找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 5879|回復: 3
收起左側

51單片機學習:基于狀態(tài)機的按鍵對時程序(短按,長按,連發(fā))

[復制鏈接]
ID:161768 發(fā)表于 2017-1-14 23:43 | 顯示全部樓層 |閱讀模式
之前的電子鐘程序中,用的按鍵消抖處理方法是10ms的延時,這種方法效率比較低
所以現在利用狀態(tài)機原理重寫一下,效率很高啊

4個獨立按鍵中用到3個,
keys5用于切換對時分秒等狀態(tài),keys2是減小數值,keys3是增加數值

同時可以判斷按鍵的"短按,長按,連發(fā)"等功能
小于2秒視為短按,
大于2秒視為長按,
在長按狀態(tài)下每0.2秒自動連發(fā)一次, 這樣對時的時候就不用按N次了


程序分很多個文件 ,Keil uVision4 打包



30880aac-82da-33b2-a05a-45059eb2bcf3.png

  1. #include "keyScan.h"
  2. #include <reg52.h>

  3. /*按鍵初始化,若io沒有復用的話可以省略此步驟
  4. void KeyInit(void)
  5. {
  6.     keyS2 = 1 ;
  7.     keyS3 = 1 ;
  8.     keyS4 = 1 ;
  9.     keyS5 = 1 ;
  10.         //即P3|=0xf0;            
  11. }*/

  12. static u8 getKey(void)                    //獲取P3口值
  13. {
  14.     if(key_down == keyS2)
  15.         {
  16.                 return KEYS2_VALUE ;
  17.         }

  18.     if(key_down == keyS3 )
  19.         {
  20.           return KEYS3_VALUE ;
  21.         }

  22.     if(key_down == keyS4 )
  23.         {
  24.                 return KEYS4_VALUE ;
  25.         }
  26.          
  27.     if(key_down == keyS5 )
  28.         {
  29.                 return KEYS5_VALUE ;
  30.         }

  31.     return key_up ;    //0xf0  沒有任何按鍵
  32. }

  33. //函數每10ms被調用一次,而我們彈性按鍵過程時一般都20ms以上
  34. //所以每次按鍵至少調用本函數2次
  35. u8 read_key(u8* pKeyValue)                          
  36. {
  37.     static u8  s_u8keyState=0;        //未按,普通短按,長按,連發(fā)等狀態(tài)
  38.     static u16 s_u16keyTimeCounts=0;  //在計時狀態(tài)的計數器
  39.         static u8  s_u8LastKey = key_up ; //保存按鍵釋放時的P3口數據

  40.     u8 keyTemp=0;                          //鍵對應io口的電平
  41.     s8 key_return=0;                //函數返回值
  42.     keyTemp=key_up & getKey();  //提取所有的key對應的io口

  43.     switch(s_u8keyState)           //這里檢測到的是先前的狀態(tài)
  44.     {
  45.         case state_keyUp:   //如果先前是初始態(tài),即無動作
  46.         {
  47.             if(key_up!=keyTemp) //如果鍵被按下
  48.             {
  49.                 s_u8keyState=state_keyDown; //更新鍵的狀態(tài),普通被按下
  50.             }
  51.         }
  52.         break;
  53.         
  54.         case state_keyDown: //如果先前是被按著的
  55.         {
  56.             if(key_up!=keyTemp) //如果現在還被按著
  57.             {
  58.                 s_u8keyState=state_keyTime; //轉換到計時態(tài)
  59.                 s_u16keyTimeCounts=0;
  60.                                 s_u8LastKey = keyTemp;     //保存鍵值
  61.             }
  62.             else
  63.             {
  64.                 s_u8keyState=state_keyUp; //鍵沒被按著,回初始態(tài),說明是干擾
  65.             }
  66.         }
  67.         break;
  68.         
  69.         case state_keyTime:  //如果先前已經轉換到計時態(tài)(值為3)
  70.         {  //如果真的是手動按鍵,必然進入本代碼塊,并且會多次進入
  71.             if(key_up==keyTemp) //如果未按鍵
  72.             {
  73.                 s_u8keyState=state_keyUp;
  74.                 key_return=return_keyPressed;    //返回1,一次完整的普通按鍵
  75.                 //程序進入這個語句塊,說明已經有2次以上10ms的中斷,等于已經消抖
  76.                 //那么此時檢測到按鍵被釋放,說明是一次普通短按
  77.             }
  78.             else  //在計時態(tài),檢測到鍵還被按著
  79.             {
  80.                 if(++s_u16keyTimeCounts>key_longTimes) //時間達到2秒
  81.                 {
  82.                     s_u8keyState=state_keyLong;  //進入長按狀態(tài)
  83.                     s_u16keyTimeCounts=0;                  //計數器清空,便于進入連發(fā)重新計數
  84.                     key_return=return_keyLong;   //返回state_keyLong
  85.                 }
  86.                 //代碼中,在2秒內如果我們一直按著key的話,返回值只會是0,不會識別為短按或長按的
  87.             }
  88.         }
  89.         break;
  90.         
  91.         case state_keyLong:  //在長按狀態(tài)檢測連發(fā)  ,每0.2秒發(fā)一次
  92.         {
  93.             if(key_up==keyTemp)
  94.             {
  95.                s_u8keyState=state_keyUp;
  96.             }
  97.             else //按鍵時間超過2秒時
  98.             {
  99.                 if(++s_u16keyTimeCounts>key_autoTimes)//10*20=200ms
  100.                 {
  101.                     s_u16keyTimeCounts=0;
  102.                     key_return=return_keyAuto;  //每0.2秒返回值的第2位置位(1<<2)
  103.                 }//連發(fā)的時候,肯定也伴隨著長按
  104.             }
  105.             key_return |= return_keyLong;  //0x02是肯定的,0x04|0x02是可能的
  106.         }
  107.         break;
  108.         
  109.         default:
  110.         break;
  111.     }
  112.         *pKeyValue = s_u8LastKey ; //返回鍵值
  113.     return key_return;
  114. }
復制代碼

回復

使用道具 舉報

ID:161747 發(fā)表于 2017-1-16 08:15 | 顯示全部樓層
沒看到打包文件啊。
回復

使用道具 舉報

ID:976756 發(fā)表于 2021-11-1 18:02 | 顯示全部樓層
沒有看到打包文件
回復

使用道具 舉報

ID:954686 發(fā)表于 2021-11-2 08:04 | 顯示全部樓層
方法不錯,狀態(tài)機,沒有死等延時
回復

使用道具 舉報

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

本版積分規(guī)則

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

Powered by 單片機教程網

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