PIC单片机 按键检测识别

按键和PIC单片机

一、按键

按键是嵌入式系统基本的人机交互手段,其使用步骤包括:检测连通、消抖、行为判断

image-20210911100053055

二、按键的物理连接与检测

简单按键

image-20210907144706229

缺点:占用端口引脚太多,一个按键就占一个引脚。

行列扫描按键

image-20210907144816499
  1. 行为input,列为output

  2. 每个列依次接地,同时其他列高阻态(建议不用逻辑1,防止短路),观察哪一/些行为0,就能锁定到被按下的按键

  3. 有多个按键同时被按下时,程序可能会错误判断按键,不可信

  4. 上面这种对比简单按键并没有优势,还是太占用引脚

行列扫描的扩展

image-20210907145650496
  1. 二极管限制了电流的流向,通过控制两个引脚的输入输出方向来判断不同按键。
  2. 但是因为每个按键都加入了一个二极管,成本增加且占用面积。

全扫描

image-20210907150107255

行列之间两两一个,行行、列列间也是两两一个。

简单按键+全扫描

image-20210907150510579

要求7~10与1~6不能同时检测,因为两组之间彼此干扰。因此必须先检测7~中有没有按下,没有的话再检测1~6。检测到有一个按下后就结束,不能检测多个同时按下的情况,不准确。

三、PIC16F18854单片机

按键检测及显示实验

按键排布

  简单按键+全扫描,四根线对应连接到PIC单片机的4个引脚,最后一根接地。

image-20210911101607560
预期效果

  4位数码管显示按键编号、行为、按动次数

总体流程

  数码管片选与段选各自维护一个查找表,在主程序中循环对数码管进行片选、段选、延时,其中段选时按照显示缓冲区内容执行。定时器中断周期设置为5ms,中断服务程序提供:连通检测、消抖、状态转换、显示驱动服务。其中关键部分是中断服务程序的设计。

image-20210911102225288 image-20210911102311079
中断服务程序

  中断服务程序分为4个模块,模块间充分解耦,其间只有个别变量在整个流程中进行传递,其他大部分变量都是各个模块自身的局部变量。

image-20210911102641294

1、连通检测

step1:单片机4个引脚弱上拉,依次检查4个引脚有无0电平,即7~10号按键有无按下,若无则进入step2。

step2:4个引脚两两间有6个按键,依次检测一遍,若只有1对为连通则说明仅一个按键按下,若有多对连通则为多按键被按下。

最后将检测到的连通状态cur_key传入消抖模块。

代码流程图:

image-20210911114313877

2、消抖模块

  检测连通检测模块传入的cur_key与上次传入的是否相同,若连着两次相同则认为不是抖动,继续传入状态转换模块;若不同,则认为是抖动造成的,把上次的key传入状态转换模块。本质是要求同一按键连按10ms才认为是按下而不是抖动。

代码流程图:

image-20210911114453552

3、状态转换

  状态转换模块功能是,根据消抖模块传入的cur_key来改变当前状态tatus,并且把相对应事件event和cur_key一起传入给后面的显示驱动模块。“输入——状态改变——输出”的运行逻辑正是一个状态机。

state\action MULTIKEY UP TIMEOUT SAME OTHER
CLICK init(single) wait press(press) click init(single)
WAIT init(single) wait init(single) double(double) click(single)
PRESS init(press_up) init(press_up) - same(press) init(press_up)
INIT init init - click click
DOUBLE init init - double init

代码流程图:

image-20210911114410604

4、显示驱动

  根据状态转换模块传来的event和cur_key调制主程序段选时使用的显示缓存区,从而在数码管显示按键状态和相应信息。

代码流程图:

image-20210911114434317
PIC汇编程序
#include <xc.inc>
    psect   intentry, class=CODE, delta=2
    psect   reset_vec, class=CODE, delta=2
    psect   eeprom_data,class=EEDATA,delta=2,space=3,noexec
    psect   powerup, class=CODE, delta=2
    psect   cinit,class=CODE,delta=2
    psect   functab,class=ENTRY,delta=2
    psect   idloc,class=IDLOC,delta=2,noexec

    global _main, reset_vec
    
