欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

PIC单片机 按键检测识别

发布时间:2025/4/5 编程问答 57 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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一起传入给后面的显示驱动模块。“输入——状态改变——输出”的运行逻辑正是一个状态机。

    state\actionMULTIKEYUPTIMEOUTSAMEOTHER
    CLICKinit(single)waitpress(press)clickinit(single)
    WAITinit(single)waitinit(single)double(double)click(single)
    PRESSinit(press_up)init(press_up)-same(press)init(press_up)
    INITinitinit-clickclick
    DOUBLEinitinit-doubleinit

    代码流程图:

     

    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单片机 按键检测识别的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。