亚洲春色中文字幕久久久-三上亚,91精品国产亚一区二区三区,久久久九色综合亚洲成色777,涩涩视频下载,国产午夜亚洲精品午夜鲁丝片,国产精品A一区二区三区腾讯导航,影音先锋色情AV在线看片,蜜臀国产在线视频,极品少妇高潮啪啪无码吴梦梦 ,精品人妻无码一区二区三区手机版

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 1012|回復(fù): 1
打印 上一主題 下一主題
收起左側(cè)

單片機(jī)通用的復(fù)雜按鍵狀態(tài)機(jī),可實(shí)現(xiàn)單擊后長(zhǎng)按,雙擊后長(zhǎng)按及更多功能

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:1155837 發(fā)表于 2026-2-5 02:02 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
下面的代碼實(shí)現(xiàn)了多種按鍵輸入處理,基于switch狀態(tài)機(jī)實(shí)現(xiàn),可實(shí)現(xiàn)單擊雙擊三擊長(zhǎng)按,單擊后長(zhǎng)按,雙擊后長(zhǎng)按。
多平臺(tái)可用,只需要修改KEYINPUT即可。
如果是51單片機(jī),改為#define KEYINPUT P32
如果是32單片機(jī),改為#define KEYINPUT GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)
使用方法:可以在定時(shí)器中斷中直接調(diào)用KEY_HANDLER函數(shù),也可以在定時(shí)器中斷設(shè)允許標(biāo)志,主循環(huán)執(zhí)行KEY_HANDLER
KEY_HANDLER函數(shù)中的不同case,我現(xiàn)在填入的是測(cè)試用的串口打印函數(shù),可以直接改為你需要的功能代碼。

本函數(shù)無(wú)法連續(xù)返回同一個(gè)按鍵狀態(tài),比如在三次定時(shí)器中斷中狀態(tài)先后變化為NOKEY→LONGKEY→NOKEY,所有的按鍵裝填,只能返回一次!
如果需要持續(xù)長(zhǎng)按來(lái)修改某個(gè)變量值的效果,推薦在KEY_HANDLER函數(shù)中僅設(shè)允許位,比如這樣
            case SINGLETOLONGKEY://單擊后長(zhǎng)按
                decreaseduty = 1;//減少占空比標(biāo)志
                break;


然后在主循環(huán)中執(zhí)行下面的,即按鍵抬起后,清零標(biāo)志
        if(KEYINPUT){//P32 == 1,按鍵抬起
            increaseduty = 0;//清空占空比調(diào)節(jié)標(biāo)志
            decreaseduty = 0;
        }

