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

標題: 基于狀態機的按鍵長按,短按,雙擊 單片機源程序 [打印本頁]

作者: 靜濤君    時間: 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)



作者: wxqhigh    時間: 2020-1-13 16:51
程序寫的非常完美,沒毛病。提一個存在的小問題,在定時器中斷函數Timr0_ISR()里面要重裝定時器初值,不然主函數第一次初始化定時器以后定時器溢出,會從0~65535計數,并且一直這樣,這樣的cnt++就不能計時10ms了,導致前面的按鍵都不能用,以上本人STC89C52親測,這個問題頭疼了2天后來發現是沒有重裝初值的問題。其他不懂也沒學過!希望后來的朋友不要走彎路,樓主加油!
作者: 中恒電子asus    時間: 2020-2-9 17:22
51需要改不少的地方
作者: yxdz1358    時間: 2020-2-15 21:20
謝謝樓主,下載試一下。對于按鍵的長按與短按,一直是困或我的問題,先謝謝了!
作者: hxszrb    時間: 2020-3-7 12:39
wxqhigh 發表于 2020-1-13 16:51
程序寫的非常完美,沒毛病。提一個存在的小問題,在定時器中斷函數Timr0_ISR()里面要重裝定時器初值,不然 ...

仔細看了代碼并測試,回復沒毛病。正在學習按鍵處理這塊,向你學習。
作者: liyezhao2019    時間: 2020-3-10 15:48
是啊不重裝初值 定時中斷只運行一次就停止了
作者: 靜濤君    時間: 2020-6-1 10:37
wxqhigh 發表于 2020-1-13 16:51
程序寫的非常完美,沒毛病。提一個存在的小問題,在定時器中斷函數Timr0_ISR()里面要重裝定時器初值,不然 ...

這個是stc15w系列的單片機,定時器用的是16位自動重裝載,所以不需要從新賦初值了,不過還是謝謝提醒,一起加油!
作者: 靜濤君    時間: 2020-6-1 10:39
liyezhao2019 發表于 2020-3-10 15:48
是啊不重裝初值 定時中斷只運行一次就停止了

嗯嗯 ,怪我沒注意,51系列的要裝初值,我這個是stc系列的芯片,定時器0是16位自動重裝載的,一起加油
作者: 靜濤君    時間: 2020-6-1 10:42
中恒電子asus 發表于 2020-2-9 17:22
51需要改不少的地方

嗯,是的,手上沒有51的板子,所以用了stc的程序寫的,不過這個按鍵的狀態機是可以用的,其他注意51的重裝初值問題。
作者: zzh2118    時間: 2020-9-22 15:27
wxqhigh 發表于 2020-1-13 16:51
程序寫的非常完美,沒毛病。提一個存在的小問題,在定時器中斷函數Timr0_ISR()里面要重裝定時器初值,不然 ...

stc15不用重裝初值
作者: Jun_w    時間: 2020-11-27 10:59
單擊的時候500ms檢測,會不會有些卡頓感?
作者: wanglx    時間: 2021-2-18 12:04
謝謝樓主,正需要單片機檢測連續按下按鍵程序
作者: tyrl800    時間: 2021-2-26 18:05
程序可以,就是太復雜了,可以簡化很多
作者: nn5959513    時間: 2021-3-10 09:51
這個狀態機寫的很不錯,nice
作者: cooleaf    時間: 2021-3-23 11:40
寫得不錯,是個很好的參考例程。
作者: 我會想你的    時間: 2021-6-3 21:38
謝謝,正在學習狀態機
作者: gxzqh    時間: 2021-6-10 10:03
針對特定的單片機寫程序和通用的單片機程序,還是有差別
作者: zaodan    時間: 2021-10-20 16:53
key_read  和  key_drive可以合并嗎
作者: zaodan    時間: 2021-10-20 16:54
key_read和key_drive可以合并嗎
作者: zzy2200    時間: 2022-8-28 15:19
感謝!感謝!
key_read和key_drive可以嘗試合并,少用一個狀態機、少占用一個byte RAM
作者: wy13043207006    時間: 2023-9-11 09:28
很好的文章,對我正在學習狀態機非常有幫助,謝謝
作者: yunyun66    時間: 2024-7-2 14:35
樓主這么nb
作者: xiaoyu112    時間: 2024-7-2 21:11
受益匪淺




歡迎光臨 (http://m.zg4o1577.cn/bbs/) Powered by Discuz! X3.1
主站蜘蛛池模板: 国产黄a三级三级看三级 | 国产一级片在线播放 | 超碰av在线播放 | 丝袜美腿亚洲综合 | 日本一本在线 | 成人精品福利 | 久久亚洲免费视频 | 中文字幕久久精品 | 国产h片在线观看 | 国产对白videos麻豆高潮 | 久久精品一区二区三区四区五区 | 欧美视频三区 | 国产午夜视频在线观看 | 黄色免费在线视频 | 久艹在线观看 | 黑人精品xxx一区一二区 | www久| 欧美人与野 | 黄色成人免费网站 | 日皮视频在线观看 | 色综合激情 | 国产精品羞羞答答 | 中文在线字幕观看 | 欧美黄色一级 | 激情久久久 | 日韩免费精品视频 | 99re在线| 在线看日韩 | 国产日韩在线播放 | 午夜在线视频观看日韩17c | 成人福利网站 | 成人av一区 | 成人av一区 | 在线观看网址你懂的 | 一区二区三区影视 | 一级黄片毛片 | 狠狠干综合网 | 精品黄色片| 黄色成人在线 | 久久久网站 | 国产精品99999 |