找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7842|回复: 4
收起左侧

有没有人用汇编的线反转法编写调试完成4*4矩阵键盘的扫描显示呢?

[复制链接]
ID:9596 发表于 2009-5-21 21:49 | 显示全部楼层 |阅读模式
最近在用汇编编写矩阵键盘的扫描(P1.0~P1.3为行线,P1.4~P1.7为列线),采用的是线反转法,预想编程的效果是 按下一个键时,先是用P0口控制的八只发光二极管(共阳接法)的发光情况来表示所按键在的行和列,比如按下0号键(第0行和第0列),则P0口的状态为11101110,即第1只和第5只二极管点亮,保持一段时间后,再通过数码管显示出所按键的键号,第一步通过二极管显示可以正常完成,但数码管显示就一直不对,很乱,只有最后一列的按键有时按下会显示出正确的键号,其他的都不知道显示的什么,找了好几本书,上面讲的思想都一样,我也是那样编的,但就是有问题,不知道有没有哪位有同样想法编写过这样的程序,或是哪位感兴趣的编编看,交流交流啊!
回复

使用道具 举报

ID:9596 发表于 2009-5-25 12:21 | 显示全部楼层

没人帮忙解决嘛,自己想办法解决了一些问题,不会显示乱码了,也去掉了用二极管显示行列状态的部分,不过又遇到了新的问题,就是硬件仿真执行程序的时候只能连续按下4到5个键并正常显示,之后再按其他键就没反应了,好像死了似的,想不通,现将程序贴出来,希望有人帮忙分析,谢谢!

;*****************************************************
;矩阵键盘的识别,检测是否有按键按下,并将其
;键号通过LED数码管显示出来
;*****************************************************
            ORG 0000H
            AJMP MAIN
            ORG 0100H
    MAIN :  MOV 31H,#00H
            MOV 30H,#00H
            ACALL KEY  ;调用键盘扫描子程序
    
            ACALL SHOW0;调用判断按键键号即数码管显示子程序
            AJMP MAIN
;************************************************************
;按键扫描子程序KEY
;************************************************************

   KEY:  MOV P1,#0FH;   P1口低四位作输入端,置1,高四位清0
         MOV A,P1   ;   读P1口到累加器A
         ANL A,#0FH ;   屏蔽高四位
         XRL A,#0FH ;   (A)与0FH相异或
         JNZ HKEY;      判断是否有按键按下,有,转到按键去抖子程序
         AJMP KEY ;     没有,返回继续扫描
 HKEY :  LCALL DELAY10ms;调用延时10ms子程序
         MOV A,P1   ;    再读P1口
         ANL A,#0FH ;    屏蔽高四位
         MOV 30H,A  ;    将行线状态放30H单元低四位寄存
         XRL A,#0FH ;    (A)与0FH相异或
         JNZ WKEY   ;    判断是否真的有键按下,若是,转到判断哪个按键按下子程序
         AJMP KEY   ;    若不是,则返回继续扫描
       
 WKEY :               ;   判断列线状态
         MOV P1,#0F0H ;   P1口高四位作输入端,置1,低四位清0
         MOV A,P1     ;   读P1口到累加器A
         ANL A,#0F0H  ;   屏蔽低四位
         MOV 31H,A    ;   将列线状态放入31H暂存
         XRL A,#0F0H  ;   
         JZ KEY       ;   再次判断按键状态,增强识别的可*性
         MOV A,31H    ;   将列线状态送回A
         ORL A,30H    ;   将行列状态合并
         MOV 30H,A    ;   放入30H
         ACALL DELAY10ms; 调用延时10ms子程序
   RE:   MOV A,P1     ;   再读入P1口状态
         CJNE A,#0F0H,RE; 判断按键是否释放了,没有,则等待释放
         RET            ; 若释放了,则返回