psect config, class=CONFIG, delta=2
#ifndef BOOTLOADER
    dw	0xDFEC
    dw	0xF7FF
    dw	0xFFBF
    dw	0xEFFE
    dw	0xFFFF
#endif
    
    psect	reset_vec
reset_vec:
    ljmp	_main


;GLOBAL VARIABLES
    psect	CommonVar, class=COMMON, space=1, delta=1
;main
dis_cache:	ds 4
delay1:	ds 1
delay2:	ds 1
;debounce
last_result:	ds 1
count:		ds 1
;status_trans
action:	ds 1
state:		ds 1
event:		ds 1
wait_count:	ds 1
click_count:  ds 1
last_key:	ds 1
;connection_check
index:		ds 1
;global
cur_key:	ds 1
    psect	udata
i:		ds 1
j:		ds 1
led_select:	ds 1
workplace2:	ds 1
dis_last_key:	ds 1
dis_count:	ds 2
swap:		ds 1
press_count:ds 1


;STATIC TABLE
    psect	Table, class=CODE, delta=2
event_table: 
    MOVWF        PCL
IRP event,1,0,3,0,1,1,0,1,2,1,4,4,0,3,4
    RETLW   event
ENDM

action_table: 
    MOVWF        PCL 
IRP row_click,0b1111,0b101,0b1010,0b0,0b1111
    RETLW   row_click
ENDM
IRP row_wait,0b1111,0b101,0b1111,0b10100,0b0
    RETLW   row_wait
ENDM
IRP row_press,0b1111,0b1111,0xff,0b1010,0b1111
    RETLW   row_press
ENDM
IRP row_init,0b1111,0b1111,0xff,0b0,0b0
    RETLW   row_init
ENDM
IRP row_double,0b1111,0b1111,0xff,0b10100,0b1111
    RETLW   row_double
ENDM

seq_table:
    ADDWF        PCL,f
IRP seq_num,0b00111111,0b00000110,0b01011011,0b01001111,0b01100110,0b01101101,0b01111101,0b00000111,0b01111111,0b01101111,0b01110111
    RETLW    seq_num
ENDM
    
code_table:
    MOVWF PCL
IRP code_num,0b00000111,0b00001011,0b00001101,0b00001110
    RETLW   code_num
ENDM

key_table: 
    ADDWF        PCL,F   
IRP key_num,5,1,2,3,4,6
    RETLW   key_num
ENDM


;INTERRUPT SERVICE
    psect intentry
intentry:
	;clear the signal bit
	BANKSEL PIR0
	BCF PIR0,5
    
	;init the TMR0 offset
	BANKSEL TMR0L
	;MOCLW 0xfec0c
	MOVLW 0xec
	MOVWF TMR0H
	MOVLW 0x78
	MOVWF TMR0L
    
    connection_check:
    CLRF cur_key
    BANKSEL i
    MOVLW 1
    MOVWF i
    CLRF index
    BANKSEL TRISB
    MOVLW 0x0f
    MOVWF TRISB
    BANKSEL WPUB
    MOVLW 0x0f
    MOVWF WPUB
jedge_i_16:
    BANKSEL i
    BTFSS i,4
    GOTO i_unequ_16
    GOTO i_equ_16
    
i_unequ_16:
    BANKSEL i
    MOVF i, W
    BANKSEL PORTB
    ANDWF PORTB, W

    BANKSEL workplace2
    MOVWF workplace2
    MOVF workplace2,f
    BTFSS STATUS,2 
    GOTO branch1_portb_unequ_0
    GOTO branch1_portb_equ_0
    
i_equ_16:
    MOVF cur_key, f
    BTFSS STATUS,2
    GOTO trunk_curkey_unequ_0
    GOTO trunk_curkey_equ_0
    
