亚洲春色中文字幕久久久-三上亚,一吻二脱三床四吻胸,国产真实伦对白视频全集,在线毛片观看,精品成品入口黄网,国产毛aⅴ片久久久,亚洲AV色香蕉一区二区三区老师,萧皇后A级艳片,色情日本视频更新,99久久亚洲精品日本无码

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 895|回復: 1
收起左側

單片機通用的復雜按鍵狀態機,可實現單擊后長按,雙擊后長按及更多功能

[復制鏈接]
ID:1155837 發表于 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;
        }

下面為全部代碼:
  1. #define KEYINPUT 15//按鍵輸入為P32
  2. #define NOKEY 0//無
  3. #define SINGLEKEY 1//單鍵
  4. #define DOUBLEKEY 2//雙鍵
  5. #define TRIPLEKEY 3//三鍵
  6. #define LONGKEY 4//長鍵
  7. #define SINGLETOLONGKEY 5//單擊后長按鍵
  8. #define DOUBLETOLONGKEY 6//雙擊后長按鍵
  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://按鍵初始狀態,按下后轉換到消抖與確認態,用定時器中斷間隔實現消抖
  21.             if(!keypress){//P32==0
  22.                 keystate = KEYSTATE1;//如果無按鍵按下就始終返回為NOKEY
  23.             }
  24.             break;
  25.         case KEYSTATE1:
  26.             if(!keypress){//P32==0
  27.                 keytime = 0;
  28.                 keystate = KEYSTATE2;}//按鍵仍然處于按下,消抖完成,狀態轉換到計時
  29.             else{
  30.                 keystate = KEYSTATE0;//低電平持續時間過小,不足一個定時器間隔
  31.             }                        //認為是無效按鍵,清零狀態,實現消抖
  32.             break;
  33.         case KEYSTATE2:
  34.             if(keypress){//P32==1,按鍵釋放,且間隔2個定時器中斷以上,認為是無抖動的有效按鍵輸入。
  35.                 keyreturn = SINGLEKEY;//返回單擊
  36.                 keystate = KEYSTATE0;//清空狀態
  37.             }//重要修改!更改長按時間由1280ms到400ms!
  38.             else if(++keytime >= 20){//P32=0,持續按下,計時加一個定時器中斷間隔時間
  39.                 keyreturn = LONGKEY;//在下次定時器中斷直接輸出為長按,不需要等待
  40.                 keystate = KEYSTATE3;//進入狀態3,等待按鍵釋放
  41.             }
  42.             break;
  43.         case KEYSTATE3://等待按鍵釋放,釋放后清空狀態
  44.             if(keypress){//P32==1,按鍵已經抬起
  45.                 keystate = KEYSTATE0;//清空狀態
  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;//多次按鍵計數器
  54.     unsigned char keyreturn = NOKEY;
  55.     //對于單擊后長按,雙擊后長按,單獨設靜態變量防止狀態丟失
  56.     unsigned char keytemp = KEY_DRIVER();//讀取按鍵狀態
  57.     switch(key1){
  58.         case KEYSTATE0:
  59.             if(keytemp == SINGLEKEY){
  60.                 keytime1 = 0;//第一次單擊,無返回值,到下個狀態判斷之后是否有再次單擊
  61.                 key1 = KEYSTATE1;//切換至下一狀態
  62.             }
  63.             else{
  64.                 keyreturn = keytemp;//對于無鍵,或首先為長按的事件返回原事件
  65.             }
  66.             break;
  67.         case KEYSTATE1:
  68.             if(keytemp == LONGKEY){//在這里檢測單擊后長按
  69.                 keyreturn = SINGLETOLONGKEY;//狀態保存到multikeyreturn中
  70.                 key1 = KEYSTATE0;//切換到狀態3,等待按鍵抬起
  71.             }
  72.             else if(keytemp == SINGLEKEY){//再次檢測到單擊,進入state2
  73.                 key1 = KEYSTATE2;}
  74.             else{
  75.                 if(++keytime1 >= 40){//在這里實現等待雙擊
  76.                     keyreturn = SINGLEKEY;//如果超時,返回單擊
  77.                     key1 = KEYSTATE0;//清空狀態
  78.                 }//等待時間800ms?無所謂,不需要對雙擊做反應
  79.             }//三擊是直接輸出,無需等待
  80.             break;
  81.         case KEYSTATE2:
  82.             if(keytemp == SINGLEKEY){//第三次單擊,總間隔小于640ms,沿用state1中的計數器
  83.                 keyreturn = TRIPLEKEY;//輸出為三擊
  84.                 key1 = KEYSTATE0;//返回初始狀態
  85.             }
  86.             else if(keytemp == LONGKEY){//檢測到長按
  87.                 keyreturn = DOUBLETOLONGKEY;
  88.                 key1 = KEYSTATE0;//切換到狀態0
  89.             }
  90.             else{
  91.                 if(++keytime1 >= 48){//沿用之前的計數器值,繼續計數
  92.                     keyreturn = DOUBLEKEY;//超時,沒有檢測到第三次單擊,輸出雙擊
  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();//調用按鍵讀取函數
  103.         switch(keyevent){
  104.             case NOKEY:
  105.                 break;
  106.             case SINGLEKEY:
  107.             Serial.println("SINGLEKEY");
  108.                 break;
  109.             case LONGKEY://長按按鍵,增加占空比
  110.                 Serial.println("LONGKEY");
  111.                 break;
  112.             case SINGLETOLONGKEY://單擊后長按
  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.         }
復制代碼

評分

參與人數 1黑幣 +10 收起 理由
wpppmlah + 10 共享資料的獎勵!

查看全部評分

回復

使用道具 舉報

ID:1167348 發表于 2026-2-8 15:30 | 顯示全部樓層

    如下,以輪詢的方式,實現單個按鍵的長按和短按檢測。其中,HAL_GetTicks 為系統systick計時。


  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. }
復制代碼
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表