單片機程序:如何用一個按鍵實現單擊\\\\雙擊\\\\長按?
時間:2021-09-06 15:20:10
手機看文章
掃描二維碼
隨時隨地手機看文章
[導讀]本文提供了一個按鍵實現【單擊\雙擊\長按】的單片機demo程序。芯片采用新唐的N76E003,但理論上可以改成其它MCU?!笥一瑒樱榭慈看a→#include"N76E003.h"#include"Common.h"#include"Delay.h"#include"SFR...
本文提供了一個按鍵實現【單擊\雙擊\長按】的單片機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)轉換到按鍵消抖和確認狀態(tài)????break;
??case?key_state_1:??//按鍵消抖與確認態(tài) if ( !key_press ) { key_time = 0;??????key_state??=?key_state_2;??????//按鍵仍然處于按下,消抖完成,狀態(tài)轉換到按下鍵時間的計時狀態(tài),但返回的還是無鍵事件 }else??????key_state?=?key_state_0;??????//按鍵已抬起,轉換到按鍵初始態(tài)。此處完成和實現軟件消抖,其實按鍵的按下和釋放都在此消抖的。????break;
case key_state_2: if ( key_press ) {??????key_return??=?S_key;??????//此時按鍵釋放,說明是產生一次短操作,回送S_key??????key_state??=?key_state_0;??????//轉換到按鍵初始態(tài)????}else?if?(? key_time?>=?100?)????//繼續(xù)按下,計時加10ms(10ms為本函數循環(huán)執(zhí)行間隔) {??????key_return??=?L_key;??????//按下時間>1000ms,此按鍵為長按操作,返回長鍵事件??????key_state??=?key_state_3;??//轉換到等待按鍵釋放狀態(tài) } break;
??case?key_state_3:???//等待按鍵釋放狀態(tài),此狀態(tài)只返回無按鍵事件 if ( key_press )??????key_state?=?key_state_0;???//按鍵已釋放,轉換到按鍵初始態(tài) break; } return(key_return);}/*============= * 中間層按鍵處理函數,調用低層函數一次,處理雙擊事件的判斷,返回上層正確的無鍵、單鍵、雙鍵、長鍵4個按鍵事件。 * 本函數由上層循環(huán)調用,間隔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)判斷后面是否出現雙擊??????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內肯定讀到的都是無鍵事件,因為長鍵>1000ms,在1s前低層返回的都是無鍵 if ( key_time_1 >= 50 ) {????????key_return?=?S_key;????????//500ms內沒有再次出現單鍵事件,返回上一次的單鍵事件????????key_m?=?key_state_0;??//返回初始狀態(tài) } } break; } return(key_return);}
/* * 下面,根據程序分析按鍵事件的反映時間: * 1、對于長鍵,按下超過1s馬上響應,反映最快?* 2、對于雙鍵,第2次按鍵釋放后馬上得到反映。?* 3、對于單鍵,釋放后延時拖后500ms才能響應,反映最慢。這個與需要判斷后面是否有雙擊操作有關,只能這樣。實際應用中,可以調整兩次單擊間隔時間定義,比如為300ms,這樣單擊的響應回快一點,單按鍵操作人員需要加快按鍵的操作過程。如果產品是針對老年人的,這個時間不易太短,因為年紀大的人,反映和動作都比較慢。?*?當然,上面兩段可以合在一起。這樣做的目的,是為了可以方便的擴展為N擊(當然,需要做修改)??墒亲畹讓拥木褪亲罨镜牟僮魈幚矶贪春烷L按,不用改動的。至于雙擊,還是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?interrupt time_10ms_ok = 1;}
main( void ){ Set_All_GPIO_Quasi_Mode;??TIMER1_MODE1_ENABLE;??//定時器1,?模式1, 16bit定時器, 定時器值滿?0xFFFF ->?0x0000?產生中斷。??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一次調用按鍵中間層函數,根據返回鍵值,點亮不同的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; } } }}END
來源:網絡版權歸原作者所有,如有侵權,請聯系刪除。
▍






