新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > MCU實戰經驗:多種的按鍵處理

        MCU實戰經驗:多種的按鍵處理

        作者: 時間:2016-06-30 來源:網絡 收藏

        按鍵通常有:IO口按鍵(BUTTON),AD按鍵(通過AD采樣電壓),IR(遙控器)
        按按鍵功能分:有短按鍵,長按鍵,連續按鍵。打個比方,遙控電視機,按一下音量鍵,音量增加1,這個就是短按鍵。按住音量鍵不放,音量連續加,這個就是連續按鍵。按住一個按鍵5s,系統會復位,這個是長按鍵。

        本文引用地址:http://www.104case.com/article/201606/293391.htm

        1、IO口按鍵,就是我們比較常見的一個IO接一個按鍵,或者是一個矩陣鍵盤。很多新人的處理方法可能是采樣延時的方法,當年我也是這樣的,如下

        1. if(GETIO==low)  

        2.  {   

        3.    delay_10ms()  

        4. if(GETIO==low)  

        5.    {  

        6. //得到按鍵值

        7.    }  

        8.  }  

         

        這種方法雖然簡單,但是有很大弊端。首先 Delay浪費很多時間,影響系統。第二,無法判斷長短按鍵,連續按鍵。第三,如果這個按鍵是開關機按鍵系統在低功耗狀態下,需要中斷喚醒,這種方法比較容易出問題,如STM8S系列的 halt 模式。

        所以我們一般在產品開發的過程中,采用掃描的方法,就是每隔10ms 去檢測IO的狀態,看是否有按鍵,然后去抖動,判斷按鍵功能。參考代碼如下,這段代碼是之前在一個論壇看到的比我自己寫的更加優秀,所以拿出來和大家分享一下,也順便感謝一下作者。這段代碼,容易修改,可以根據自己的時間需要,進行長短按鍵,連續按鍵,還有組合按鍵的判斷。

        1. /* 按鍵濾波時間50ms, 單位10ms

        2.  *只有連續檢測到50ms狀態不變才認為有效,包括彈起和按下兩種事件

        3.  */

        4. #define BUTTON_FILTER_TIME         5

        5. #define BUTTON_LONG_TIME         300                /* 持續1秒,認為長按事件 */

        6. /*

        7.         每個按鍵對應1個全局的結構體變量。

        8.         其成員變量是實現濾波和多種按鍵狀態所必須的

        9. */

        10. typedefstruct

        11. {  

        12. /* 下面是一個函數指針,指向判斷按鍵手否按下的函數 */

        13.         unsigned char  (*IsKeyDownFunc)(void); /* 按鍵按下的判斷函數,1表示按下 */

        14.         unsigned char  Count;                        /* 濾波器計數器 */

        15.         unsigned char  FilterTime;                /* 濾波時間(最大255,表示2550ms) */

        16.         unsigned short LongCount;                /* 長按計數器 */

        17.         unsigned short LongTime;                /* 按鍵按下持續時間, 0表示不檢測長按 */

        18.         unsigned char   State;                        /* 按鍵當前狀態(按下還是彈起) */

        19.         unsigned char  KeyCodeUp;                /* 按鍵彈起的鍵值代碼, 0表示不檢測按鍵彈起 */

        20.         unsigned char  KeyCodeDown;        /* 按鍵按下的鍵值代碼, 0表示不檢測按鍵按下 */

        21.         unsigned char  KeyCodeLong;        /* 按鍵長按的鍵值代碼, 0表示不檢測長按 */

        22.         unsigned char  RepeatSpeed;        /* 連續按鍵周期 */

        23.         unsigned char  RepeatCount;        /* 連續按鍵計數器 */

        24. }BUTTON_T;  

        25. typedefenum

        26. {  

        27.         KEY_NONE = 0,                        /* 0 表示按鍵事件 */

        28.         KEY_DOWN_Power,                        /* 按鍵鍵按下 */

        29.         KEY_UP_Power,                        /* 按鍵鍵彈起 */

        30.         KEY_LONG_Power,                        /* 按鍵鍵長按 */

        31.         KEY_DOWN_Power_TAMPER        /* 組合鍵,Power鍵和WAKEUP鍵同時按下 */

        32. }KEY_ENUM;  

        33. BUTTON_T s_Powerkey;                  

        34. //是否有按鍵按下接口函數

        35. unsigned char  IsKeyDownUser(void)                   

        36. {if (0==GPIO_ReadInputPin(POWER_KEY_PORT, POWER_KEY_PIN) ) return 1;return 0;}  

        37. void  PanakeyHard_Init(void)  

        38. {  

        39.    GPIO_Init (POWER_KEY_PORT, POWER_KEY_PIN, GPIO_MODE_IN_FL_NO_IT);//power key

        40. }  

        41. void  PanakeyVar_Init(void)  

        42. {  

        43. /* 初始化USER按鍵變量,支持按下、彈起、長按 */

        44.         s_Powerkey.IsKeyDownFunc = IsKeyDownUser;                /* 判斷按鍵按下的函數 */

        45.         s_Powerkey.FilterTime = BUTTON_FILTER_TIME;                /* 按鍵濾波時間 */

        46.         s_Powerkey.LongTime = BUTTON_LONG_TIME;                        /* 長按時間 */

        47.         s_Powerkey.Count = s_Powerkey.FilterTime / 2;                /* 計數器設置為濾波時間的一半 */

        48.         s_Powerkey.State = 0;                                                        /* 按鍵缺省狀態,0為未按下 */

        49.         s_Powerkey.KeyCodeDown = KEY_DOWN_Power;                        /* 按鍵按下的鍵值代碼 */

        50.         s_Powerkey.KeyCodeUp =KEY_UP_Power;                                /* 按鍵彈起的鍵值代碼 */

        51.         s_Powerkey.KeyCodeLong = KEY_LONG_Power;                        /* 按鍵被持續按下的鍵值代碼 */

        52.         s_Powerkey.RepeatSpeed = 0;                                                /* 按鍵連發的速度,0表示不支持連發 */

        53.         s_Powerkey.RepeatCount = 0;                                                /* 連發計數器 */

        54. }  

        55. void Panakey_Init(void)  

        56. {  

        57.         PanakeyHard_Init();                /* 初始化按鍵變量 */

        58.         PanakeyVar_Init();                /* 初始化按鍵硬件 */

        59. }  

        60. /*

        61. *********************************************************************************************************

        62. *        函 數 名: bsp_DetectButton

        63. *        功能說明: 檢測一個按鍵。非阻塞狀態,必須被周期性的調用。

        64. *        形    參:按鍵結構變量指針

        65. *        返 回 值: 無

        66. *********************************************************************************************************

        67. */

        68. void Button_Detect(BUTTON_T *_pBtn)  

        69. {  

        70. if (_pBtn->IsKeyDownFunc())  

        71.         {  

        72. if (_pBtn->Count < _pBtn->FilterTime)  

        73.                 {  

        74.                         _pBtn->Count = _pBtn->FilterTime;  

        75.                 }  

        76. elseif(_pBtn->Count < 2 * _pBtn->FilterTime)  

        77.                 {  

        78.                         _pBtn->Count++;  

        79.                 }  

        80. else

        81.                 {  

        82. if (_pBtn->State == 0)  

        83.                         {  

        84.                                 _pBtn->State = 1;  

        85. /* 發送按鈕按下的消息 */

        86. if (_pBtn->KeyCodeDown > 0)  

        87.                                 {  

        88. /* 鍵值放入按鍵FIFO */

        89.                                         Pannelkey_Put(_pBtn->KeyCodeDown);// 記錄按鍵按下標志,等待釋放

        90.                                 }  

        91.                         }  

        92. if (_pBtn->LongTime > 0)  

        93.                         {  

        94. if (_pBtn->LongCount < _pBtn->LongTime)  

        95.                                 {  

        96. /* 發送按鈕持續按下的消息 */

        97. if (++_pBtn->LongCount == _pBtn->LongTime)  

        98.                                         {  

        99. /* 鍵值放入按鍵FIFO */

        100.                                                 Pannelkey_Put(_pBtn->KeyCodeLong);          

        101.                                         }  

        102.                                 }  

        103. else

        104.                                 {  

        105. if (_pBtn->RepeatSpeed > 0)  

        106.                                         {  

        107. if (++_pBtn->RepeatCount >= _pBtn->RepeatSpeed)  

        108.                                                 {  

        109.                                                         _pBtn->RepeatCount = 0;  

        110. /* 常按鍵后,每隔10ms發送1個按鍵 */

        111.                                                         Pannelkey_Put(_pBtn->KeyCodeDown);          

        112.                                                 }  

        113.                                         }  

        114.                                 }  

        115.                         }  

        116.                 }  

        117.         }  

        118. else

        119.         {  

        120. if(_pBtn->Count > _pBtn->FilterTime)  

        121.                 {  

        122.                         _pBtn->Count = _pBtn->FilterTime;  

        123.                 }  

        124. elseif(_pBtn->Count != 0)  

        125.                 {  

        126.                         _pBtn->Count--;  

        127.                 }  

        128. else

        129.                 {  

        130. if (_pBtn->State == 1)  

        131.                         {  

        132.                                 _pBtn->State = 0;  

        133. /* 發送按鈕彈起的消息 */

        134. if (_pBtn->KeyCodeUp > 0) /*按鍵釋放*/

        135.                                 {  

        136. /* 鍵值放入按鍵FIFO */

        137.                                 Pannelkey_Put(_pBtn->KeyCodeUp);          

        138.                                 }  

        139.                         }  

        140.                 }  

        141.                 _pBtn->LongCount = 0;  

        142.                 _pBtn->RepeatCount = 0;  

        143.         }  

        144. }  

        145. //功能說明: 檢測所有按鍵。10MS 調用一次

        146. void Pannelkey_Polling(void)  

        147. {  

        148.         Button_Detect(&s_Powerkey);                /* USER 鍵 */

        149. }  

        150. void Pannelkey_Put(void)  

        151. {  

        152. // 定義一個隊列 放入按鍵值        

        153. }  


        2、遙控器按鍵,遙控器解碼的一般就有兩種:脈寬調制和脈沖調制,這里就不細講解碼的過程了。這里詳細解碼之后,如何處理遙控器按鍵實現遙控器按鍵的長短按功能和連續按鍵功能。代碼裁剪過,大家根據實際需要改動。其實AD按鍵,通過AD采樣獲得按鍵值之后,可以采取如下面的一樣方法處理,提一個函數接口即可

         

        1. typedefstruct

        2. {  

        3.   unsigned char count;//

        4.   unsigned char LongkeyFlag;/*是否長按鍵,1代表是*/

        5.   unsigned char  PreKeyValue;/*按鍵值的一個備份,用于釋放按鍵值*/

        6. }ScanKeyDef;  

        7. #define SHORT_PRESS_TIME_IR                16 // 10ms 

        8. #define SERIES_PRESS_TIME_IR            10  

        9. #define LONG_PRESS_TIME_IR                    22

        10. #define KEY_RELEASE_TIME_OUT_IR     12  // 10ms 

        11. //提供5個接口函數,如下。 

        12. unsigned char get_irkey(void);  

        13. unsigned char ISSeriesKey(unsigned char temp);//按鍵是否需要做連續按鍵

        14. unsigned char changeSeriesKey(unsigned char temp);//轉換連續按鍵值

        15. unsigned char ISLongKey(unsigned char temp);//按鍵是否需要做連續按鍵

        16. unsigned char changeToLongKey(unsigned char temp);//轉換連續按鍵值

        17. unsigned char KeyScan(void)   

        18. {  

        19.     unsigned char  KeyValue = KEY_NONE,  

        20.                                 KeyValueTemp = KEY_NONE;  

        21. static   unsigned char KeyReleaseTimeCount =0;  

        22.     KeyValueTemp = get_irkey();  

        23. if(KeyValueTemp != KEY_NONE)  

        24.     {  

        25.         ScanKeyDef.count++;  

        26.         KeyReleaseTimeCount =0;  

        27. if(ScanKeyDef.count < LONG_PRESS_TIME_IR )  

        28.         {  

        29.             ScanKeyDef.LongkeyFlag = 0;  

        30. if((ScanKeyDef.count == SERIES_PRESS_TIME_IR) && ISSeriesKey(KeyValueTemp)) //處理連續按鍵

        31.                 {  

        32.                     KeyValue = changeSeriesKey ( KeyValueTemp );  

        33.                     ScanKeyDef.PreKeyValue = KEY_NONE;  

        34.                 }  

        35. elseif ( ScanKeyDef.count  < SHORT_PRESS_TIME_IR )  

        36.             {  

        37.                 ScanKeyDef.PreKeyValue = KeyValueTemp;  

        38.             }  

        39. else

        40.             {  

        41.                 ScanKeyDef.PreKeyValue  = KEY_NONE; // 無效按鍵

        42.             }  

        43.         }  

        44. elseif ( ScanKeyDef.count  == LONG_PRESS_TIME_IR )  

        45.         {  

        46. if (ISLongKey(KeyValueTemp))  

        47.             {  

        48.                 {  

        49.                    ScanKeyDef.LongkeyFlag = 1;  

        50.                    KeyValue = changeToLongKey ( KeyValueTemp );  

        51.                }  

        52.           }  

        53.             ScanKeyDef.PreKeyValue = KEY_NONE;  

        54.         }  

        55. elseif (ScanKeyDef.count > LONG_PRESS_TIME_IR )  

        56.         {  

        57.             ScanKeyDef.PreKeyValue  = KEY_NONE; //無效按鍵

        58.         }  

        59.     }  

        60. else//release & no press

        61.     {  

        62.         KeyReleaseTimeCount ++;  

        63. if(KeyReleaseTimeCount >= KEY_RELEASE_TIME_OUT_IR)  

        64.         {  

        65. if ( ScanKeyDef.PreKeyValue != KEY_NONE ) //釋放按鍵值

        66.             {  

        67. if ( ScanKeyDef.LongkeyFlag == 0 )  

        68.                 {  

        69.                     KeyValue =ScanKeyDef.PreKeyValue ;  

        70.                 }  

        71.             }            

        72.             ScanKeyDef.count  = 0;  

        73.             ScanKeyDef.LongkeyFlag = 0;  

        74.            ScanKeyDef.PreKeyValue = KEY_NONE;  

        75.         }  

        76.     }  

        77. return(KeyValue);  

        78. }  



        關鍵詞: MCU 按鍵處理

        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 师宗县| 阿城市| 兰考县| 平山县| 彰武县| 古交市| 湟中县| 资中县| 苏尼特右旗| 姚安县| 博野县| 阜阳市| 新田县| 安陆市| 萍乡市| 淳安县| 海门市| 福安市| 黎城县| 绥阳县| 浠水县| 长泰县| 华安县| 苗栗县| 温州市| 咸阳市| 南平市| 湘西| 滕州市| 闻喜县| 河池市| 海伦市| 陆河县| 青海省| 黔西| 北川| 清原| 桦南县| 会昌县| 楚雄市| 白朗县|