【Proteus仿真+Keil汇编】(PBL练习2)

一、项目要求

实现矩阵式键盘输入、多LED动态输出显示

二、矩阵键盘

2.1 独立式和矩阵式键盘比较
        独立式键盘虽然硬件、软件结构简单,但在按键数量较多的情况下,将占有较多的I/O端口,所以在按键数量较多的情况下,一般采用可以有效减少I/O端口数量的矩阵式键盘。矩阵式键盘又称为行列式键盘,采用行、列线结构,按键设置在行列线的交叉点上,如下图所示,H0H3为四条行线,L0L3为四条列线,在行列相交的每个交点上通过按键来连通,按键开关的一个触点连行线,一个触点连列线,从而组成4×4矩阵16键键盘

【Proteus仿真+Keil汇编】(PBL练习2)_第1张图片

 2.2 键编码及键值

(1) 用键盘连接的I/O线的二进制组合表示键码

例如用4行、4列线构成的16个键的键盘,可使用一个8位I/O口线的高、低4位口线的二进制数的组合表示16个键的编码

【Proteus仿真+Keil汇编】(PBL练习2)_第2张图片

如图所示,各键相应的键值为:                                                       

88H、84H、82H、81H 

48H44H、42H、41H 

28H24H、22H、21H   

18H、14H12H、11H                                                                                                                      

(2)顺序排列键码

如图所示,这种方法键值的形成要根据I/O线的状态作相应的程序处理。键码可按下式形成:

1111,1110,1101,1100 

1011,1010,1001,1000

 0111,0110,0101,0100 

0011,0010,0001,0000 

高四位对应的行首键码、行键值及低四位的列号、列键值如下表所示:

高四位

行首键码 行键值 D7 第3行 1100 1000_0000 D6 第2行 1000 0100_0000 D5 第1行 0100 0010_0000 D4 第0行 0000 0001_0000

低四位

列号 列键值 D3 第3列 0011 0000_1000 D2 第2列 0010 0000_0100 D1 第1列 0001 0000_0010 D0 第0列 0000 0000_0001

键值=行键值+列键值              例:42H(=D6+D1)=0100_0000H+0000_0010H=0100_0010H

键码=行首键值+列号              例:42H对应的键码为 1000+0001=1001

2.3 矩阵式键盘工作原理

①无按键按下时,行线输入高电平;
②有按键按下时,行线输入电平由与此行线相连的列线电平决定.

        •如果列线输出低电平,则行线电平为低
        •如果列线输出高电平,则行线电平为高
 ③为了确认按键位置,必须将行、列线配合使用。

对键盘的工作过程可分两步:

       第一步是CPU首先检测键盘上是否有键按下;

       第二步是再识别是哪一个键按下。

       检测键盘上有无键按下可采用程序扫描方式中断工作方式。

本文仅介绍程序扫描方式

 一般情况下,在单片机应用系统中,键盘处理只是CPU工作的一部分。为了能及时发现有键按下CPU必须不算调用键盘处理程序,对键盘进行扫描,因此称为程序扫描方式。

【Proteus仿真+Keil汇编】(PBL练习2)_第3张图片

①首先列线全输出0,判断是否有键按下。
如果行线为全1,无按键按下
如果行线非全1,有按键按下
②然后,让列线
P1.4输出0,其它3条列线输出1,读行线状态。
如果行线为全1,第一列无按键按下,继续扫描。
如果行线非全1,可以判断按键在第0列,再根据为0的行线序号,可以确定按键具体的行号,停止扫描。
③如果第
0列无按键按下,让列线P1.5口输出0,其它三条列线输出1,读行线状态,判断按键是否在第一列。
④为求取键码,在逐列扫描时,可用计数器记录下当前扫描列的列号,然后用行首键码加列号的办法计算。

下面以教材《单片机原理》P169举例

【Proteus仿真+Keil汇编】(PBL练习2)_第4张图片

例: 12号键按下,对应第1行,第4列,则行首键码为01_000,列号为00_100

故键值为:01_000+00_100=01_100

R2(PA7~PA0)

列扫描字

R4

(列号)

扫描第0

  FE(1111_1110)

0 (000)

扫描第1

  FD(1111_1101)

1 (001)

扫描第2

  FB(1111_1011)

2 (010)

扫描第3

  F7(1111_0111)

3 (011)

扫描第4

  EF(1110_1111)

4 (100)

扫描第5

   DF(1101_1111)

5 (101)

扫描第6

  BF(1011_1111)

6 (110)

扫描第7

  7F(0111_1111)

7 (111)

行首键码

第0行

00_000  (00H)

第1列

01_000 (08H)

第2列

10_000 (10H)

第3列

11_000 (18H)

键盘扫描子程序流程图:

编写键盘程序四步

(1)判断是否有键闭合

(2)去抖动

(3)求键值

(4)等待按键的释放

//本例代码
/******首先列线全输出0,判断是否有键按下。
    如果行线为全1,无按键按下
    如果行线非全1,有按键按下
******/


KS: MOV     DPTR, #PA                    ;A口地址送入DPTR
            MOV    A, #00H                              ;全扫描字送A	
            MOVX  @DPTR, A                          ;全扫描字送PA口,列全部输出0	                    
            INC      DPTR                              ;指向C口				 
            INC       DPTR
            MOVX   A, @DPTR               ;读入PC口(行)状态			 
            CPL       A                         ;变正逻辑:高电平表示有键按下	
            ANL       A, #0FH	                     ;屏蔽高4位
            RET

KEY: LCALL  KS                ;判别有无键按下	   	     
            JNZ       K1                    ;(A)不等于0,有键按下,转K1	
            LCALL  DELAY	          ;无键按下调用延时子程序     
            AJMP    KEY                   ;返回重新查询	     
K1:  LCALL  DELAY           ;加长延时,消除键抖动     
            LCALL   DELAY
            LCALL   KS                     ;再次查询有无键按下     
            JNZ       K2	          ; (A)不等于0,有键按下,转逐列扫描     
            AJMP    KEY	          ;误读键,返回     


/******然后,让列线PA0输出0,其它七条列线输出1,读行线状态。
如果行线为全1,第一列无按键按下,继续扫描。
如果行线非全1,可以判断按键在第一列,再根据为0的行线序号,可以确定按键具体的行号,停止扫描。
******/

K2:          MOV   R2, #0FEH     ;首列扫描字送R2
             MOV     R4, #00H         ;首列号送R4
K3:          MOV   DPTR, #PA    ;A口地址送DPTR
             MOV    A, R2
             MOVX    @DPTR, A    ;列扫描字送8155A口
             INC       DPTR     
             INC       DPTR
             MOVX   A, @DPTR	;读取行扫描值 
             JB          ACC.0, L1;(PC.0)=(ACC.0)=1,第0行无键按下,转查第一行
             MOV      A, #00H		 ;第0行有键按下,行首键号送A
             AJMP     LK	                  ;转求键号
 
L1:          JB  ACC.1, L2	 ;(PC.1)=(ACC.1)=1,第1行无键按下,转查第2行MOV    A, #08H		 ;第1行有键按下,行首键号送A
             AJMP   LK			 ;转求键号
L2:          JB  ACC.2, L3	 ;(PC.2)=(ACC.2)=1,第2行无键按下,转查第3行
             MOV    A, #10H		;第2行有键按下,行首键号送A 
             AJMP   LK			 	 ;转求键号
L3:          JB  ACC.3, NEXT ;(PC.3)=(ACC.3)=1,第3行无键按下,转查下一列
             MOV    A, #18H		;第3行有键按下,行首键号送A 
                                                        ;开始求键码
LK:          ADD  A, R4		 ;形成键码送A:键码=行首键码+列号
             PUSH  ACC		;键码入栈保存	 
K4:          LCALL DELAY                   
             LCALL KS		;等待键释放			 
             JNZ        K4		;(A)不等于0,有键按下,按键未释放,等待		 
             POP    A			;键释放,弹出键码		 
             RET                                                         

/******如果第一列无按键按下,让列线PA1口输出0,其它七条列线输出1,读行线状态,判断按键是否在第二列。
******/

                                                          ;准备扫描下一列
NEXT:        INC    R4			;修改列号,扫描下一列		 
             MOV   A, R2                         ;PA口(列)数据送A
             JNB   ACC.7, KEY	 ;(PA.7)=(ACC.7)=0,8列扫描完,返回KEY 	RL    A	                                 ;未扫描完,扫描字左移一位
             MOV   R2, A		;扫描字存R2		 
             AJMP  K3

                                                        ;延时子程序
DELAY:       MOV   R7, #0FFH
LP0:         MOV     R6, #0FFH
LP:          NOP
             DJNZ    R6, LP
             DJNZ    R7, LP0			
             RET                

三、多LED动态显示

①实现效果一:按下键盘,键盘对应数字依次从左往右扫过数码管

【Proteus仿真+Keil汇编】(PBL练习2)_第5张图片

 如图,P0口为段选端,P3口为位选端

因为P0口内部没有上拉电阻,不能输出高电平,所以要接上拉电阻。其中用到的是RESPACK8排阻,有关数码管显示的问题,可参考其他大佬的文章。

ORG 	0000H
	LJMP START
	ORG 0030H
