單片機(jī)程序:如何用一個(gè)按鍵實(shí)現(xiàn)單擊\\\\雙擊\\\\長(zhǎng)按?
時(shí)間:2021-09-06 15:20:10
手機(jī)看文章
掃描二維碼
隨時(shí)隨地手機(jī)看文章
[導(dǎo)讀]本文提供了一個(gè)按鍵實(shí)現(xiàn)【單擊\雙擊\長(zhǎng)按】的單片機(jī)demo程序。芯片采用新唐的N76E003,但理論上可以改成其它MCU?!笥一瑒?dòng),查看全部代碼→#include"N76E003.h"#include"Common.h"#include"Delay.h"#include"SFR...
本文提供了一個(gè)按鍵實(shí)現(xiàn)【單擊\雙擊\長(zhǎng)按】的單片機(jī)demo程序。
芯片采用新唐的N76E003,但理論上可以改成其它MCU。
←左右滑動(dòng),查看全部代碼→
#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???????//無(wú)鍵
#define?S_key????1???????//單鍵
#define?D_key????2???????//雙鍵
#define?L_key????3???????//長(zhǎng)鍵
#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)換到按鍵消抖和確認(rèn)狀態(tài)
????break;
??case?key_state_1:??//按鍵消抖與確認(rèn)態(tài)
if ( !key_press )
{
key_time = 0;
??????key_state??=?key_state_2;
??????//按鍵仍然處于按下,消抖完成,狀態(tài)轉(zhuǎn)換到按下鍵時(shí)間的計(jì)時(shí)狀態(tài),但返回的還是無(wú)鍵事件
}else
??????key_state?=?key_state_0;
??????//按鍵已抬起,轉(zhuǎn)換到按鍵初始態(tài)。此處完成和實(shí)現(xiàn)軟件消抖,其實(shí)按鍵的按下和釋放都在此消抖的。
????break;
case key_state_2:
if ( key_press )
{
??????key_return??=?S_key;
??????//此時(shí)按鍵釋放,說(shuō)明是產(chǎn)生一次短操作,回送S_key
??????key_state??=?key_state_0;
??????//轉(zhuǎn)換到按鍵初始態(tài)
????}else?if?(? key_time?>=?100?)
????//繼續(xù)按下,計(jì)時(shí)加10ms(10ms為本函數(shù)循環(huán)執(zhí)行間隔)
{
??????key_return??=?L_key;
??????//按下時(shí)間>1000ms,此按鍵為長(zhǎng)按操作,返回長(zhǎng)鍵事件
??????key_state??=?key_state_3;??//轉(zhuǎn)換到等待按鍵釋放狀態(tài)
}
break;
??case?key_state_3:???//等待按鍵釋放狀態(tài),此狀態(tài)只返回?zé)o按鍵事件
if ( key_press )
??????key_state?=?key_state_0;???//按鍵已釋放,轉(zhuǎn)換到按鍵初始態(tài)
break;
}
return(key_return);
}
/*=============
* 中間層按鍵處理函數(shù),調(diào)用低層函數(shù)一次,處理雙擊事件的判斷,返回上層正確的無(wú)鍵、單鍵、雙鍵、長(zhǎng)鍵4個(gè)按鍵事件。
* 本函數(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次單擊,不返回,到下個(gè)狀態(tài)判斷后面是否出現(xiàn)雙擊
??????key_m?=?key_state_1;
}else
??????key_return?=?key_temp;???//對(duì)于無(wú)鍵、長(zhǎng)鍵,返回原事件
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)肯定讀到的都是無(wú)鍵事件,因?yàn)殚L(zhǎng)鍵>1000ms,在1s前低層返回的都是無(wú)鍵
if ( key_time_1 >= 50 )
{
????????key_return?=?S_key;
????????//500ms內(nèi)沒(méi)有再次出現(xiàn)單鍵事件,返回上一次的單鍵事件
????????key_m?=?key_state_0;??//返回初始狀態(tài)
}
}
break;
}
return(key_return);
}
/*
* 下面,根據(jù)程序分析按鍵事件的反映時(shí)間:
* 1、對(duì)于長(zhǎng)鍵,按下超過(guò)1s馬上響應(yīng),反映最快
?* 2、對(duì)于雙鍵,第2次按鍵釋放后馬上得到反映。
?* 3、對(duì)于單鍵,釋放后延時(shí)拖后500ms才能響應(yīng),反映最慢。這個(gè)與需要判斷后面是否有雙擊操作有關(guān),只能這樣。實(shí)際應(yīng)用中,可以調(diào)整兩次單擊間隔時(shí)間定義,比如為300ms,這樣單擊的響應(yīng)回快一點(diǎn),單按鍵操作人員需要加快按鍵的操作過(guò)程。如果產(chǎn)品是針對(duì)老年人的,這個(gè)時(shí)間不易太短,因?yàn)槟昙o(jì)大的人,反映和動(dòng)作都比較慢。
?*?當(dāng)然,上面兩段可以合在一起。這樣做的目的,是為了可以方便的擴(kuò)展為N擊(當(dāng)然,需要做修改)??墒亲畹讓拥木褪亲罨镜牟僮魈幚矶贪春烷L(zhǎng)按,不用改動(dòng)的。至于雙擊,還是N擊,在中間層處理。這就是程序設(shè)計(jì)中分層結(jié)構(gòu)的優(yōu)點(diǎn)。
* 測(cè)試代碼環(huán)境如下:
*/
void?Timer1_ISR(?void?)?interrupt?3?????//timer1定時(shí)器10ms中斷服務(wù)
{
??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;
??//定時(shí)器1,?模式1, 16bit定時(shí)器, 定時(shí)器值滿?0xFFFF ->?0x0000?產(chǎn)生中斷。
??clr_T1M;
??//T1M?=?0,兼容傳統(tǒng)?8051,TIMER1時(shí)鐘?=?Fsys/12?=?16M?/12
??//set_T1M;
??//T1M?=?1,TIMER1時(shí)鐘?=?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ù)返回鍵值,點(diǎn)亮不同的LED燈,全面測(cè)試按鍵操作是否正常
??????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?)???????//長(zhǎng)按
{
IO_BEEP = 0;
Timer0_Delay1ms( 150 );
IO_BEEP = 1;
}
}
}
}
END
來(lái)源:網(wǎng)絡(luò)版權(quán)歸原作者所有,如有侵權(quán),請(qǐng)聯(lián)系刪除。
▍