控制芯片: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 ;PORTBTRISB扫描配置信息
    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是吴显示)。