久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 12877|回復: 22
收起左側

基于狀態機的按鍵長按,短按,雙擊 單片機源程序

  [復制鏈接]
ID:573901 發表于 2019-8-23 14:41 | 顯示全部樓層 |閱讀模式
先前根據以為前輩的程序理解了一段時間,之后自己寫了一份控制led燈的簡單按鍵程序

單片機源程序如下:
  1. #include<stc15w202s.h>
  2. #include<stdio.h>
  3. #define key_state_0 0
  4. #define key_state_1 1
  5. #define key_state_2 2
  6. #define key_state_3 3
  7. #define key_no 0
  8. #define key_click 1
  9. #define key_double 2
  10. #define key_long 3
  11. sbit KEY = P3^3;
  12. sbit LED_E1P = P3^1;
  13. sbit LED_G1 = P3^2;
  14. sbit LED2 = P5^5;        //W2OUT
  15. sbit LED3 = P5^4;  
  16. unsigned char flag;
  17. unsigned char cnt = 0;


  18. static unsigned char key_driver(void)
  19. {
  20.         static unsigned char key_state_buffer1 = key_state_0;
  21.         static unsigned char key_timer_cnt1 = 0;
  22.         unsigned char key_return = key_no;
  23.         unsigned char key;
  24.        
  25.         key = KEY;  //read the I/O states
  26.        
  27.         switch(key_state_buffer1)
  28.         {
  29.                 case key_state_0:
  30.                         if(key == 0)
  31.                                 key_state_buffer1 = key_state_1;
  32.                                 //按鍵被按下,狀態轉換到按鍵消抖和確認狀態//
  33.                         break;
  34.                 case key_state_1:
  35.                         if(key == 0)
  36.                         {
  37.                                 key_timer_cnt1 = 0;
  38.                                 key_state_buffer1 = key_state_2;
  39.                                 //按鍵仍然處于按下狀態
  40.                                 //消抖完成,key_timer開始準備計時
  41.                                 //狀態切換到按下時間計時狀態
  42.                         }
  43.                         else
  44.                                 key_state_buffer1 = key_state_0;
  45.                                 //按鍵已經抬起,回到按鍵初始狀態
  46.                         break;  //完成軟件消抖
  47.                 case key_state_2:
  48.                         if(key == 1)
  49.                         {
  50.                                 key_return = key_click;  //按鍵抬起,產生一次click操作
  51.                                 key_state_buffer1 = key_state_0;  //轉換到按鍵初始狀態
  52.                         }
  53.                         else if(++key_timer_cnt1 >= 100)  //按鍵繼續按下,計時超過1000ms
  54.                         {
  55.                                 key_return = key_long;  //送回長按事件
  56.                                 key_state_buffer1 = key_state_3;  //轉換到等待按鍵釋放狀態
  57.                         }
  58.                         break;
  59.                 case key_state_3:  //等待按鍵釋放
  60.                         if(key == 1)  //按鍵釋放
  61.                                 key_state_buffer1 = key_state_0;  //切回按鍵初始狀態
  62.                         break;
  63.         }
  64.         return key_return;
  65. }

  66. unsigned char key_read(void)
  67. {
  68.         static unsigned char key_state_buffer2 = key_state_0;
  69.         static unsigned char key_timer_cnt2 = 0;
  70.         unsigned char key_return = key_no;
  71.         unsigned char key;
  72.        
  73.         key = key_driver();
  74.        
  75.         switch(key_state_buffer2)
  76.         {
  77.                 case key_state_0:
  78.                         if(key == key_click)
  79.                         {
  80.                                 key_timer_cnt2 = 0;  //第一次單擊,不返回,到下個狀態判斷是否會出現雙擊
  81.                                 key_state_buffer2 = key_state_1;
  82.                         }
  83.                         else
  84.                                 key_return = key;  //對于無鍵、長按,返回原事件
  85.                         break;
  86.                 case key_state_1:
  87.                         if(key == key_click)  //又一次單擊,時間間隔小于500ms
  88.                         {
  89.                                 key_return = key_double;  //返回雙擊事件,回到初始狀態
  90.                                 key_state_buffer2 = key_state_0;
  91.                         }
  92.                         else if(++key_timer_cnt2 >= 50)
  93.                         {   
  94.                         //這里在下一次的按鍵來臨之前,并且時間是小于500ms的時候,就會一直執行的是這個key_timer_cnt2++.直到下一次的按鍵到來,再判斷看是雙擊還是單擊。
  95.                                 //這里500ms內肯定讀到的都是無鍵事件,因為長按大于1000ms
  96.                                 //在1s前底層返回的都是無鍵
  97.                                                                        
  98.                                 key_return = key_click;  //500ms內沒有再次出現單擊事件,返回單擊事件
  99.                                 key_state_buffer2 = key_state_0;  //返回初始狀態
  100.                                        
  101.                         }
  102.                         break;
  103.         }
  104.        
  105.         return key_return;
  106. }

  107. void Timer0Init(void)                //1毫秒@11.0592MHz
  108. {
  109.         AUXR |= 0x80;                //定時器時鐘1T模式
  110.         TMOD &= 0xF0;                //設置定時器模式
  111.         TL0 = 0xCD;                //設置定時初值
  112.         TH0 = 0xD4;                //設置定時初值
  113.         TF0 = 0;                //清除TF0標志
  114.         TR0 = 1;                //定時器0開始計時
  115.         ET0 = 1;

  116. }
  117. void IO_init()
  118. {
  119.    
  120.     P3M0 = 0x01;
  121.     P3M1 = 0x01;
  122.     P5M0 = 0x00;
  123.     P5M1 = 0x00;
  124.    
  125. }


  126. void main(void)
  127. {          
  128.        unsigned char key = 1;
  129.              Timer0Init();
  130.            IO_init();
  131.            LED_E1P = 1;
  132.            LED_G1 = 1;
  133.            LED2 = 1;
  134.            LED3 = 0;
  135.                    EA = 1;
  136.            while(1)
  137.            {
  138.              if(flag)
  139.                  {
  140.                    flag=0;
  141.            key = key_read();
  142.                    switch(key)
  143.                    {
  144.                             case key_click:LED2 = !LED2; break;
  145.                          case key_double:LED2 = !LED2;LED3 = !LED3; break;
  146.                          case key_long: LED2 = 1; LED3 = 1; LED_G1 = 0; LED_E1P = 0; break;
  147.                          default : break;
  148.                    }
  149.                  }
  150.            }
  151. }

  152. void Timr0_ISR() interrupt 1
  153. {
  154.    cnt++;
  155.    if(cnt>=10)
  156.    {
  157.        cnt = 0;
  158.               flag = 1;
  159.    }
  160. }
