亚洲春色中文字幕久久久-三上亚,91精品国产亚一区二区三区,久久久九色综合亚洲成色777,涩涩视频下载,国产午夜亚洲精品午夜鲁丝片,国产精品A一区二区三区腾讯导航,影音先锋色情AV在线看片,蜜臀国产在线视频,极品少妇高潮啪啪无码吴梦梦 ,精品人妻无码一区二区三区手机版
標題:
單片機通用的復雜按鍵狀態機,可實現單擊后長按,雙擊后長按及更多功能
[打印本頁]
作者:
千早愛音愛玩51
時間:
2026-2-5 02:02
標題:
單片機通用的復雜按鍵狀態機,可實現單擊后長按,雙擊后長按及更多功能
下面的代碼實現了多種按鍵輸入處理,基于switch狀態機實現,可實現單擊雙擊三擊長按,單擊后長按,雙擊后長按。
多平臺可用,只需要修改KEYINPUT即可。
如果是51單片機,改為#define KEYINPUT P32
如果是32單片機,改為#define KEYINPUT GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)
使用方法:可以在定時器中斷中直接調用KEY_HANDLER函數,也可以在定時器中斷設允許標志,主循環執行KEY_HANDLER
KEY_HANDLER函數中的不同case,我現在填入的是測試用的串口打印函數,可以直接改為你需要的功能代碼。
本函數無法連續返回同一個按鍵狀態,比如在三次定時器中斷中狀態先后變化為NOKEY→LONGKEY→NOKEY,所有的按鍵裝填,只能返回一次!
如果需要持續長按來修改某個變量值的效果,推薦在KEY_HANDLER函數中僅設允許位,比如這樣
:
case
SINGLETOLONGKEY
:
//單擊后長按
decreaseduty
=
1
;
//減少占空比標志
break
;
然后在主循環中執行下面的,即按鍵抬起后,清零標志
if
(
KEYINPUT
){
//P32 == 1,按鍵抬起
increaseduty
=
0
;
//清空占空比調節標志
decreaseduty
=
0
;
}
下面為全部代碼:
#define KEYINPUT 15//按鍵輸入為P32
#define NOKEY 0//無
#define SINGLEKEY 1//單鍵
#define DOUBLEKEY 2//雙鍵
#define TRIPLEKEY 3//三鍵
#define LONGKEY 4//長鍵
#define SINGLETOLONGKEY 5//單擊后長按鍵
#define DOUBLETOLONGKEY 6//雙擊后長按鍵
#define KEYSTATE0 0
#define KEYSTATE1 1
#define KEYSTATE2 2
#define KEYSTATE3 3
unsigned char KEY_DRIVER(void){
static unsigned char keystate = KEYSTATE0;
static unsigned char keytime = 0;
bool keypress;
unsigned char keyreturn = NOKEY;
keypress = digitalRead(Button);//讀取P32電平
switch(keystate){
case KEYSTATE0://按鍵初始狀態,按下后轉換到消抖與確認態,用定時器中斷間隔實現消抖
if(!keypress){//P32==0
keystate = KEYSTATE1;//如果無按鍵按下就始終返回為NOKEY
}
break;
case KEYSTATE1:
if(!keypress){//P32==0
keytime = 0;
keystate = KEYSTATE2;}//按鍵仍然處于按下,消抖完成,狀態轉換到計時
else{
keystate = KEYSTATE0;//低電平持續時間過小,不足一個定時器間隔
} //認為是無效按鍵,清零狀態,實現消抖
break;
case KEYSTATE2:
if(keypress){//P32==1,按鍵釋放,且間隔2個定時器中斷以上,認為是無抖動的有效按鍵輸入。
keyreturn = SINGLEKEY;//返回單擊
keystate = KEYSTATE0;//清空狀態
}//重要修改!更改長按時間由1280ms到400ms!
else if(++keytime >= 20){//P32=0,持續按下,計時加一個定時器中斷間隔時間
keyreturn = LONGKEY;//在下次定時器中斷直接輸出為長按,不需要等待
keystate = KEYSTATE3;//進入狀態3,等待按鍵釋放
}
break;
case KEYSTATE3://等待按鍵釋放,釋放后清空狀態
if(keypress){//P32==1,按鍵已經抬起
keystate = KEYSTATE0;//清空狀態
}
break;
}
return keyreturn;
}
unsigned char KEY_READ(void){
static unsigned char key1 = KEYSTATE0;
static unsigned char keytime1 = 0;//多次按鍵計數器
unsigned char keyreturn = NOKEY;
//對于單擊后長按,雙擊后長按,單獨設靜態變量防止狀態丟失
unsigned char keytemp = KEY_DRIVER();//讀取按鍵狀態
switch(key1){
case KEYSTATE0:
if(keytemp == SINGLEKEY){
keytime1 = 0;//第一次單擊,無返回值,到下個狀態判斷之后是否有再次單擊
key1 = KEYSTATE1;//切換至下一狀態
}
else{
keyreturn = keytemp;//對于無鍵,或首先為長按的事件返回原事件
}
break;
case KEYSTATE1:
if(keytemp == LONGKEY){//在這里檢測單擊后長按
keyreturn = SINGLETOLONGKEY;//狀態保存到multikeyreturn中
key1 = KEYSTATE0;//切換到狀態3,等待按鍵抬起
}
else if(keytemp == SINGLEKEY){//再次檢測到單擊,進入state2
key1 = KEYSTATE2;}
else{
if(++keytime1 >= 40){//在這里實現等待雙擊
keyreturn = SINGLEKEY;//如果超時,返回單擊
key1 = KEYSTATE0;//清空狀態
}//等待時間800ms?無所謂,不需要對雙擊做反應
}//三擊是直接輸出,無需等待
break;
case KEYSTATE2:
if(keytemp == SINGLEKEY){//第三次單擊,總間隔小于640ms,沿用state1中的計數器
keyreturn = TRIPLEKEY;//輸出為三擊
key1 = KEYSTATE0;//返回初始狀態
}
else if(keytemp == LONGKEY){//檢測到長按
keyreturn = DOUBLETOLONGKEY;
key1 = KEYSTATE0;//切換到狀態0
}
else{
if(++keytime1 >= 48){//沿用之前的計數器值,繼續計數
keyreturn = DOUBLEKEY;//超時,沒有檢測到第三次單擊,輸出雙擊
key1 = KEYSTATE0;
}
}
break;
}
return keyreturn;
}
unsigned char keyevent = NOKEY;//初始化為0
void KEY_HANDLER(void){//按鍵處理
keyevent = KEY_READ();//調用按鍵讀取函數
switch(keyevent){
case NOKEY:
break;
case SINGLEKEY:
Serial.println("SINGLEKEY");
break;
case LONGKEY://長按按鍵,增加占空比
Serial.println("LONGKEY");
break;
case SINGLETOLONGKEY://單擊后長按
Serial.println("SINGLETOLONGKEY");
break;
case DOUBLEKEY://雙擊,快速退出閃爍模式
Serial.println("DOUBLEKEY");
break;
case DOUBLETOLONGKEY:
Serial.println("DOUBLETOLONGKEY");
break;
case TRIPLEKEY://三擊
Serial.println("TRIPLEKEY");
break;
}
}
復制代碼
作者:
wallywl
時間:
2026-2-8 15:30
如下,以輪詢的方式,實現單個按鍵的長按和短按檢測。其中,HAL_GetTicks 為系統systick計時。
void set_button_task(void *param){
uint8_t rv = 0;
uint32_t ticks_elapsed = 0;
uint32_t ticks_now = 0;
while(true){
osDelay(80);
rv = set_button_press_confirm();
if (!rv && !button_press_time_start){ // low pressed down
button_press_time_start = HAL_GetTick();
ticks_elapsed = 0;
local_printf("button press down\r\n");
}
if (rv && button_press_time_start){ //high press up
ticks_now = HAL_GetTick();
if (ticks_now >= button_press_time_start){
ticks_elapsed = ticks_now - button_press_time_start;
} else {
ticks_elapsed = MAX_WORD_VALUE - button_press_time_start + ticks_now;
}
button_press_time_start = 0;
if (ticks_elapsed > 1400) {
button_double_click();
local_printf("button double\r\n");
} else if (ticks_elapsed > 120) {
button_single_click();
local_printf("button single\r\n");
}
}
}
}
復制代碼
歡迎光臨 (http://www.denmoz.com/bbs/)
Powered by Discuz! X3.1