單片機程序 | 如何用一個按鍵實現(xiàn)單擊\雙擊\長按?

本文提供了一個按鍵實現(xiàn)【單擊\雙擊\長按】的單片機demo程序。

芯片采用新唐的N76E003,但理論上可以改成其它MCU。


←左右滑動,查看全部代碼→

#include "N76E003.h"#include "Common.h"#include "Delay.h"#include "SFR_Macro.h"#include "Function_define.h"
#define TIMER1_INIT (6663 * 2)
UINT8  u8TH1_Tmp, u8TL1_Tmp;UINT8  time_10ms_ok;
unsigned char  key;
#define IO_KEY_INPUT  P10     //按鍵輸入口#define IO_BEEP    P30
#define N_key    0       //無鍵#define S_key    1       //單鍵#define D_key    2       //雙鍵#define L_key    3       //長鍵
#define key_state_0  0#define key_state_1  1#define key_state_2  2#define key_state_3  3
unsigned char key_driver( void ){  static unsigned char  key_state = key_state_0, key_time = 0;  unsigned char    key_press, key_return = N_key;
  key_press = IO_KEY_INPUT;    //讀按鍵I/O電平  switch ( key_state )  {  case key_state_0:    //按鍵初始態(tài)    if ( !key_press )      key_state = key_state_1;      //鍵被按下,狀態(tài)轉(zhuǎn)換到按鍵消抖和確認狀態(tài)    break;
  case key_state_1:  //按鍵消抖與確認態(tài)    if ( !key_press )    {      key_time  = 0;      key_state  = key_state_2;      //按鍵仍然處于按下,消抖完成,狀態(tài)轉(zhuǎn)換到按下鍵時間的計時狀態(tài),但返回的還是無鍵事件    }else      key_state = key_state_0;      //按鍵已抬起,轉(zhuǎn)換到按鍵初始態(tài)。此處完成和實現(xiàn)軟件消抖,其實按鍵的按下和釋放都在此消抖的。    break;
 case key_state_2:    if ( key_press )    {      key_return  = S_key;      //此時按鍵釋放,說明是產(chǎn)生一次短操作,回送S_key      key_state  = key_state_0;      //轉(zhuǎn)換到按鍵初始態(tài)    }else if ( ++key_time >= 100 )    //繼續(xù)按下,計時加10ms(10ms為本函數(shù)循環(huán)執(zhí)行間隔)    {      key_return  = L_key;      //按下時間>1000ms,此按鍵為長按操作,返回長鍵事件      key_state  = key_state_3;  //轉(zhuǎn)換到等待按鍵釋放狀態(tài)    }    break;
  case key_state_3:   //等待按鍵釋放狀態(tài),此狀態(tài)只返回無按鍵事件    if ( key_press )      key_state = key_state_0;   //按鍵已釋放,轉(zhuǎn)換到按鍵初始態(tài)    break;  }  return(key_return);}/*============= * 中間層按鍵處理函數(shù),調(diào)用低層函數(shù)一次,處理雙擊事件的判斷,返回上層正確的無鍵、單鍵、雙鍵、長鍵4個按鍵事件。 * 本函數(shù)由上層循環(huán)調(diào)用,間隔10ms * ===============*/
unsigned char key_read( void ){  static unsigned char  key_m = key_state_0, key_time_1 = 0;  unsigned char    key_return = N_key, key_temp;
 key_temp = key_driver();
 switch ( key_m )  {  case key_state_0:    if ( key_temp == S_key )    {      key_time_1  = 0;      //第1次單擊,不返回,到下個狀態(tài)判斷后面是否出現(xiàn)雙擊      key_m = key_state_1;    }else      key_return = key_temp;   //對于無鍵、長鍵,返回原事件    break;
 case key_state_1:    if ( key_temp == S_key )   //又一次單擊(間隔肯定<500ms)    {      key_return = D_key;   //返回雙擊鍵事件,回初始狀態(tài)      key_m = key_state_0;    }else  {    //這里500ms內(nèi)肯定讀到的都是無鍵事件,因為長鍵>1000ms,在1s前低層返回的都是無鍵      if ( ++key_time_1 >= 50 )      {        key_return = S_key;        //500ms內(nèi)沒有再次出現(xiàn)單鍵事件,返回上一次的單鍵事件        key_m = key_state_0;  //返回初始狀態(tài)      }    }    break;  }  return(key_return);}
/* * 下面,根據(jù)程序分析按鍵事件的反映時間: * 1、對于長鍵,按下超過1s馬上響應,反映最快 * 2、對于雙鍵,第2次按鍵釋放后馬上得到反映。 * 3、對于單鍵,釋放后延時拖后500ms才能響應,反映最慢。這個與需要判斷后面是否有雙擊操作有關,只能這樣。實際應用中,可以調(diào)整兩次單擊間隔時間定義,比如為300ms,這樣單擊的響應回快一點,單按鍵操作人員需要加快按鍵的操作過程。如果產(chǎn)品是針對老年人的,這個時間不易太短,因為年紀大的人,反映和動作都比較慢。 * 當然,上面兩段可以合在一起。這樣做的目的,是為了可以方便的擴展為N擊(當然,需要做修改)。可是最底層的就是最基本的操作處理短按和長按,不用改動的。至于雙擊,還是N擊,在中間層處理。這就是程序設計中分層結構的優(yōu)點。 * 測試代碼環(huán)境如下: */
void Timer1_ISRvoid ) interrupt 3     //timer1定時器10ms中斷服務{  TH1 = u8TH1_Tmp;  TL1 = u8TL1_Tmp;
  P06 = ~P06;         //P0.3 toggle when interrupt  time_10ms_ok  = 1;}
main( void ){  Set_All_GPIO_Quasi_Mode;  TIMER1_MODE1_ENABLE;  //定時器1, 模式1, 16bit定時器, 定時器值滿 0xFFFF -> 0x0000 產(chǎn)生中斷。  clr_T1M;  //T1M = 0,兼容傳統(tǒng) 8051,TIMER1時鐘 = Fsys/12 = 16M /12  //set_T1M;  //T1M = 1,TIMER1時鐘 = Fsys = 16M
 u8TH1_Tmp  = (65536 - TIMER1_INIT) / 256;  u8TL1_Tmp  = (65536 - TIMER1_INIT) % 256;
  TH1 = u8TH1_Tmp;  TL1 = u8TL1_Tmp;
  set_ET1;              //enable Timer1 interrupt  set_EA;               //enable interrupts  set_TR1;             //Timer1 run
 while ( 1 )  {    if ( time_10ms_ok )    //每10ms執(zhí)行一次    {      time_10ms_ok  = 0;      key    = key_read();      //10ms一次調(diào)用按鍵中間層函數(shù),根據(jù)返回鍵值,點亮不同的LED燈,全面測試按鍵操作是否正常
      if ( key == S_key )      //短按      {        IO_BEEP = 0;        Timer0_Delay1ms( 10 );        IO_BEEP = 1;      }
      else if ( key == D_key )       //雙擊      {        IO_BEEP = 0;        Timer0_Delay1ms( 50 );        IO_BEEP = 1;      }
      else if ( key == L_key )       //長按      {        IO_BEEP = 0;        Timer0_Delay1ms( 150 );        IO_BEEP = 1;      }    }  }}

*本文系網(wǎng)絡轉(zhuǎn)載,版權歸原作者所有,如有侵權請聯(lián)系刪除


登錄后免費查看全文
立即登錄
App下載
技術鄰APP
工程師必備
  • 項目客服
  • 培訓客服
  • 平臺客服

TOP

1