branch1_portb_equ_0:
    MOVF cur_key,f
    BTFSS STATUS,2
    GOTO branch1_curkey_unequ_0
    GOTO branch1_curkey_equ_0
    
branch1_portb_unequ_0:
    BANKSEL i
    LSLF i, f
    INCF index,f
    GOTO jedge_i_16
    
branch1_curkey_unequ_0:
    MOVLW 255
    MOVWF cur_key
    GOTO trunk_curkey_unequ_0
    
branch1_curkey_equ_0:
    MOVLW 7
    ADDWF index, W
    MOVWF cur_key
    GOTO branch1_portb_unequ_0
    
trunk_curkey_unequ_0:
    GOTO debounce

trunk_curkey_equ_0:
    BANKSEL i
    MOVLW 1
    MOVWF i
    MOVLW 2
    MOVWF j
    CLRF index
jedge_i_8:
    BTFSS i, 3
    GOTO i_unequ_8
    GOTO i_equ_8

i_unequ_8:
    MOVF j, w
    BTFSS j, 4
    GOTO j_unequ_16
    GOTO j_equ_16
    
i_equ_8:
    GOTO trunk_curkey_unequ_0
    
j_unequ_16:
    BANKSEL j
    COMF j, W
    BANKSEL TRISB
    MOVWF TRISB
    BANKSEL WPUB
    MOVWF WPUB
    BANKSEL PORTB
    MOVWF PORTB
    
    BANKSEL i
    MOVF i, W
    BANKSEL PORTB
    ANDWF PORTB, W

    BANKSEL workplace2
    MOVWF workplace2
    MOVF workplace2,F
    BTFSS STATUS,2 
    GOTO branch2_portb_unequ_0
    GOTO branch2_portb_equ_0
    
j_equ_16:
    BANKSEL i
    LSLF i, f
    LSLF i, W
    MOVWF j
    GOTO jedge_i_8
    
    
branch2_portb_equ_0:
    MOVF cur_key,F 
    BTFSS STATUS,2 
    GOTO branch2_curkey_unequ_0
    GOTO branch2_curkey_equ_0
    
branch2_portb_unequ_0:
    LSLF j, f
    INCF index, f
    GOTO i_unequ_8
    
branch2_curkey_equ_0:
    ;cur_key = key_table[index]
    MOVLW HIGH(key_table)
    MOVWF PCLATH  
    MOVF index,W
    CALL key_table
    MOVWF cur_key
    GOTO j_equ_16
    
branch2_curkey_unequ_0:
    MOVLW 255
    MOVWF cur_key
    GOTO i_equ_8

debounce:
    MOVF    last_result, W
    XORWF   cur_key, W
    BTFSC   STATUS, 2
    GOTO    deb_continue    ;no shake
    INCF    count	    ;shake
    MOVLW   2
    XORWF   count, W
    BTFSS   STATUS, 2
    GOTO    deb_ignore	    ;not equ
    MOVF    cur_key, W;equ
    MOVWF   last_result
    GOTO    deb_continue
    
deb_ignore:
    MOVF    last_result, W
    MOVWF   cur_key
    GOTO    transfer
    
deb_continue:
    CLRF    count
    GOTO transfer
    
    
transfer:
;key value
    MULTI	EQU 0xFF
    NOKEY	EQU 0
;action index
    MULTIKEY	EQU 0
    UP		EQU 1
    TIMEOUT	EQU 2
    SAME	EQU 3
    OTHER	EQU 4
;state value
    CLICK	EQU 0
    WAIT	EQU 5
    PRESS	EQU 10
    INIT	EQU 15
    DOUBLE	EQU 20
;const
    UPCOUNT	EQU 60
    PRESSCOUNT	EQU 100
    PRESSADD	EQU 100
trans_judge_action:
    MOVLW   MULTI
    XORWF   cur_key, w
    BTFSC   STATUS, 2
    GOTO    action_multi	;multi
    MOVLW   NOKEY		;continue
    XORWF   cur_key, w
    BTFSC   STATUS, 2
    GOTO    action_up_timeout	;up
    MOVF    last_key, w		;down
    XORWF   cur_key, w
    BTFSC   STATUS, 2
    GOTO    action_same_timeout ;same
    GOTO    action_other	 ;other