復制代碼

以上資料51hei提供下載:
基于狀態機的按鍵長按短按雙擊控制程序.zip (1.87 KB, 下載次數: 367)

評分

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

查看全部評分

回復

使用道具 舉報

ID:405604 發表于 2020-1-13 16:51 | 顯示全部樓層
程序寫的非常完美,沒毛病。提一個存在的小問題,在定時器中斷函數Timr0_ISR()里面要重裝定時器初值,不然主函數第一次初始化定時器以后定時器溢出,會從0~65535計數,并且一直這樣,這樣的cnt++就不能計時10ms了,導致前面的按鍵都不能用,以上本人STC89C52親測,這個問題頭疼了2天后來發現是沒有重裝初值的問題。其他不懂也沒學過!希望后來的朋友不要走彎路,樓主加油!
回復

使用道具 舉報

ID:377382 發表于 2020-2-9 17:22 | 顯示全部樓層
51需要改不少的地方
回復

使用道具 舉報

ID:334781 發表于 2020-2-15 21:20 | 顯示全部樓層
謝謝樓主,下載試一下。對于按鍵的長按與短按,一直是困或我的問題,先謝謝了!
回復

使用道具 舉報

ID:465279 發表于 2020-3-7 12:39 | 顯示全部樓層
wxqhigh 發表于 2020-1-13 16:51
程序寫的非常完美,沒毛病。提一個存在的小問題,在定時器中斷函數Timr0_ISR()里面要重裝定時器初值,不然 ...

仔細看了代碼并測試,回復沒毛病。正在學習按鍵處理這塊,向你學習。
回復

使用道具 舉報

ID:448556 發表于 2020-3-10 15:48 | 顯示全部樓層
是啊不重裝初值 定時中斷只運行一次就停止了
回復

使用道具 舉報

ID:573901 發表于 2020-6-1 10:37 | 顯示全部樓層
wxqhigh 發表于 2020-1-13 16:51
程序寫的非常完美,沒毛病。提一個存在的小問題,在定時器中斷函數Timr0_ISR()里面要重裝定時器初值,不然 ...

這個是stc15w系列的單片機,定時器用的是16位自動重裝載,所以不需要從新賦初值了,不過還是謝謝提醒,一起加油!
回復

