PIC单片机 按键检测识别
目錄
- 按鍵和PIC單片機
- 一、按鍵
- 二、按鍵的物理連接與檢測
- 三、PIC16F18854單片機
- 按鍵檢測及顯示實驗
- 按鍵排布
- 預期效果
- 總體流程
- 中斷服務程序
- PIC匯編程序
按鍵和PIC單片機
一、按鍵
按鍵是嵌入式系統基本的人機交互手段,其使用步驟包括:檢測連通、消抖、行為判斷
?
二、按鍵的物理連接與檢測
簡單按鍵
缺點:占用端口引腳太多,一個按鍵就占一個引腳。
?
行列掃描按鍵
行為input,列為output
每個列依次接地,同時其他列高阻態(建議不用邏輯1,防止短路),觀察哪一/些行為0,就能鎖定到被按下的按鍵
有多個按鍵同時被按下時,程序可能會錯誤判斷按鍵,不可信
上面這種對比簡單按鍵并沒有優勢,還是太占用引腳
?
行列掃描的擴展
?
全掃描
行列之間兩兩一個,行行、列列間也是兩兩一個。
?
簡單按鍵+全掃描
要求7~10與1~6不能同時檢測,因為兩組之間彼此干擾。因此必須先檢測7~中有沒有按下,沒有的話再檢測1~6。檢測到有一個按下后就結束,不能檢測多個同時按下的情況,不準確。
?
?
三、PIC16F18854單片機
按鍵檢測及顯示實驗
按鍵排布
??簡單按鍵+全掃描,四根線對應連接到PIC單片機的4個引腳,最后一根接地。
?
預期效果
??4位數碼管顯示按鍵編號、行為、按動次數
?
總體流程
??數碼管片選與段選各自維護一個查找表,在主程序中循環對數碼管進行片選、段選、延時,其中段選時按照顯示緩沖區內容執行。定時器中斷周期設置為5ms,中斷服務程序提供:連通檢測、消抖、狀態轉換、顯示驅動服務。其中關鍵部分是中斷服務程序的設計。
?
?
中斷服務程序
??中斷服務程序分為4個模塊,模塊間充分解耦,其間只有個別變量在整個流程中進行傳遞,其他大部分變量都是各個模塊自身的局部變量。
?
1、連通檢測
step1:單片機4個引腳弱上拉,依次檢查4個引腳有無0電平,即7~10號按鍵有無按下,若無則進入step2。
step2:4個引腳兩兩間有6個按鍵,依次檢測一遍,若只有1對為連通則說明僅一個按鍵按下,若有多對連通則為多按鍵被按下。
最后將檢測到的連通狀態cur_key傳入消抖模塊。
代碼流程圖:
?
2、消抖模塊
??檢測連通檢測模塊傳入的cur_key與上次傳入的是否相同,若連著兩次相同則認為不是抖動,繼續傳入狀態轉換模塊;若不同,則認為是抖動造成的,把上次的key傳入狀態轉換模塊。本質是要求同一按鍵連按10ms才認為是按下而不是抖動。
代碼流程圖:
?
3、狀態轉換
??狀態轉換模塊功能是,根據消抖模塊傳入的cur_key來改變當前狀態tatus,并且把相對應事件event和cur_key一起傳入給后面的顯示驅動模塊。“輸入——狀態改變——輸出”的運行邏輯正是一個狀態機。
| 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 |
代碼流程圖:
?
4、顯示驅動
??根據狀態轉換模塊傳來的event和cur_key調制主程序段選時使用的顯示緩存區,從而在數碼管顯示按鍵狀態和相應信息。
代碼流程圖:
?
?
PIC匯編程序
#include <xc.inc>psect intentry, class=CODE, delta=2psect reset_vec, class=CODE, delta=2psect eeprom_data,class=EEDATA,delta=2,space=3,noexecpsect powerup, class=CODE, delta=2psect cinit,class=CODE,delta=2psect functab,class=ENTRY,delta=2psect idloc,class=IDLOC,delta=2,noexecglobal _main, reset_vecpsect config, class=CONFIG, delta=2 #ifndef BOOTLOADERdw 0xDFECdw 0xF7FFdw 0xFFBFdw 0xEFFEdw 0xFFFF #endifpsect reset_vec reset_vec:ljmp _main;GLOBAL VARIABLESpsect 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 1psect 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 TABLEpsect 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,4RETLW event ENDMaction_table: MOVWF PCL IRP row_click,0b1111,0b101,0b1010,0b0,0b1111RETLW row_click ENDM IRP row_wait,0b1111,0b101,0b1111,0b10100,0b0RETLW row_wait ENDM IRP row_press,0b1111,0b1111,0xff,0b1010,0b1111RETLW row_press ENDM IRP row_init,0b1111,0b1111,0xff,0b0,0b0RETLW row_init ENDM IRP row_double,0b1111,0b1111,0xff,0b10100,0b1111RETLW row_double ENDMseq_table:ADDWF PCL,f IRP seq_num,0b00111111,0b00000110,0b01011011,0b01001111,0b01100110,0b01101101,0b01111101,0b00000111,0b01111111,0b01101111,0b01110111RETLW seq_num ENDMcode_table:MOVWF PCL IRP code_num,0b00000111,0b00001011,0b00001101,0b00001110RETLW code_num ENDMkey_table: ADDWF PCL,F IRP key_num,5,1,2,3,4,6RETLW key_num ENDM;INTERRUPT SERVICEpsect intentry intentry:;clear the signal bitBANKSEL PIR0BCF PIR0,5;init the TMR0 offsetBANKSEL TMR0L;MOCLW 0xfec0cMOVLW 0xecMOVWF TMR0HMOVLW 0x78MOVWF TMR0Lconnection_check:CLRF cur_keyBANKSEL iMOVLW 1MOVWF iCLRF indexBANKSEL TRISBMOVLW 0x0fMOVWF TRISBBANKSEL WPUBMOVLW 0x0fMOVWF WPUB jedge_i_16:BANKSEL iBTFSS i,4GOTO i_unequ_16GOTO i_equ_16i_unequ_16:BANKSEL iMOVF i, WBANKSEL PORTBANDWF PORTB, WBANKSEL workplace2MOVWF workplace2MOVF workplace2,fBTFSS STATUS,2 GOTO branch1_portb_unequ_0GOTO branch1_portb_equ_0i_equ_16:MOVF cur_key, fBTFSS STATUS,2GOTO trunk_curkey_unequ_0GOTO trunk_curkey_equ_0branch1_portb_equ_0:MOVF cur_key,fBTFSS STATUS,2GOTO branch1_curkey_unequ_0GOTO branch1_curkey_equ_0branch1_portb_unequ_0:BANKSEL iLSLF i, fINCF index,fGOTO jedge_i_16branch1_curkey_unequ_0:MOVLW 255MOVWF cur_keyGOTO trunk_curkey_unequ_0branch1_curkey_equ_0:MOVLW 7ADDWF index, WMOVWF cur_keyGOTO branch1_portb_unequ_0trunk_curkey_unequ_0:GOTO debouncetrunk_curkey_equ_0:BANKSEL iMOVLW 1MOVWF iMOVLW 2MOVWF jCLRF index jedge_i_8:BTFSS i, 3GOTO i_unequ_8GOTO i_equ_8i_unequ_8:MOVF j, wBTFSS j, 4GOTO j_unequ_16GOTO j_equ_16i_equ_8:GOTO trunk_curkey_unequ_0j_unequ_16:BANKSEL jCOMF j, WBANKSEL TRISBMOVWF TRISBBANKSEL WPUBMOVWF WPUBBANKSEL PORTBMOVWF PORTBBANKSEL iMOVF i, WBANKSEL PORTBANDWF PORTB, WBANKSEL workplace2MOVWF workplace2MOVF workplace2,FBTFSS STATUS,2 GOTO branch2_portb_unequ_0GOTO branch2_portb_equ_0j_equ_16:BANKSEL iLSLF i, fLSLF i, WMOVWF jGOTO jedge_i_8branch2_portb_equ_0:MOVF cur_key,F BTFSS STATUS,2 GOTO branch2_curkey_unequ_0GOTO branch2_curkey_equ_0branch2_portb_unequ_0:LSLF j, fINCF index, fGOTO i_unequ_8branch2_curkey_equ_0:;cur_key = key_table[index]MOVLW HIGH(key_table)MOVWF PCLATH MOVF index,WCALL key_tableMOVWF cur_keyGOTO j_equ_16branch2_curkey_unequ_0:MOVLW 255MOVWF cur_keyGOTO i_equ_8debounce:MOVF last_result, WXORWF cur_key, WBTFSC STATUS, 2GOTO deb_continue ;no shakeINCF count ;shakeMOVLW 2XORWF count, WBTFSS STATUS, 2GOTO deb_ignore ;not equMOVF cur_key, W;equMOVWF last_resultGOTO deb_continuedeb_ignore:MOVF last_result, WMOVWF cur_keyGOTO transferdeb_continue:CLRF countGOTO transfertransfer: ;key valueMULTI EQU 0xFFNOKEY EQU 0 ;action indexMULTIKEY EQU 0UP EQU 1TIMEOUT EQU 2SAME EQU 3OTHER EQU 4 ;state valueCLICK EQU 0WAIT EQU 5PRESS EQU 10INIT EQU 15DOUBLE EQU 20 ;constUPCOUNT EQU 60PRESSCOUNT EQU 100PRESSADD EQU 100 trans_judge_action:MOVLW MULTIXORWF cur_key, wBTFSC STATUS, 2GOTO action_multi ;multiMOVLW NOKEY ;continueXORWF cur_key, wBTFSC STATUS, 2GOTO action_up_timeout ;upMOVF last_key, w ;downXORWF cur_key, wBTFSC STATUS, 2GOTO action_same_timeout ;sameGOTO action_other ;other ; action_multi:MOVLW MULTIKEYGOTO do_transfer action_up_timeout:MOVLW WAITXORWF state, wBTFSS STATUS, 2GOTO action_up ;not waitINCF wait_count ;waitingMOVLW UPCOUNTXORWF wait_count, wBTFSS STATUS, 2GOTO action_upGOTO action_timeoutaction_up:MOVLW UPGOTO do_transfer action_same_timeout:MOVLW CLICKXORWF state, wBTFSS STATUS, 2GOTO action_sameINCF click_countMOVLW PRESSCOUNTXORWF click_count, wBTFSS STATUS, 2GOTO action_sameGOTO action_timeout action_same:MOVLW SAMEGOTO do_transfer action_timeout:MOVLW TIMEOUTGOTO do_transfer action_other:MOVLW OTHERGOTO do_transferdo_transfer:MOVWF actionCLRF eventMOVF state, waddlw 1ADDWF action, fMOVLW INIT+1SUBWF action, wBTFSC STATUS, 0GOTO change_state ;no carry -> state+action+1>=INIT+1movlp high(event_table)MOVLW low(event_table)ADDWF action, wBTFSC STATUS, 0INCF PCLATHCALL event_table ;get next stateMOVWF event change_state:movlp high(action_table)MOVLW low(action_table)ADDWF action, wBTFSC STATUS, 0INCF PCLATHCALL action_table ;get next stateMOVWF stateclear_count_judge:MOVF event, fBTFSC STATUS, 2GOTO transfer_final ;event == 0clear_count:CLRF wait_countCLRF click_counttransfer_final:banksel swapMOVF last_key, wMOVWF swapMOVWF cur_key, wBTFSS STATUS, 2MOVWF last_keyMOVF swap, wMOVWF cur_keydisplay:MOVF event, fBTFSC STATUS, 2RETFIEbanksel dis_last_keyMOVF dis_last_key, WXORWF cur_key, WBTFSC STATUS, 2GOTO display_judge_event display_change:banksel dis_countCLRF dis_countCLRF dis_count+1MOVF cur_key, Wbanksel dis_last_keyMOVWF dis_last_key display_judge_event:banksel dis_countMOVLW 3SUBWF event, WBTFSS STATUS, 0GOTO event_1_2 ;if carry -> event<3MOVLW 3XORWF event, WBTFSC STATUS, 2GOTO event_3GOTO display_finalevent_1_2:MOVF event,WADDWF dis_count, FGOTO display_final event_3:INCF press_countMOVLW PRESSADDXORWF press_count, WBTFSC STATUS, 2GOTO event_3_add_countGOTO display_finalevent_3_add_count:INCF dis_countCLRF press_countdisplay_final:MOVF cur_key, WMOVWF dis_cacheMOVF event,WMOVWF dis_cache+1MOVLW 10SUBWF dis_count, WBTFSS STATUS, 0GOTO display_count ;if carry display_count_carry:INCF dis_count+1MOVLW 10SUBWF dis_count, FSUBWF dis_count+1, WBTFSC STATUS, 0CLRF dis_count+1 ;if no carry display_count:MOVF dis_count, WMOVWF dis_cache+3MOVF dis_count+1, WMOVWF dis_cache+2RETFIE;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 TRISABANKSEL LATB ;Data Latch CLRF LATB BANKSEL ANSELB CLRF ANSELB ;digital I/OBANKSEL 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 PORTCGOTO LOOPend reset_vec總結
以上是生活随笔為你收集整理的PIC单片机 按键检测识别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于socket的线上聊天框
- 下一篇: PIC单片机 电容式触摸检测