;    
action_multi:
    MOVLW   MULTIKEY
    GOTO    do_transfer
action_up_timeout:
    MOVLW   WAIT
    XORWF   state, w
    BTFSS   STATUS, 2
    GOTO    action_up	    ;not wait
    INCF    wait_count	    ;waiting
    MOVLW   UPCOUNT
    XORWF   wait_count, w
    BTFSS   STATUS, 2
    GOTO    action_up
    GOTO    action_timeout
    
action_up:
    MOVLW   UP
    GOTO    do_transfer    
action_same_timeout:
    MOVLW   CLICK
    XORWF   state, w
    BTFSS   STATUS, 2
    GOTO    action_same
    INCF    click_count
    MOVLW   PRESSCOUNT
    XORWF   click_count, w
    BTFSS   STATUS, 2
    GOTO    action_same
    GOTO    action_timeout
action_same:
    MOVLW   SAME
    GOTO    do_transfer
action_timeout:
    MOVLW   TIMEOUT
    GOTO    do_transfer     
action_other:
    MOVLW   OTHER
    GOTO    do_transfer
       
do_transfer:
    MOVWF   action
    CLRF    event
    
    MOVF    state, w
    addlw   1
    ADDWF   action, f
    MOVLW   INIT+1
    SUBWF   action, w
    BTFSC   STATUS, 0
    GOTO    change_state ;no carry -> state+action+1>=INIT+1
    movlp   high(event_table)
    MOVLW   low(event_table)
    ADDWF   action, w
    BTFSC   STATUS, 0
    INCF    PCLATH
    CALL    event_table  ;get next state
    MOVWF   event
change_state:
    movlp   high(action_table)
    MOVLW   low(action_table)
    ADDWF   action, w
    BTFSC   STATUS, 0
    INCF    PCLATH
    CALL    action_table  ;get next state
    MOVWF   state

clear_count_judge:
    MOVF    event, f
    BTFSC   STATUS, 2
    GOTO    transfer_final ;event == 0

clear_count:
    CLRF    wait_count
    CLRF    click_count

transfer_final:
    banksel swap
    MOVF    last_key, w
    MOVWF   swap
    
    MOVWF   cur_key, w
    BTFSS   STATUS, 2
    MOVWF   last_key
    
    MOVF    swap, w
    MOVWF   cur_key
    
display:
    MOVF    event, f
    BTFSC   STATUS, 2
    RETFIE
    banksel dis_last_key
    MOVF    dis_last_key, W
    XORWF   cur_key, W
    BTFSC   STATUS, 2
    GOTO    display_judge_event
display_change:
    banksel dis_count
    CLRF    dis_count
    CLRF    dis_count+1
    MOVF    cur_key, W
    banksel dis_last_key
    MOVWF   dis_last_key
display_judge_event:
    banksel dis_count
    MOVLW   3
    SUBWF   event, W
    BTFSS   STATUS, 0
    GOTO    event_1_2   ;if carry -> event<3
    MOVLW   3
    XORWF   event, W
    BTFSC   STATUS, 2
    GOTO    event_3
    GOTO    display_final

event_1_2:
    MOVF    event,W
    ADDWF   dis_count, F
    GOTO    display_final
event_3:
    INCF    press_count
    MOVLW   PRESSADD
    XORWF   press_count, W
    BTFSC   STATUS, 2
    GOTO    event_3_add_count
    GOTO    display_final

event_3_add_count:
    INCF    dis_count
    CLRF    press_count

display_final:
    MOVF   cur_key, W
    MOVWF   dis_cache
    MOVF    event,W
    MOVWF   dis_cache+1
    MOVLW   10
    SUBWF   dis_count, W
    BTFSS   STATUS, 0
    GOTO    display_count   ;if carry
