📄 实验七(键盘扫描).asm
字号:
;功能:5*4键盘扫描程序
KEYNAME DATA 28H ;b4~b0位记录按键值
;b7-作为按键值有效标志,b7为0时,表示b4-b0位中的按键值无效。
;b7为1时,表示b4-b0位记录的按键值有效,且未尚未处理,不能
;接受新按键。
;b6-保留。
;外部程序执行了按键功能后,将按键有效标志清0,允许接收新按键
KEYSTU DATA 2AH ;键盘按键状态寄存器,其中b2、b1、b0分别记录最近
;三次定时中断的按键状态。
DISPBUF DATA 30H ;显示缓冲区首地址(30H-33H)
PORTDR DATA 34H ;U105(八上升沿D型触发器74HC273)地址内存中的影射地址
;设置影射地址目的是为了在执行键盘扫描过程中不影响
;该输出口高3位(b5~b3)位内容
BTIME DATA 40H ;10ms计数单元
DISPB BIT 00H ;50ms定时时间到标志
SDI BIT P1.2 ;串行数据输入
SCLK BIT P3.4 ;串行数据移位脉冲
PCLK BIT P3.5 ;并行锁存脉冲
PORTA EQU 9000H ;8255A口地址
PORTB EQU 9100H ;8255B口地址
PORTC EQU 9200H ;8255C口地址
PORTS EQU 9300H ;8255控制/状态口地址
PORTD EQU 8800H ;U105(八上升沿D型触发器74HC273)地址
ORG 0000H
LJMP MAIN
ORG 002BH
LJMP CTC2 ;定时/计数器T2中断服务程序入口地址
ORG 0050H
;-----主程序开始-----
PROC MAIN
MAIN:
MOV SP, #0DFH ;对于具有256字节内部RAM芯片来说,
;将0E0H-0FFH,共计32字节作为堆栈区
MOV DPTR, #8000H ;关闭蜂鸣器
MOV A, #0FFH
MOVX @DPTR, A
;---复位后,将08H-0FF内部RAM单元清0。
MOV R7, #248
MOV R0, #08H
LOOP1:
MOV @R0, #0
INC R0
DJNZ R7, LOOP1
MOV KEYSTU, #07H ;按键状态初始化为111
MOV KEYNAME, #1FH ;将键盘按键置为1FH(无效)
;初始化U107(8255)可编程并行I/O接口芯片的工作方式
MOV DPTR, #PORTS ;8255控制/状态口地址
MOV A, #10011011B ;A口工作在方式0,输入;B口工作在方式0,输入;
;C口高、低半部暂时定义为输入
MOVX @DPTR, A ;送控制字寄存器
;将PD4~PD0置为高电平,使U105(74HC273)输出级截止,降低功耗。
MOV DPTR, #PORTD ;U105口地址送DPTR
MOV A, PORTDR ;读U105口在内存中的映象地址
ORL A, #1FH
MOVX @DPTR, A ;数据送U105输出口
;----初始化定时器T2
; MOV TH2, #0FCH
; MOV TL2, #67H ;初值0DC00送定时器T2
; MOV RCAP2H, #0FCH
; MOV RCAP2L, #67H ;初始化重装初值
MOV TH2, #0FCH
MOV TL2, #67H ;初值0DC00送定时器T2
MOV RCAP2H, #0FCH
MOV RCAP2L, #67H ;初始化重装初值
MOV T2CON, #00000100B ;初始化T2工作方式(自动重装初值、定时)
;并启动了T2
;-----初始化中断控制器
SETB ET2 ;允许定时器T2中断
SETB EA ;开中断
MOV BTIME, #5 ;初值为5(即每50ms检测一次)
LOOP2:
JNB DISPB, LOOP2 ;50ms定时时间未到
CLR DISPB
LCALL KEYCHK ;每50ms读键盘状态
;检查键盘有无输入
MOV A, KEYNAME
JNB ACC.7, LOOP2 ;键盘按键无效,就循环等待
;按键有效,先将显示缓冲区笔段码左移一个字节
MOV R0, #DISPBUF ;显示缓冲区首地址送R0
MOV R1, #DISPBUF+1 ;显示缓冲区地址送R1
MOV R7, #3
LOOP3:
MOV A, @R1
MOV @R0, A
INC R0
INC R1
DJNZ R7, LOOP3
MOV A, KEYNAME ;读按键值
ANL A, #1FH ;保留
MOV KEYNAME, A ;清除按键处理标志
CJNE A, #10H, NEXT1
NEXT1:
JC NEXT2
;按下了功能键,键值>=10H,用两位LED来显示
ANL A, #0F0H
SWAP A
MOV DPTR, #LEDTAB ;0-F字模表首地址送DPTR
MOVC A, @A+DPTR ;查表取模
MOV R1, #DISPBUF+2 ;显示缓冲区地址送R1
MOV @R1, A ;字模送显示缓冲区
NEXT2:
MOV A, KEYNAME ;读按键值
ANL A, #0FH ;保留低4位
MOV DPTR, #LEDTAB ;0-F字模表首地址送DPTR
MOVC A, @A+DPTR ;查表取模
MOV R1, #DISPBUF+3 ;显示缓冲区地址送R1
MOV @R1, A ;字模送显示缓冲区
LCALL S_DISP ;串行显示
LJMP LOOP2 ;循环等待
END
PROC S_DISP ;串行输出子程序
S_DISP:
MOV R0, #DISPBUF ;显示缓冲区首地址送R0
MOV R7, #4
LOOP2:
MOV A, @R0
MOV R6, #8
LOOP1:
CLR SCLK
RLC A
MOV SDI, C ;串行数据送SDI引脚
NOP
SETB SCLK ;锁存串行输入数据
DJNZ R6, LOOP1
;取下一显示码
INC R0
DJNZ R7, LOOP2
;4位笔段码已全部移到串入并出芯片中
CLR PCLK
NOP ;延迟一个机器周期
SETB PCLK
RET
END
;定时/计数器T2中断服务程序
PROC CTC2
CTC2:
PUSH PSW
DJNZ BTIME, EXIT ;溢出次数减1,不为0跳转
;溢出次数已经回到0,重新初始化溢出次数
MOV BTIME, #5
SETB DISPB ;置位1秒时间到标志
EXIT:
CLR TF2 ;清除定时器T2溢出标志
POP PSW
RETI
END
PROC KEYCHK ;键盘检测
KEYCHK:
;---键盘检测-----------
MOV DPTR, #PORTD ;U105口地址送DPTR
MOV A, PORTDR ;读U105口在内存中的映象地址
ANL A, #0E0H ;输出全为低电平的扫描信号
MOVX @DPTR, A ;数据送U105输出口,将PD4~PD0置为低电平
MOV DPTR, #PORTB ;8255(U107)B口地址送DPTR
MOVX A, @DPTR ;读出B口
ANL A, #0FH ;屏蔽高4位
CJNE A, #0FH, NEXT1
;等于0F,说明没有按键被按下
SETB C ;将C标志置1
SJMP NEXT2
NEXT1:
CLR C ;C标志清0
NEXT2:
MOV A, KEYSTU
RLC A ;左移一位,记录最新的按键状态
ANL A, #07H ;保留按键状态
MOV KEYSTU, A ;保存按键状态
;判别按键状态,决定是否执行按键扫描
CJNE A, #0, SNEXT1
;处于000态,按键未释放,退出(假设一次按键仅视为一次输入)
SJMP KEXIT
SNEXT1:
CJNE A, #1, SNEXT2
;处于001态, 按键可能刚被释放,不处理
SJMP KEXIT
SNEXT2:
CJNE A, #2, SNEXT3
;处于010态,干扰,作000态处理
ANL KEYSTU, #00H
SJMP KEXIT
SNEXT3:
CJNE A, #3, SNEXT4
;处于011态,按键处于释放状态,退出
SJMP KEXIT
SNEXT4:
CJNE A, #4, SNEXT5
;处于100态,按键已经稳定闭合,进行按键扫描
LCALL KEYSCAN ;执行键盘扫描,确定哪一按键被按下
SJMP KEXIT
SNEXT5:
CJNE A, #5, SNEXT6
;处于101态, 干扰,作111态处理
ORL KEYSTU, #07H ;b2~b0位置1
SJMP KEXIT
SNEXT6:
CJNE A, #6, SNEXT7
;处于110态,按键刚被按下,未稳定,暂不处理
; LJMP EXIT
SNEXT7:
;处于111态
KEXIT:
;将PD4~PD0置为高电平,使74HC273输出级截止,降低功耗。
MOV DPTR, #PORTD ;U105口地址送DPTR
MOV A, PORTDR ;读U105口在内存中的映象地址
ORL A, #1FH
MOVX @DPTR, A ;数据送U105输出口
;---键盘检测结束-----------
RET
END
PROC KEYSCAN ;键盘扫描程序
KEYSCAN:
MOV R7, #5 ;定义扫描次数
MOV R1, #0 ;初始化列地址
MOV R3, #01111111B ;扫描码初值
LOOP1:
;生成扫描码
MOV A, R3
RL A ;左移一位(从PD0开始扫描)
MOV R3, A ;保存扫描码
ANL A, #00011111B ;保留扫描
MOV B, A ;暂时保存在B寄存器中
MOV DPTR, #PORTD ;U105口地址送DPTR
MOV A, PORTDR ;读U105口在内存中的映象地址
ANL A, #0E0H ;保留与键盘扫描无关的b7~b5位。
ORL A, B ;与扫描或
MOVX @DPTR, A ;数据送U105输出口,将PD4~PD0置为低电平
NOP ;延迟一个机器周期等待输出口状态稳定
MOV DPTR, #PORTB ;B口地址送DPTR
MOVX A, @DPTR ;读B口
ANL A, #0FH ;屏蔽高4位
JB ACC.0, NEXT1
;ACC.0位为0,说明0行有按键被按下
MOV R2, #0 ;行地址为0
SJMP NEXT5
NEXT1:
JB ACC.1, NEXT2
;ACC.1位为0,说明1行有按键被按下
MOV R2, #1 ;行地址为1
SJMP NEXT5
NEXT2:
JB ACC.2, NEXT3
;ACC.2位为0,说明2行有按键被按下
MOV R2, #2 ;行地址为2
SJMP NEXT5
NEXT3:
JB ACC.3, NEXT4
;ACC.3位为0,说明3行有按键被按下
MOV R2, #3 ;行地址为3
SJMP NEXT5
NEXT4:
;说明该列上没有按键被按下
INC R1 ;列地址加+1,继续扫描
DJNZ R7, LOOP1
;扫描所有列,均没发现按按键被按下
SJMP EXIT
NEXT5:
;计算行列地址,查表或区
MOV A, R1
RL A
RL A ;列地址乘4(每列对应4行)
ADD A, R2 ;加行地址
MOV DPTR, #KEYTAB
MOVC A, @A+DPTR ;查表获取键值
MOV KEYNAME, A ;按键值送键名寄存器中
ORL KEYNAME, #80H ;按键有效标志置1
EXIT:
RET
END
;***********按键扫描码、键值对应关系******************
KEYTAB:
DB 0FH ;扫描码为0,即PD0与PB0交叉点对应数字键"F"
DB 0EH ;扫描码为1,即PD0与PB1交叉点对应数字键"E"
DB 0DH ;扫描码为2,即PD0与PB2交叉点对应数字键"D"
DB 0CH ;扫描码为3,即PD0与PB3交叉点对应数字键"C"
DB 09H ;扫描码为4,即PD1与PB0交叉点对应数字键"9"
DB 06H ;扫描码为5,即PD1与PB1交叉点对应数字键"6"
DB 03H ;扫描码为6,即PD1与PB2交叉点对应数字键"3"
DB 0BH ;扫描码为7,即PD1与PB3交叉点对应数字键"B"
DB 08H ;扫描码为8,即PD2与PB0交叉点对应数字键"8"
DB 05H ;扫描码为9,即PD2与PB1交叉点对应数字键"5"
DB 02H ;扫描码为A,即PD2与PB2交叉点对应数字键"2"
DB 00H ;扫描码为B,即PD2与PB3交叉点对应数字键"0"
DB 07H ;扫描码为C,即PD3与PB0交叉点对应数字键"7"
DB 04H ;扫描码为D,即PD3与PB1交叉点对应数字键"4"
DB 01H ;扫描码为E,即PD3与PB2交叉点对应数字键"1"
DB 0AH ;扫描码为F,即PD3与PB3交叉点对应数字键"A"
DB 13H ;扫描码为10,即PD4与PB0交叉点对应"↑"
DB 12H ;扫描码为11,即PD4与PB1交叉点对应"Enter"
DB 11H ;扫描码为12,即PD4与PB2交叉点对应"ESC"
DB 10H ;扫描码为13,即PD4与PB3交叉点对应"↓"
LEDTAB: ;八段LED共阳数码管字模
;数码 0 1 2 3 4 5 6 7
DB 0C0H, 0F9H, 0A4H, 0B0H, 99H, 92H, 82H, 0F8H
;数码 8 9 A B C D E F
DB 80H, 90H, 88H, 83H, 0C6H, 0A1H, 86H, 8EH
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -