控制芯片:PIC16F883
引脚图:
按键连接图:
四位数码管连接:四个共阴极分别连接PORTA<3:0>,8段数码管分别连接PORTC<7:0>,PORTB<4,2:0>分别连接按键的四个I/O引脚。
我在PORTC上连接了数码管,按键进行编号。按键时数码管会显示对应的编号。
简单说明:
我是改变PORTB引脚的设置(TRISB,PORTB),写了后立刻读取PORTB引脚的值,检查连接按键的引脚——值为0的引脚有按键按下。比如上图,PORTB<4,2,1,0>引脚全设置为输入时,读取PORTB寄存器的值。若我按下了S7,PORTB4就是0值(同理S8\S9\S10)。我们微机原理老师强调一定先检测S7\S8\S9\S10。我没试过先检测其他按键的情况,是按照老师的提示做的。下次更改设置:PORTB4设为输出低电位(0),其他三个引脚都设置为输入。读取PORTB<2,1,0>引脚的值,S5\S1\S2中某一按键被按下就可以在PORTB<2,1,0>对应的引脚检测到。就这样扫描所有按键,有按键按下就会调用按键处理程序。
实现代码如下:
#include<p16f883.inc> udata_shr counter res 1 ;延时计数 counter0 res 1 ;延时计数 counter1 res 1 ;扫描按键变量 counter2 res 1 ;延时程序微调参数 key_state res 1 ;按键状态 keynum res 1 ;按键标号 swap res 1 ;确认按键转换值 keydown res 1 keyup res 1 reset code 0x0000 pagesel start goto start ;int_vector code 0x0004 code start banksel ANSEL ;设置PORTA为数字模式 clrf ANSEL banksel ANSELH ;设置PORTB为数字模式 clrf ANSELH banksel WPUB ;设置PORTB弱上拉 movlw b'11111111' movwf WPUB banksel OPTION_REG movlw b'01000101' ;TMR0 64分频 movwf OPTION_REG banksel TRISA ;设置PORTA<3:0>为输出,接数码管的共阴极 movlw b'11110000' movwf TRISA banksel PORTA clrf PORTA banksel TRISC movlw b'00000000' ;设置PORTC为输出,接8段数码管 movwf TRISC loop banksel TRISB movf counter1,0 call Table1 movwf TRISB banksel PORTB movwf PORTB movf PORTB,0 movwf key_state movlw b'11101000' iorwf key_state,1 movf counter1,0 call Table1 xorwf key_state,0 movwf swap comf swap,1 incfsz swap,1 goto case1 incf counter1,1 movf counter1,0 call Table1 banksel TRISB movwf TRISB movf counter1,0 call Table1 banksel PORTB movwf PORTB movf PORTB,0 ;读取I/O状态 movwf key_state movlw b'11001000' iorwf key_state,1 movf counter1,0 call Table1 xorwf key_state,0 movwf swap comf swap,1 incfsz swap,1 goto case2 incf counter1,1 movf counter1,0 call Table1 banksel TRISB movwf TRISB movf counter1,0 call Table1 banksel PORTB movwf PORTB movf PORTB,0 ;读取I/O状态 movwf key_state movlw b'11001000' iorwf key_state,1 movf counter1,0 call Table1 xorwf key_state,0 movwf swap comf swap,1 incfsz swap,1 goto case3 incf counter1,1 movf counter1,0 call Table1 banksel TRISB movwf TRISB movf counter1,0 call Table1 banksel PORTB movwf PORTB movf PORTB,0 ;读取I/O状态 movwf key_state movlw b'11001000' iorwf key_state,1 movf counter1,0 call Table1 xorwf key_state,0 movwf swap comf swap,1 incfsz swap,1 goto case4 goto continue case1 btfsc key_state,4 goto key2 movlw d'1' movwf keynum call DealKeyPress goto continue key2 btfsc key_state,2 goto key3 movlw d'2' movwf keynum call DealKeyPress goto continue key3 btfsc key_state,1 goto key4 movlw d'3' movwf keynum call DealKeyPress goto continue key4 btfsc key_state,0 goto continue movlw d'4' movwf keynum call DealKeyPress goto continue case2 ;------------------------------------------------- ;下面代码实现K10\K8\K5的按键处理 btfsc key_state,2 goto key8 movlw d'10' movwf keynum call DealKeyPress goto continue ;------------------------------------ ;处理K8 key8 btfsc key_state,1 goto key5 movlw d'8' movwf keynum call DealKeyPress goto continue ;------------------------------------ ;处理K5 key5 btfsc key_state,0 goto case3 movlw d'5' movwf keynum call DealKeyPress goto continue case3 ;---------------------------------- ;处理K6/K9 btfsc key_state,1 goto key6 movlw d'9' movwf keynum call DealKeyPress goto continue key6 btfsc key_state,0 goto case4 movlw d'6' movwf keynum call DealKeyPress goto continue case4 ;----------------------------------------- ;处理K7 btfsc key_state,0 goto continue movlw d'7' movwf keynum call DealKeyPress continue clrf counter1 goto loop delay ;按键去抖,约8mS movlw d'4' movwf counter2 LOOP2 banksel TMR0 clrf TMR0 LOOP1 banksel INTCON btfss INTCON,T0IF goto LOOP1 bcf INTCON,T0IF decfsz counter2,1 goto LOOP2 return DealKeyPress call delay movf counter1,0 call Table1 banksel TRISB movwf TRISB banksel PORTB movwf PORTB movf PORTB,0 ;读取I/O状态 movwf key_state movlw b'11101000' iorwf key_state,1 movf counter1,0 call Table1 xorwf key_state,0 movwf swap comf swap,1 incfsz swap,1 goto continue movf keynum,0 call Table3 banksel PORTC movwf PORTC clrf keynum return Table1 ;PORTB、TRISB扫描配置信息 ADDWF PCL,f RETLW B'11111111' RETLW B'11101111' RETLW B'11111011' RETLW B'11111101' Table3 ;PORTC设置,数码管真值表 ADDWF PCL,f RETLW B'01001001' ;三条横线 RETLW B'10111111' ;0 RETLW B'00000110' ;1 RETLW B'01011011' ;2 RETLW B'01001111' ;3 RETLW B'01100110' ;4 RETLW B'01101101' ;5 RETLW B'01111101' ;6 RETLW B'00000111' ;7 RETLW B'01111111' ;8 RETLW B'01101111' ;9 end
我用逻辑与运算屏蔽掉PORTB<7,6,4>号引脚。仅检查PORTB<4,2,1,0>引脚。该方法先检测按键7、8、9、10,调整配置后检测按键5、1、2,再调整配置检测按键3、4,最后调整配置检测按键6。
1)PORTB<4,2,1,0>设置为输入,然后读取并检测这四个角
2)PORTB4设置为输出低电平0,PORTB<2,1,0>设置为输入,然后检测2、1、0引脚电平(为0则有按键按下)
3)PORTB2设置为输出低电平,其他三个脚设置为输入,仅检测1、0引脚电平
4)PORTB1设置为输出低电平,其他三个角设置为输入,仅检测0引脚电平
由于我的按键编号与上图连接图不一致,图中的K7、K8、K9、K10分别对应我的K1、K2、K3、K4(按下数码管会显示1、2、3、4),K2、K4、K6分别对应我的K5、K6、K7(按下会显示5、6、7),K1、K3分别对应我的K8、K9(按下分别显示8、9),K5对应我的K10(这个由于数码管只设置1-9,K10按下会显示7是吴显示)。