下面為全部代碼:
  1. #define KEYINPUT 15//按鍵輸入為P32
  2. #define NOKEY 0//無(wú)
  3. #define SINGLEKEY 1//單鍵
  4. #define DOUBLEKEY 2//雙鍵
  5. #define TRIPLEKEY 3//三鍵
  6. #define LONGKEY 4//長(zhǎng)鍵
  7. #define SINGLETOLONGKEY 5//單擊后長(zhǎng)按鍵
  8. #define DOUBLETOLONGKEY 6//雙擊后長(zhǎng)按鍵
  9. #define KEYSTATE0 0
  10. #define KEYSTATE1 1
  11. #define KEYSTATE2 2
  12. #define KEYSTATE3 3
  13. unsigned char KEY_DRIVER(void){
  14.     static unsigned char keystate = KEYSTATE0;
  15.     static unsigned char keytime = 0;
  16.     bool keypress;
  17.     unsigned char keyreturn = NOKEY;
  18.     keypress = digitalRead(Button);//讀取P32電平
  19.     switch(keystate){
  20.         case KEYSTATE0://按鍵初始狀態(tài),按下后轉(zhuǎn)換到消抖與確認(rèn)態(tài),用定時(shí)器中斷間隔實(shí)現(xiàn)消抖
  21.             if(!keypress){//P32==0
  22.                 keystate = KEYSTATE1;//如果無(wú)按鍵按下就始終返回為NOKEY
  23.             }
  24.             break;
  25.         case KEYSTATE1:
  26.             if(!keypress){//P32==0
  27.                 keytime = 0;
  28.                 keystate = KEYSTATE2;}//按鍵仍然處于按下,消抖完成,狀態(tài)轉(zhuǎn)換到計(jì)時(shí)
  29.             else{
  30.                 keystate = KEYSTATE0;//低電平持續(xù)時(shí)間過(guò)小,不足一個(gè)定時(shí)器間隔
  31.             }                        //認(rèn)為是無(wú)效按鍵,清零狀態(tài),實(shí)現(xiàn)消抖
  32.             break;
  33.         case KEYSTATE2:
  34.             if(keypress){//P32==1,按鍵釋放,且間隔2個(gè)定時(shí)器中斷以上,認(rèn)為是無(wú)抖動(dòng)的有效按鍵輸入。
  35.                 keyreturn = SINGLEKEY;//返回單擊
  36.                 keystate = KEYSTATE0;//清空狀態(tài)
  37.             }//重要修改!更改長(zhǎng)按時(shí)間由1280ms到400ms!
  38.             else if(++keytime >= 20){//P32=0,持續(xù)按下,計(jì)時(shí)加一個(gè)定時(shí)器中斷間隔時(shí)間
  39.                 keyreturn = LONGKEY;//在下次定時(shí)器中斷直接輸出為長(zhǎng)按,不需要等待
  40.                 keystate = KEYSTATE3;//進(jìn)入狀態(tài)3,等待按鍵釋放
  41.             }
  42.             break;
  43.         case KEYSTATE3://等待按鍵釋放,釋放后清空狀態(tài)
  44.             if(keypress){//P32==1,按鍵已經(jīng)抬起
  45.                 keystate = KEYSTATE0;//清空狀態(tài)
  46.             }
  47.             break;
  48.         }
  49.             return keyreturn;
  50.     }
  51. unsigned char KEY_READ(void){
  52.     static unsigned char key1 = KEYSTATE0;
  53.     static unsigned char keytime1 = 0;//多次按鍵計(jì)數(shù)器
  54.     unsigned char keyreturn = NOKEY;
  55.     //對(duì)于單擊后長(zhǎng)按,雙擊后長(zhǎng)按,單獨(dú)設(shè)靜態(tài)變量防止?fàn)顟B(tài)丟失
  56.     unsigned char keytemp = KEY_DRIVER();//讀取按鍵狀態(tài)
  57.     switch(key1){
  58.         case KEYSTATE0:
  59.             if(keytemp == SINGLEKEY){
  60.                 keytime1 = 0;//第一次單擊,無(wú)返回值,到下個(gè)狀態(tài)判斷之后是否有再次單擊
  61.                 key1 = KEYSTATE1;//切換至下一狀態(tài)
  62.             }
  63.             else{
  64.                 keyreturn = keytemp;//對(duì)于無(wú)鍵,或首先為長(zhǎng)按的事件返回原事件
  65.             }
  66.             break;
  67.         case KEYSTATE1:
  68.             if(keytemp == LONGKEY){//在這里檢測(cè)單擊后長(zhǎng)按
  69.                 keyreturn = SINGLETOLONGKEY;//狀態(tài)保存到multikeyreturn中
  70.                 key1 = KEYSTATE0;//切換到狀態(tài)3,等待按鍵抬起
  71.             }
  72.             else if(keytemp == SINGLEKEY){//再次檢測(cè)到單擊,進(jìn)入state2
  73.                 key1 = KEYSTATE2;}
  74.             else{
  75.                 if(++keytime1 >= 40){//在這里實(shí)現(xiàn)等待雙擊
  76.                     keyreturn = SINGLEKEY;//如果超時(shí),返回單擊
  77.                     key1 = KEYSTATE0;//清空狀態(tài)
  78.                 }//等待時(shí)間800ms?無(wú)所謂,不需要對(duì)雙擊做反應(yīng)
  79.             }//三擊是直接輸出,無(wú)需等待
  80.             break;
  81.         case KEYSTATE2:
  82.             if(keytemp == SINGLEKEY){//第三次單擊,總間隔小于640ms,沿用state1中的計(jì)數(shù)器
  83.                 keyreturn = TRIPLEKEY;//輸出為三擊
  84.                 key1 = KEYSTATE0;//返回初始狀態(tài)
  85.             }
  86.             else if(keytemp == LONGKEY){//檢測(cè)到長(zhǎng)按
  87.                 keyreturn = DOUBLETOLONGKEY;
  88.                 key1 = KEYSTATE0;//切換到狀態(tài)0
  89.             }
  90.             else{
  91.                 if(++keytime1 >= 48){//沿用之前的計(jì)數(shù)器值,繼續(xù)計(jì)數(shù)
  92.                     keyreturn = DOUBLEKEY;//超時(shí),沒(méi)有檢測(cè)到第三次單擊,輸出雙擊
  93.                     key1 = KEYSTATE0;
  94.                 }
  95.             }
  96.             break;
  97.         }
  98.         return keyreturn;
  99.     }
  100. unsigned char keyevent = NOKEY;//初始化為0
  101. void KEY_HANDLER(void){//按鍵處理
  102.     keyevent = KEY_READ();//調(diào)用按鍵讀取函數(shù)
  103.         switch(keyevent){
  104.             case NOKEY:
  105.                 break;
  106.             case SINGLEKEY:
  107.             Serial.println("SINGLEKEY");
  108.                 break;
  109.             case LONGKEY://長(zhǎng)按按鍵,增加占空比
  110.                 Serial.println("LONGKEY");
  111.                 break;
  112.             case SINGLETOLONGKEY://單擊后長(zhǎng)按
  113.                 Serial.println("SINGLETOLONGKEY");
  114.                 break;
  115.             case DOUBLEKEY://雙擊,快速退出閃爍模式
  116.             Serial.println("DOUBLEKEY");
  117.                 break;
  118.             case DOUBLETOLONGKEY:
  119.             Serial.println("DOUBLETOLONGKEY");
  120.                 break;
  121.             case TRIPLEKEY://三擊
  122.                 Serial.println("TRIPLEKEY");
  123.                 break;
  124.             }
  125.         }
