// 程序名称:4-4keyscan.asm;// 程序用途:4*4矩阵键盘扫描检测;// 功能描述:扫描键盘,确定按键值。程序不支持双键同时按下,;// 如果发生双键同时按下时,程序将只识别其中先扫描的按键;// 程序入口:void;// 程序出口:KEYNAME,包含按键信息、按键有效信息、当前按键状态;//======================================================================PROC KEYCHKKEYNAME DATA 40H ;按键名称存储单元 ;(b7-b5纪录按键状态,b4位为有效位, ;b3-b0纪录按键)KEYRTIME DATA 43H ;重复按键时间间隔SIGNAL DATA 50H ;提示信号时间存储单元 KEY EQU P3 ;键盘接口(必须完整I/O口)
KEYPL EQU P0.6 ;指示灯接口
RTIME EQU 30 ;重复按键输入等待时间
KEYCHK:
;//=============按键检测程序=============================================
MOV KEY,#0FH ;送扫描信号
MOV A,KEY ;读按键状态
CJNE A,#0FH,NEXT1 ;ACC<=0FH
; CLR C ;Acc等于0FH,则CY为0,无须置0
NEXT1:
; SETB C ;Acc不等于0FH,则ACC必小于0FH,
;CY为1,无须置1
MOV A,KEYNAME
ANL KEYNAME,#1FH ;按键名称屏蔽高三位
RRC A ;ACC带CY右移一位,纪录当前按键状态
ANL A,#0E0H ;屏蔽低五位
ORL KEYNAME,A ;保留按键状态
;//=============判别按键状态,决定是否执行按键扫描========================
CJNE A,#0C0H,NEXT2 ;110按键稳定闭合,调用按键检测子程序
SJMP KEYSCAN
NEXT2:
CJNE A,#0E0H,NEXT3 ;111按键长闭合,重复输入允许判断
SJMP WAIT
NEXT3:
CJNE A,#0A0H,EXIT ;101干扰,当111长闭合处理
ORL KEYNAME,#0E0H
WAIT:
MOV A,KEYRTIME
JNZ EXIT ;时间没到,退出
;//=============键盘扫描程序==============================================
KEYSCAN:商旅系统
MOV R1,#0 ;初始化列地址
MOV R3,#11110111B ;初始化扫描码
LOOP:
MOV A,R3
RL A
MOV R3,A ;保留扫描码
MOV KEY,A ;送扫描码
MOV A,KEY ;读键盘
ORL A,#0F0H ;屏蔽高四位
CJNE A,#0FFH,NEXT31 ;A不等于FFH,说明该列有按键动作
INC R1 ;列地址加1,准备扫描下一列
CJNE R1,#4,LOOP ;列地址不等于4,扫描下一列
SJMP EXIT ;没有按键,退出
;//=============按键判断对应位等于零,说明该行有按键按下==================
NEXT31:
JB ACC.0,NEXT32
MOV R2,#0 ;第0行有按键
SJMP NEXT5
NEXT32:
JB ACC.1,NEXT33
MOV R2,#1 ;第1行有按键
SJMP NEXT5
NEXT33:
JB ACC.2,NEXT34
光通量测试 MOV R2,#2 ;第2行有按键
万维视频网 SJMP NEXT5
NEXT34:
MOV R2,#3 ;第3行有按键
NEXT5: ;计算按键地址
MOV A,R1
RL A
RL A ;列地址乘4(每列对应4行)
ADD A,R2 ;加行地址
MOV DPTR,#KEYTAB
MOVC A,@A+DPTR
ANL KEYNAME,#0E0H
ORL KEYNAME,A ;送按键(送值的时候已经置按键有效)
MOV KEYRTIME,#RTIME ;送重复按键等待时间点火加热装置
CLR KEYPL ;打开指示灯
MOV SIGNAL,#10 ;送信号提示时间(每次按键闪100ms)
EXIT:
MOV KEY,#0FFH ;置键盘接口高电平
RET ;退出
;//=============按键名称表================================================
KEYTAB:
DB 1AH ;扫描码0,对应A ******************************************
DB 1BH ;扫描码1,对应B ** **
DB 1CH ;扫描码2,对应C ** I/O口 PX.4 PX.5 PX.6 PX.7 **
DB 1DH ;滑步机扫描码3,对应D ** **
DB 11H ;扫描码4,对应1 ** PX.0 A(0) 1(4) 2(8) 3(C) **
DB 14H ;扫描码5,对应4 ** **
DB 17H ;扫描码6,对应7 ** PX.1 B(1) 4(5) 5(9) 6(D) **
DB 1EH ;扫描码7,对应E ** **
DB 12H ;扫描码8,对应2 ** PX.2 C(2) 7(6) 8(A) 9(E) **
DB 15H ;扫描码9,对应5 ** **
DB 18H ;扫描码A,对应8 ** PX.3 D(3) E(7) 0(B) F(F) **
DB 10H ;扫描码B,对应0 ** **
DB 13H ;扫描码C,对应3 ******************************************
DB 16H ;扫描码D,对应6
DB 19H ;扫描码E,对应9
DB 1FH ;扫描码F,对应F
END
第二种解法
ORG 0000H
START: MOV R0,#00H ;初始化程序,开始的延时是为了使硬件能够准备好
DJNZ R0,$
LOOP: MOV SP,#60H
CALL KEY
DISPLAY:
MOV A,R4
MOV DPTR,#TABLE ;定义字形表的起始地址
MOVC A,@A+DPTR ;TABLE为表的起始地址
MOV P2,A
SJMP LOOP
;子程序内容 ,P1口的低四位为行线,高四位为列线
KEY: PUSH PSW
PUSH ACC
MOV P1,#0F0H ;令所有的行为低电平,全扫描字-P1.0-P1.3,列为输入方式
;这一段只是验证有键按下,并不能判断是哪一行
MOV R7,#0FFH ;设置计数常数,作为延时
KEY1: DJNZ R7, KEY1
MOV A,P1 ;读取P1口的列值
ANL A,#0F0H ;判别有键值按下吗(当有键按下时,P1口的高四位就不全为1了,底四位还是都为0的)
;这个地方进行相或的原因,是因为要把底四位的0000变成1111,以便下一步进行求反
ORL A,#0FH //这个地方原版上没有,这是又加了,如果不加的的话,是不对的********
CPL A ;求反后,有高电平就有键按下
JZ EKEY;累加器为0则转移(意为求反后本来全为0的,如果有键按下时,求反后高四位就有1了),退出
LCALL DEL20ms ;有键按下,进行处理