使用道具 舉報

ID:573901 發表于 2020-6-1 10:39 | 顯示全部樓層
liyezhao2019 發表于 2020-3-10 15:48
是啊不重裝初值 定時中斷只運行一次就停止了

嗯嗯 ,怪我沒注意,51系列的要裝初值,我這個是stc系列的芯片,定時器0是16位自動重裝載的,一起加油
回復

使用道具 舉報

ID:573901 發表于 2020-6-1 10:42 | 顯示全部樓層

嗯,是的,手上沒有51的板子,所以用了stc的程序寫的,不過這個按鍵的狀態機是可以用的,其他注意51的重裝初值問題。
回復

使用道具 舉報

ID:389488 發表于 2020-9-22 15:27 | 顯示全部樓層
wxqhigh 發表于 2020-1-13 16:51
程序寫的非常完美,沒毛病。提一個存在的小問題,在定時器中斷函數Timr0_ISR()里面要重裝定時器初值,不然 ...

stc15不用重裝初值
回復

使用道具 舉報

ID:610086 發表于 2020-11-27 10:59 | 顯示全部樓層
單擊的時候500ms檢測,會不會有些卡頓感?
回復

使用道具 舉報

ID:367948 發表于 2021-2-18 12:04 | 顯示全部樓層
謝謝樓主,正需要單片機檢測連續按下按鍵程序
回復

使用道具 舉報

ID:275826 發表于 2021-2-26 18:05 | 顯示全部樓層
程序可以,就是太復雜了,可以簡化很多
回復

使用道具 舉報

ID:508724 發表于 2021-3-10 09:51 | 顯示全部樓層
這個狀態機寫的很不錯,nice
回復

使用道具 舉報

ID:430492 發表于 2021-3-23 11:40 | 顯示全部樓層
寫得不錯,是個很好的參考例程。
回復

使用道具 舉報

ID:839438 發表于 2021-6-3 21:38 | 顯示全部樓層
謝謝,正在學習狀態機
回復

使用道具 舉報

ID:935260 發表于 2021-6-10 10:03 | 顯示全部樓層
針對特定的單片機寫程序和通用的單片機程序,還是有差別
回復

使用道具 舉報

ID:601234 發表于 2021-10-20 16:53 | 顯示全部樓層
key_read  和  key_drive可以合并嗎
回復

使用道具 舉報

ID:601234 發表于 2021-10-20 16:54 | 顯示全部樓層
key_read和key_drive可以合并嗎
回復

使用道具 舉報

ID:821788 發表于 2022-8-28 15:19 | 顯示全部樓層
感謝!感謝!
key_read和key_drive可以嘗試合并,少用一個狀態機、少占用一個byte RAM
回復

使用道具 舉報

ID:59300 發表于 2023-9-11 09:28 | 顯示全部樓層
很好的文章,對我正在學習狀態機非常有幫助,謝謝
回復

使用道具 舉報

ID:1127891 發表于 2024-7-2 14:35 | 顯示全部樓層
樓主這么nb
回復

使用道具 舉報

ID:786399 發表于 2024-7-2 21:11 | 顯示全部樓層
受益匪淺
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 精品日韩一区二区 | 亚洲欧美一区二区三区在线 | 久久岛国 | 一区二区三区四区在线 | 亚洲欧美精品国产一级在线 | 99国产精品99久久久久久粉嫩 | 亚洲毛片在线观看 | 亚洲喷水 | 日韩成人精品一区二区三区 | 91精品在线播放 | 国产精品久久av | 三区在线 | 91传媒在线观看 | 欧美一级大片 | 99精品国自产在线 | 美女视频一区 | 国产精品一二区 | 第四色狠狠| 久久久久久久香蕉 | 欧美男人天堂 | 97超在线视频 | 日美女逼逼 | 久久久久久久一区 | 日韩欧美国产一区二区三区 | 亚洲国产成人精品久久久国产成人一区 | 色橹橹欧美在线观看视频高清 | 国产精品一区在线观看 | 中文字幕av网 | 国内自拍视频在线观看 | 亚洲成av人片在线观看 | 黑人巨大精品欧美一区二区免费 | 国产精品久久 | 欧美日韩亚洲一区 | 日韩在线精品 | 久久国产精品免费一区二区三区 | 国产一区影院 | 成人免费视频 | 91在线看| 成人依人 | 成人国产精品免费观看 | 日韩免费在线 |