復(fù)制代碼

評(píng)分

參與人數(shù) 1黑幣 +10 收起 理由
wpppmlah + 10 共享資料的獎(jiǎng)勵(lì)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏8 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:1167348 發(fā)表于 2026-2-8 15:30 | 只看該作者

    如下,以輪詢的方式,實(shí)現(xiàn)單個(gè)按鍵的長(zhǎng)按和短按檢測(cè)。其中,HAL_GetTicks 為系統(tǒng)systick計(jì)時(shí)。


  1. void set_button_task(void *param){

  2.     uint8_t rv = 0;
  3.         
  4.     uint32_t ticks_elapsed = 0;
  5.     uint32_t ticks_now = 0;
  6.    
  7.     while(true){

  8.         osDelay(80);
  9.                
  10.         rv = set_button_press_confirm();
  11.         if (!rv && !button_press_time_start){       // low pressed down
  12.                      
  13.             button_press_time_start = HAL_GetTick();

  14.             ticks_elapsed = 0;

  15.             local_printf("button press down\r\n");

  16.         }


  17.         if (rv && button_press_time_start){                              //high  press up
  18.             ticks_now = HAL_GetTick();

  19.             if (ticks_now >= button_press_time_start){
  20.                
  21.                 ticks_elapsed = ticks_now - button_press_time_start;
  22.             } else {

  23.                 ticks_elapsed = MAX_WORD_VALUE - button_press_time_start + ticks_now;
  24.             }


  25.             button_press_time_start = 0;              


  26.             if (ticks_elapsed > 1400) {
  27.                            
  28.                 button_double_click();         

  29.                 local_printf("button double\r\n");

  30.             } else if (ticks_elapsed > 120) {
  31.                            
  32.                 button_single_click();

  33.                 local_printf("button single\r\n");
  34.             }                       
  35.         }

  36.     }

  37. }
復(fù)制代碼
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表