單片機程序 | 如何用一個按鍵實現(xiàn)單擊\雙擊\長按?
瀏覽:3194 收藏:1
本文提供了一個按鍵實現(xiàn)【單擊\雙擊\長按】的單片機demo程序。
芯片采用新唐的N76E003,但理論上可以改成其它MCU。
←左右滑動,查看全部代碼→
UINT8 u8TH1_Tmp, u8TL1_Tmp;UINT8 time_10ms_ok;unsigned char key;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),但返回的還是無鍵事件}elsekey_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_keykey_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;}elsekey_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_ISR( void ) interrupt 3 //timer1定時器10ms中斷服務{TH1 = u8TH1_Tmp;TL1 = u8TL1_Tmp;P06 = ~P06; //P0.3 toggle when interrupttime_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 = 16Mu8TH1_Tmp = (65536 - TIMER1_INIT) / 256;u8TL1_Tmp = (65536 - TIMER1_INIT) % 256;TH1 = u8TH1_Tmp;TL1 = u8TL1_Tmp;set_ET1; //enable Timer1 interruptset_EA; //enable interruptsset_TR1; //Timer1 runwhile ( 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
工程師必備
工程師必備
- 項目客服
- 培訓客服
- 平臺客服
TOP
1




