;到这边为止经过测试是没有问题的,读出的行列状态即30H中的内容是正确的,就是执行后面的程序不知道为什么会出问题!!!!!
;***************************************************************
;判断按键的键号及数码管显示子程序SHOW0
;**************************************************************
   SHOW0: 
    
      L1:   MOV A,30H    ;将检测到得按键行列状态送到A
            XRL A,#77H   ;(A)与77H(01110111)相异或
            JNZ L2       ;判断是否是第16个键按下,若不是,转到L2判断是否是第15个键按下
            MOV A,#0FH   ;若是,则将键号送入A
            ACALL SHOW0_1;调用数码管显示子程序
      L2:   MOV A,30H    ;...............................
            XRL A,#0B7H  ;..............................
            JNZ L3      
            MOV A,#0EH
            ACALL SHOW0_1
      L3:   MOV A,30H
            XRL A,#0D7H
            JNZ L4
            MOV A,#0DH
            ACALL SHOW0_1
      L4:   MOV A,30H
            XRL A,#0E7H
            JNZ L5
            MOV A,#0CH
            ACALL SHOW0_1
      L5:   MOV A,30H
            XRL A,#7BH
            JNZ L6
            MOV A,#0BH
            ACALL SHOW0_1
      L6:   MOV A,30H
            XRL A,#0BBH
            JNZ L7
            MOV A,#0AH
            ACALL SHOW0_1
      L7:   MOV A,30H
            XRL A,#0DBH
            JNZ L8
            MOV A,#09H
            ACALL SHOW0_1
      L8:   MOV A,30H
            XRL A,#0EBH
            JNZ L9
            MOV A,#08H
            ACALL SHOW0_1
    
      L9:   MOV A,30H
            XRL A,#7DH
            JNZ L10
            MOV A,#07H
            ACALL SHOW0_1
      L10:  MOV A,30H
            XRL A,#0BDH
            JNZ L11
            MOV A,#06H
            ACALL SHOW0_1
      L11:  MOV A,30H
            XRL A,#0DDH
            JNZ L12
            MOV A,#05H
            ACALL SHOW0_1
      L12:  MOV A,30H
            XRL A,#0EDH
            JNZ L13
            MOV A,#04H
            ACALL SHOW0_1
      L13: 
            MOV A,30H
            XRL A,#7EH
            JNZ L14
            MOV A,#03H
            ACALL SHOW0_1
      L14:  MOV A,30H
            XRL A,#0BEH
            JNZ L15
            MOV A,#02H
            ACALL SHOW0_1
      L15:  MOV A,30H
            XRL A,#0DEH
            JNZ L16
            MOV A,#01H
            ACALL SHOW0_1
      L16:  MOV A,30H
            XRL A,#0EEH
            JNZ L17            ;若检测到均不是以上键号对应的按键按下,则转到L17返回主程序重新检测
            MOV A,#00H
            ACALL SHOW0_1      ;.....................
      L17: 
            AJMP MAIN
;********************************************************************************
;键号送数码管显示
;********************************************************************************          
SHOW0_1:   CLR P2.0
            MOV DPTR,#TAB
            MOVC A,@A+DPTR
            MOV P0,A
    
            RET
DELAY10ms:  MOV R6,#20 ;延时10ms子程序
      LX0:  MOV R7,#248h
            DJNZ R7,$
            DJNZ R6,LX0
            RET
   TAB:  DB 0C0H,0F9H,0A4H,0B0H
         DB 99H,92H,82H,0F8H
         DB 80H,90H,88H,83H
         DB 0C6H,0A1H,86H,8EH
    
         END

回复

使用道具 举报

ID:9596 发表于 2009-5-29 00:04 | 显示全部楼层

哈哈,真惨,自己的问题还是要自己回答啊,问题已解决了,主要有两个问题:

  1、没有关闭ADC、DAC时钟通道数据寄存器。这是因为对自己实验板还没有完全学习掌握完,所以这是卖家帮助解决的,很钦佩卖家的服务态度!解决方法就是将其关闭呗:

            ORG 0000H
            AJMP MAIN1
            ORG 0100H
    MAIN1:  CLR P2.2 ;关闭时钟芯片
            CLR P3.7;关闭数码管以外的其他通道
            SETB P2.2
    MAIN :  MOV 31H,#00H
            MOV 30H,#00H
            LCALL KEY  ;调用键盘扫描子程序
            LCALL SHOW0;调用判断按键键号即数码管显示子程序
            AJMP MAIN

           ……………

但仅仅这样问题依然存在,下一个问题是什么呢?

  2、子程序设计与堆栈技术:在调用子程序的时候我没有按照子程序的原则,最后一定以返回指令RET结束,而是用的AJMP指令,一种解决方法就是如卖家的建议,按子程序设计的原则来,以RET 结束,键盘扫描子程序无需修改,修改如下;

          ………………  …………

;****************************************************************

;判断按键的键号及数码管显示子程序SHOW0

