实现扫描按键显示功能

2019-04-15 12:31发布

;********************************************************************************
;本程序实现扫描按键显示功能.                                                    *   
;分别按16个键盘显示分别显示数字123A456B789C*0#D                                 *
;键盘口P1,数码管显示第一位p21, 数码管段位p0口                                   *
;********************************************************************************
;将行线所接的单片机的IO口作为输出端,而列线所接的IO口则作为输入。这样,当按键没有按下时,所有的输出端都是高电平,代表无键按下。
;行线输出是低电平,一旦有键按下,则输入线就会被拉低,这样,通过读入输入线的状态就可得知是否有键按下了。
;确定矩阵式按键上何键被按下,行扫描法或者线反转法。
;行扫描法 行扫描法又称为逐行(或列)扫描查询法,是一种最常用的按键识别方法。
;判断键盘中有无键按下:将全部行线置低电平,然后检测列线的状态。只要有一列的电平为低,则表示键盘中有键被按下,而且闭合的键位于
;低电平与4根行线线交叉的4个按键之中。若所有列线均为高电平,则键盘中无键按下。
;判断闭合键所在的位置:在确认有键按下后,即可进入确定具体闭合键的过错。其方法是:一次将行线置为低电平,即在置某根行线为低电平时,其他线为高电平。
;在确定某根行线位置为低电平后,再逐行检测各列线的电平状态。若某列为低,则该列线与置为低电平的行线交叉处的按键就是闭合的按键。
;单片机的P1口用作键盘I/O口,键盘的列线接到P1口的低4位,键盘的行线接到P1口的高4位,列线P1.0-P1.3设置为输入线,行线P1.4-P1.7设置为输出线,
;4根行线和4根列线形成16个相交点。
;1.检测当前是否有键被按下,检测的方法是P1.4-P1.7输出全“0”,读取P1.0-P1.3的状态,若P1.0-P1.3为全“1”,则无键闭合,否则有键闭合;
;2.去除键抖动,当检测到有键按下后,延时一段时间再做下一步的检测判断。
;3.若有键被按下,应识别出是哪一个键闭合。方法是对键盘的行线进行扫描。P1.4-P1.7按下述4种组合依次输出:
;P1.7  1110    P1.6 1101  P1.5 1011   P1.4 0111
;在每组行输出时读取P1.0-P1.3,若全为“1”,则表示为“0”这一行没有键闭合。否则有键闭合,由此得出闭合键的行值和列值,如后
;然后可采用计算法和查表法将闭合键的行值和列值转换成所定义的键;
;4,为保证键没闭合一次CPU仅作一次处理,必须去除键释放时的抖动;
     org 0000h
     ajmp main
     org 0030h
main:
     mov dptr,#tab  ;将表头放入DPTR
     lcall key   ;调用键盘扫描程序
     movc a,@a+dptr               ;查表后将键值送入ACC
     mov p0,a                    ;将Acc值送入P0口
     CLR P2.1                           ;开显示
     ljmp main                    ;返回调用子程序反复循环显示
KEY: LCALL KS                           ;调用检测按键子程序
     JNZ K1                             ;有键按下继续
     LCALL DELAY2                       ;无键按下调用延时去抖动程序
     AJMP KEY                           ;返回继续检测有无按键按下
K1:  LCALL DELAY2
     LCALL DELAY2                       ;有键按下继续延时去抖动
     LCALL KS                           ;再一次调用检测按键程序
     JNZ K2                             ;确认有按下进行下一步
     AJMP KEY                           ;无键按下返回继续检测
K2:  MOV R2,#0EFH                       ;将扫描值送入 R2暂存
     MOV R4,#00H                        ;将第一列的列值00H送入R4暂存,R4用于存放列值。
K3:  MOV P1,R2                          ;将R2的值送入P1口
L6:  JB P1.0,L1                         ;P1.0等于1跳转到L1
     MOV A,#00H                         ;将第一行的行值00H送入ACC
     AJMP LK                            ;跳转到键值处理程序
L1:  JB P1.1,L2                         ;P1.1等于1跳转到L2
     MOV A,#04H                         ;将第二行的行值送入ACC
     AJMP LK                            ;跳转到键值理程序进行键值处理
L2:  JB P1.2,L3                         ;P1.2等于1跳转到L3
     MOV A,#08H                         ;将第三行的行值送入ACC
     AJMP LK                            ;跳转到键值处理程序
L3:  JB P1.3,NEXT                       ;P1.3等于1跳转到NEXT处
     MOV A,#0cH                         ;将第四行的行值送入ACC
LK:  ADD A,R4                           ;行值与列值相加后的键值送入A
     PUSH ACC                           ;将A中的值送入堆栈暂存
K4:  LCALL DELAY2                       ;调用延时去抖动程序
     LCALL KS                           ;调用按键检测程序
     JNZ K4                             ;按键没有松开继续返回检测
     POP ACC                            ;将堆栈的值送入ACC
     RET NEXT:
      INC  R4                            ;将列值加一
      MOV A,R2                           ;将R2的值送入A
      JNB ACC.7,KEY                      ;扫描完成跳至KEY处进行下一回合的扫描
      RL A                               ;扫描未完成将A中的值右移一位进行下一列的扫描
      MOV R2,A                           ;将ACC的值送入R2暂存
      AJMP K3                            ;跳转到K3继续
KS:   MOV P1,#0FH                        ;将P1口高四位置0低四位值1
      MOV A,P1                           ;读P1口
      XRL A,#0FH                         ;将A中的值与A中的值相异或
      RET                                ;子程序返回
DELAY2:                                  ;40ms延时去抖动子程序8*FA*2=40ms
      MOV R5,#08H
L7:   MOV R6,#0FAH
L8:   DJNZ R6,L8
      DJNZ R5,L7
      RET tab:
      db  28h,34h,28h,34h,0a9h,60h,20h,7ah,20h,21h,61h,74h,30h,62h,0a2h,7eh
         ;0h0hc9878654a321 轮流显示键盘因为无法表达*# 就用H表示,B用8表示
end