START: 	MOV 	DPTR,#TABLE	  ;DPTR指向段码表首地址
	MOV 	R7,#7FH      	  ;设置动态显示扫描初值
S1:	MOV	A,#00H		   
	MOVC	A,@A+DPTR	  ;查表取得段码 
	CJNE	A,#01H,S2	  ;判断段码是否为结束符
	SJMP	START
S2:	MOV 	B,A		  ;段码送B保存
	MOV	A,R7
	RL 	A		  ;显示位扫描值左移1位
	MOV 	P3,A		  ;显示位扫描值送P3口
	MOV 	R7,A
	MOV	P0,B		  ;显示段码送P0显示
	LCALL	DELAY		  ;延时
	INC	DPTR
	SJMP	S1
DELAY: 	MOV 	R5,#20		  ;延时子程序
D2: 	MOV 	R6,#20
D1: 	NOP
	DJNZ 	R6,D1
	DJNZ 	R5,D2
	RET							  
TABLE: 	DB 	3FH,06H,5BH,4FH,66H,6DH,7DH,07H	  ;0-7共阴段码表
	DB	01H				  ;结束符
	END

四、PBL练习2

【Proteus仿真+Keil汇编】(PBL练习2)_第6张图片

 说明:

数码管:
段选端连P0口,位选端连P1口
矩阵键盘:
行连P2口低三位,列连P3口低三位
LED:
用于观察数码管位选端

/*************矩阵式键盘输入**************/

	KS:	 MOV A,#00H
			MOV P3,A
			CPL   A                     ;变正逻辑:高电平表示有键按下	
			ANL   A,  #0FH	           ;屏蔽高4位
			RET
											;
	KEY:    LCALL   KS        ;判别有无键按下	   	     
			JNZ     K1               ;(A)不等于0,有键按下,转K1	
			LCALL   DELAY1	           ;无键按下调用延时子程序     
			AJMP    KEY                   ;返回重新查询	     
	K1:     LCALL   DELAY1           			 ;加长延时,消除键抖动     
			LCALL   KS                    ;再次查询有无键按下     
			JNZ     K2	         		 ; (A)不等于0,有键按下,转逐列扫描     
			AJMP    KEY	         		 ;误读键,返回     
												
	K2:     MOV     R2,  #0FEH ;首列扫描字送R2
			MOV     R4,  #00H             ;首列号送R4
	K3:     MOV     A,  R2               
			MOV     P3,  A 			;列扫描字送P3口       
			JB      P2.0,  L1		 ;P2.0=1,第0行无键按下,转查第一行
			MOV     A,  #00H		  		 ;第0行有键按下,行首键号送A
			AJMP    LK	                 ;转求键号
												;
	L1:     JB       P2.1,  L2		 ;P2.1=1,第1行无键按下,转查第2行
			MOV A,  #03H							 ;第1行有键按下,行首键号送A
			AJMP   LK						 ;转求键号
	L2:       
			JB       P2.2,  NEXT		 ;P2.2=1,第2行无键按下,转查第3行
			MOV    A, #06H					 ;第2行有键按下,行首键号送A 
			AJMP   LK			 			 ;转求键号
													
	LK:     ADD    A, R4						 ;形成键码送A:键码=行首键码+列号
	MOV R1,A 						 ;键码A送R1保存
			SJMP START
								                   ;准备扫描下一列
	NEXT:   INC    R4								 ;修改列号,扫描下一列		 
			MOV   A,R2                   ;列数据送A
			JNB   P3.2, KEY	  			 ;P3.2=0,4列扫描完,返回KEY 
			RL    A	                     ;未扫描完,扫描字左移一位
			MOV   R2, A					 ;扫描字存R2		 
			AJMP  K3		                
	DELAY1: MOV     R7, #0FFH
	LP0:    MOV     R6, #0FFH
	LP:     NOP
            DJNZ    R6, LP
            DJNZ    R7, LP0			
            RET
/*************多LED数码管动态输出显示**************/

	START: 	MOV A,#00H
			MOV DPTR,#TABLE	  ;DPTR指向段码表首地址
			MOV 	R7,#7FH      	  ;设置动态显示扫描初值
	S1: 	ADD A,R1              ;获取键码
			MOVC A,@A+DPTR        ;显示键码值
			MOV 	B,A		  ;段码送B保存
	S2:		MOV	A,R7
			RL 	A		  ;显示位扫描值左移1位
			MOV 	P1,A		  ;显示位扫描值送P3口
			MOV 	R7,A
			MOV	P0,B		  ;显示段码送P0显示
			LCALL	DELAY		  ;延时
			JNB P1.7,K1
			SJMP S2
			
	DELAY: 	MOV 	R5,#200		  ;延时子程序
	D2: 	MOV 	R6,#248
	D1: 	NOP
			DJNZ 	R6,D1
			DJNZ 	R5,D2
			RET		
	TABLE: 	DB 	06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH	  ;1-9共阴段码表
			DB	01H				  ;结束符
					
			END

②实现效果二:按下键盘,键盘对应数字显示在数码管对应位上

(ps:对应proteus电路图跟效果一演示电路图一致)

		ORG 0000H
		LJMP KEY
		ORG 0030H
/*************矩阵式键盘输入**************/

	KS:	 MOV A,#00H
			MOV P3,A
			CPL   A                     ;变正逻辑:高电平表示有键按下	
			ANL   A,  #0FH	           ;屏蔽高4位
			RET
											;
	KEY:    
			LCALL   KS        ;判别有无键按下	   	     
			JNZ     K1               ;(A)不等于0,有键按下,转K1	
			LCALL   DELAY1	           ;无键按下调用延时子程序     
			AJMP    KEY                   ;返回重新查询	     
	K1:     LCALL   DELAY1           			 ;加长延时,消除键抖动     
			LCALL   KS                    ;再次查询有无键按下     
			JNZ     K2	         		 ; (A)不等于0,有键按下,转逐列扫描     
			AJMP    KEY	         		 ;误读键,返回     
												
	K2:     MOV     R2,  #0FEH ;首列扫描字送R2
			MOV     R4,  #00H             ;首列号送R4
	K3:     MOV     A,  R2               
			MOV     P3,  A 			;列扫描字送P3口       
			JB      P2.0,  L1		 ;P2.0=1,第0行无键按下,转查第一行
			MOV     A,  #00H		  		 ;第0行有键按下,行首键号送A
			AJMP    LK	                 ;转求键号
												;
	L1:     JB       P2.1,  L2		 ;P2.1=1,第1行无键按下,转查第2行
			MOV A,  #03H							 ;第1行有键按下,行首键号送A
			AJMP   LK						 ;转求键号
	L2:       
			JB       P2.2,  NEXT		 ;P2.2=1,第2行无键按下,转查第3行
			MOV    A, #06H					 ;第2行有键按下,行首键号送A 
			AJMP   LK			 			 ;转求键号
												
	
	LK:     ADD    A, R4						 ;形成键码送A:键码=行首键码+列号
	MOV R1,A 						 ;键码A送R1保存
			SJMP START
								                   ;准备扫描下一列
	NEXT:   INC    R4								 ;修改列号,扫描下一列		 
			MOV   A,R2                   ;列数据送A
			JNB   P3.2, KEY	  			 ;P3.2=0,4列扫描完,返回KEY 
			RL    A	                     ;未扫描完,扫描字左移一位
			MOV   R2, A					 ;扫描字存R2		 
			AJMP  K3		                 ;
	DELAY1: MOV     R7, #0FFH
	LP0:    MOV     R6, #0FFH
	LP:     NOP
            DJNZ    R6, LP
            DJNZ    R7, LP0			
            RET                  		
                                                         
/*************多LED数码管动态输出显示**************/

	START: 	MOV A,#00H
			MOV DPTR,#TABLE	  ;DPTR指向段码表首地址
			//MOV 	R7,#7FH      	  ;设置动态显示扫描初值
			
	S1: 	ADD A,R1              ;获取键码
			MOVC A,@A+DPTR        ;显示键码值
			MOV 	B,A		  ;段码送B保存			
			MOV A,R1					;获取位码
			MOV DPTR,#TABLE1	  ;DPTR指向位码表首地址
			MOVC A,@A+DPTR        ;显示位码值
			MOV R7,A
			
	S2:		;MOV	A,R7
			;RL 	A		  ;显示位扫描值左移1位
			;MOV 	P1,A		  ;显示位扫描值送P3口
			;MOV 	R7,A
			MOV	P1,R7		  ;显示位码送P1显示
			MOV	P0,B		  ;显示段码送P0显示
			LCALL	DELAY		  ;延时
			//JNB P1.7,K1
			SJMP KEY
			
	DELAY: 	MOV 	R5,#200		  ;延时子程序
	D2: 	MOV 	R6,#248
	D1: 	NOP
			DJNZ 	R6,D1
			DJNZ 	R5,D2
			RET		
	TABLE: 	DB 	06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH	  ;1-9共阴段码表
			DB	01H				  ;结束符
	TABLE1: DB 	0feH,0fdH,0fbH,0f7H,0efH,0dfH,0bfH,07fH	  ;8 位码表
			DB	02H				
					
			END

最终演示效果在本人视频分区中,请移步观看

你可能感兴趣的:(proteus,单片机,嵌入式硬件)