display_count_carry:
    INCF    dis_count+1
    MOVLW   10
    SUBWF   dis_count, F
    SUBWF   dis_count+1, W
    BTFSC   STATUS, 0
    CLRF    dis_count+1	;if no carry
display_count:
    MOVF    dis_count, W
    MOVWF   dis_cache+3
    MOVF    dis_count+1, W
    MOVWF   dis_cache+2
    
    RETFIE

	
;MAIN FUNCTION
psect   main,class=CODE,delta=2 ; PIC10/12/16   
global _main
_main:
    
;Timer0 configuration
BANKSEL T0CON0
MOVLW 0b00010000;set Timer0 in 16bit mode,post:1:8
MOVWF T0CON0
BANKSEL T0CON1
MOVLW 01000000;FOCS/4,synchronized to FOSC/4,pre:1:1
MOVWF T0CON1
BANKSEL TMR0L
MOVLW 0xfe
MOVWF TMR0H
MOVLW 0x0c
MOVWF TMR0L;init the TMR0 offset

    
;interrupt configuration
BANKSEL PIR0
BCF PIR0,5;clear the timer signal bit
banksel INTCON
BSF INTCON,0;INT enable
BSF INTCON,7;global enable
banksel PIE0
BSF PIE0,5;timer0_interrupt enable


;start timing
BANKSEL T0CON0
BSF T0CON0,7; enable Timer0


;init PORTA / PORTB / PORTC
BANKSEL PORTA 
CLRF PORTA ;Init PORTA
BANKSEL LATA ;Data Latch
CLRF LATA 
BANKSEL ANSELA 
CLRF ANSELA ;digital I/O
BANKSEL TRISA 
CLRF TRISA

BANKSEL LATB ;Data Latch
CLRF LATB
BANKSEL ANSELB 
CLRF ANSELB ;digital I/O
 
BANKSEL PORTC
BANKSEL PORTC
CLRF PORTC ;Init PORTC
BANKSEL LATC ;Data Latch
CLRF LATC
BANKSEL ANSELC
CLRF ANSELC ;digital I/O
BANKSEL TRISC
CLRF TRISC


;init variables
CLRF dis_cache
CLRF dis_cache + 1
CLRF dis_cache + 2
CLRF dis_cache + 3
CLRF last_result
CLRF count
CLRF action
MOVLW 15
MOVWF state
CLRF wait_count
CLRF click_count
CLRF last_key
CLRF index
CLRF cur_key
BANKSEL led_select
CLRF led_select
CLRF i
CLRF j
CLRF dis_last_key
CLRF dis_count
CLRF swap
CLRF press_count
CLRF workplace2


;MAIN
LOOP:
;code_sel
MOVLW HIGH(code_table)
MOVWF PCLATH      
MOVLW LOW(code_table)
BANKSEL led_select
ADDWF led_select, W
BTFSS STATUS, 0
GOTO CALL_TABLE
INCF PCLATH
CALL_TABLE:
ADDLW 1
CALL code_table
BANKSEL PORTA 
MOVWF PORTA


;seq_sel
MOVLW HIGH(seq_table)
MOVWF PCLATH  
;w = dis_cache + offset
MOVLW   high(dis_cache)
MOVWF   FSR0H
MOVLW   low(dis_cache)
BANKSEL led_select
ADDWF   led_select, w
MOVWF   FSR0L
MOVF    INDF0, w
;seq_table[dis_cache + offset]
CALL seq_table
MOVWF PORTC   

    
;led_select = (led_select + 1) mod 4
BANKSEL led_select
INCF led_select,f
MOVLW 0b11
ANDWF led_select,f

    
;delay
MOVLW 2
MOVWF delay2
DELAY1:
MOVLW 0xff
MOVWF delay1
DECFSZ delay1,f
GOTO $-1
DECFSZ delay2,f
GOTO DELAY1

    
;end seq_select
CLRF PORTC

    
GOTO LOOP
    
end reset_vec

猜你喜欢

转载自blog.csdn.net/qq_45753394/article/details/120244710