;**************************************************************
   SHOW0: 
      L1:   MOV A,30H    ;将检测到得按键行列状态送到A
            XRL A,#77H   ;(A)与77H(01110111)相异或
            JNZ L2       ;判断是否是第16个键按下,若不是,转到L2判断是否是第15个键按下
            MOV A,#0FH   ;若是,则将键号送入A
            ACALL SHOW0_1;调用数码管显示子程序
     RET
      L2:   MOV A,30H    ;...............................
            XRL A,#0B7H  ;..............................
            JNZ L3      
            MOV A,#0EH
            ACALL SHOW0_1
     RET
      L3:   MOV A,30H
            XRL A,#0D7H
            JNZ L4
            MOV A,#0DH
            ACALL SHOW0_1
     RET
      L4:   MOV A,30H
            XRL A,#0E7H
            JNZ L5
            MOV A,#0CH
            ACALL SHOW0_1
     RET
      L5:   MOV A,30H
            XRL A,#7BH
            JNZ L6
            MOV A,#0BH
            ACALL SHOW0_1
     RET
      L6:   MOV A,30H
            XRL A,#0BBH
            JNZ L7
            MOV A,#0AH
            ACALL SHOW0_1
     RET
      L7:   MOV A,30H
            XRL A,#0DBH
            JNZ L8
            MOV A,#09H
            ACALL SHOW0_1
     RET
      L8:   MOV A,30H
            XRL A,#0EBH
            JNZ L9
            MOV A,#08H
            ACALL SHOW0_1
     RET
      L9:   MOV A,30H
            XRL A,#7DH
            JNZ L10
            MOV A,#07H
            ACALL SHOW0_1
     RET
      L10:  MOV A,30H
            XRL A,#0BDH
            JNZ L11
            MOV A,#06H
            ACALL SHOW0_1
     RET
      L11:  MOV A,30H
            XRL A,#0DDH
            JNZ L12
            MOV A,#05H
            ACALL SHOW0_1
     RET
      L12:  MOV A,30H
            XRL A,#0EDH
            JNZ L13
            MOV A,#04H
            ACALL SHOW0_1
     RET
      L13:  MOV A,30H
            XRL A,#7EH
            JNZ L14
            MOV A,#03H
            ACALL SHOW0_1
     RET
      L14:  MOV A,30H
            XRL A,#0BEH
            JNZ L15
            MOV A,#02H
            ACALL SHOW0_1
     RET
      L15:  MOV A,30H
            XRL A,#0DEH
            JNZ L16
            MOV A,#01H
            ACALL SHOW0_1
     RET
      L16:  MOV A,30H
            XRL A,#0EEH
            JNZ L17            ;若检测到均不是以上键号对应的按键按下,则转到L17返回主程序重新检测
            MOV A,#00H
            ACALL SHOW0_1;.....................
      L17:  RET


;********************************************************************************
;键号送数码管显示
;********************************************************************************          
SHOW0_1:    CLR P2.0
            MOV DPTR,#TAB
            MOVC A,@A+DPTR
            MOV P0,A
     RET

DELAY10ms:  MOV R6,#20 ;延时10ms子程序
      LX0:  MOV R7,#248
            DJNZ R7,$
            DJNZ R6,LX0
     RET
   TAB:  DB 0C0H,0F9H,0A4H,0B0H
         DB 99H,92H,82H,0F8H
         DB 80H,90H,88H,83H
         DB 0C6H,0A1H,86H,8EH
    
         END

但究其原因,我为什么要用RET结束呢?总得有原因的吧,通过看书,思考,我认为这应该是堆栈的问题,因为在执行调用子程序的指令时,也执行了PUSH(压入堆栈)指令,将数据压入堆栈,而在子程序执行完后,我用的AJMP指令,程序就直接跳到AJMP指定的地址去了,而压入堆栈的数据还在堆栈中,与使用RET指令相比,少了一个POP(出栈)过程,所以每执行一次调用子程序指令,就会往堆栈中压入数据,而堆栈SP是一个8为寄存器,在反复执行几次调用指令后,SP指针就到栈顶了,相当于堆栈已压经满了数据,后面再执行调用指令时,数据无法压入堆栈,也就导致程序无法继续执行了,这就是为什么之后无论怎么按键都没反应的原因了,到这里,我想何不“将错就错”,直接在主程序中加一条设置堆栈的指令,当然最好在每个子程序执行完后设置一下堆栈,于是做出如下修改(红色和绿色为修改的部分):

;*****************************************************
;矩阵键盘的识别,检测是否有按键按下,并将其
;键号通过LED数码管显示出来
;*****************************************************
            ORG 0000H
            AJMP MAIN
            ORG 0100H
    MAIN :  CLR P2.2;
            clr p3.7;
     SETB P2.2
    MAIN1:  mov sp,#07h
            MOV 31H,#00H
            MOV 30H,#00H

            LCALL KEY  ;调用键盘扫描子程序
    
            LCALL SHOW0;调用判断按键键号即数码管显示子程序
         AJMP MAIN1
    上述两种修改方法均经过实验板调试,可以正常运行!但不知道我的解释有没有问题,还是希望有高人指点,谢谢! 

回复

使用道具 举报

ID:9596 发表于 2009-5-29 00:06 | 显示全部楼层
不过建议还是按照子程序设计的规则来写程序,不然可能会出现很多意想不到的情况的!
回复

使用道具 举报

ID:71905 发表于 2015-1-9 13:07 | 显示全部楼层
求问楼主拿键盘扫描子程序
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表