<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > MCU實(shí)戰(zhàn)經(jīng)驗(yàn):多種的按鍵處理

          MCU實(shí)戰(zhàn)經(jīng)驗(yàn):多種的按鍵處理

          作者: 時(shí)間:2016-06-30 來(lái)源:網(wǎng)絡(luò) 收藏

          按鍵通常有:IO口按鍵(BUTTON),AD按鍵(通過(guò)AD采樣電壓),IR(遙控器)
          按按鍵功能分:有短按鍵,長(zhǎng)按鍵,連續(xù)按鍵。打個(gè)比方,遙控電視機(jī),按一下音量鍵,音量增加1,這個(gè)就是短按鍵。按住音量鍵不放,音量連續(xù)加,這個(gè)就是連續(xù)按鍵。按住一個(gè)按鍵5s,系統(tǒng)會(huì)復(fù)位,這個(gè)是長(zhǎng)按鍵。

          本文引用地址:http://www.ex-cimer.com/article/201606/293391.htm

          1、IO口按鍵,就是我們比較常見(jiàn)的一個(gè)IO接一個(gè)按鍵,或者是一個(gè)矩陣鍵盤(pán)。很多新人的處理方法可能是采樣延時(shí)的方法,當(dāng)年我也是這樣的,如下

          1. if(GETIO==low)  

          2.  {   

          3.    delay_10ms()  

          4. if(GETIO==low)  

          5.    {  

          6. //得到按鍵值

          7.    }  

          8.  }  

           

          這種方法雖然簡(jiǎn)單,但是有很大弊端。首先 Delay浪費(fèi)很多時(shí)間,影響系統(tǒng)。第二,無(wú)法判斷長(zhǎng)短按鍵,連續(xù)按鍵。第三,如果這個(gè)按鍵是開(kāi)關(guān)機(jī)按鍵系統(tǒng)在低功耗狀態(tài)下,需要中斷喚醒,這種方法比較容易出問(wèn)題,如STM8S系列的 halt 模式。

          所以我們一般在產(chǎn)品開(kāi)發(fā)的過(guò)程中,采用掃描的方法,就是每隔10ms 去檢測(cè)IO的狀態(tài),看是否有按鍵,然后去抖動(dòng),判斷按鍵功能。參考代碼如下,這段代碼是之前在一個(gè)論壇看到的比我自己寫(xiě)的更加優(yōu)秀,所以拿出來(lái)和大家分享一下,也順便感謝一下作者。這段代碼,容易修改,可以根據(jù)自己的時(shí)間需要,進(jìn)行長(zhǎng)短按鍵,連續(xù)按鍵,還有組合按鍵的判斷。

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

          2.  *只有連續(xù)檢測(cè)到50ms狀態(tài)不變才認(rèn)為有效,包括彈起和按下兩種事件

          3.  */

          4. #define BUTTON_FILTER_TIME         5

          5. #define BUTTON_LONG_TIME         300                /* 持續(xù)1秒,認(rèn)為長(zhǎng)按事件 */

          6. /*

          7.         每個(gè)按鍵對(duì)應(yīng)1個(gè)全局的結(jié)構(gòu)體變量。

          8.         其成員變量是實(shí)現(xiàn)濾波和多種按鍵狀態(tài)所必須的

          9. */

          10. typedefstruct

          11. {  

          12. /* 下面是一個(gè)函數(shù)指針,指向判斷按鍵手否按下的函數(shù) */

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

          14.         unsigned char  Count;                        /* 濾波器計(jì)數(shù)器 */

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

          16.         unsigned short LongCount;                /* 長(zhǎng)按計(jì)數(shù)器 */

          17.         unsigned short LongTime;                /* 按鍵按下持續(xù)時(shí)間, 0表示不檢測(cè)長(zhǎng)按 */

          18.         unsigned char   State;                        /* 按鍵當(dāng)前狀態(tài)(按下還是彈起) */

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

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

          21.         unsigned char  KeyCodeLong;        /* 按鍵長(zhǎng)按的鍵值代碼, 0表示不檢測(cè)長(zhǎng)按 */

          22.         unsigned char  RepeatSpeed;        /* 連續(xù)按鍵周期 */

          23.         unsigned char  RepeatCount;        /* 連續(xù)按鍵計(jì)數(shù)器 */

          24. }BUTTON_T;  

          25. typedefenum

          26. {  

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

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

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

          30.         KEY_LONG_Power,                        /* 按鍵鍵長(zhǎng)按 */

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

          32. }KEY_ENUM;  

          33. BUTTON_T s_Powerkey;                  

          34. //是否有按鍵按下接口函數(shù)

          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按鍵變量,支持按下、彈起、長(zhǎng)按 */

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

          45.         s_Powerkey.FilterTime = BUTTON_FILTER_TIME;                /* 按鍵濾波時(shí)間 */

          46.         s_Powerkey.LongTime = BUTTON_LONG_TIME;                        /* 長(zhǎng)按時(shí)間 */

          47.         s_Powerkey.Count = s_Powerkey.FilterTime / 2;                /* 計(jì)數(shù)器設(shè)置為濾波時(shí)間的一半 */

          48.         s_Powerkey.State = 0;                                                        /* 按鍵缺省狀態(tài),0為未按下 */

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

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

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

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

          53.         s_Powerkey.RepeatCount = 0;                                                /* 連發(fā)計(jì)數(shù)器 */

          54. }  

          55. void Panakey_Init(void)  

          56. {  

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

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

          59. }  

          60. /*

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

          62. *        函 數(shù) 名: bsp_DetectButton

          63. *        功能說(shuō)明: 檢測(cè)一個(gè)按鍵。非阻塞狀態(tài),必須被周期性的調(diào)用。

          64. *        形    參:按鍵結(jié)構(gòu)變量指針

          65. *        返 回 值: 無(wú)

          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. /* 發(fā)送按鈕按下的消息 */

          86. if (_pBtn->KeyCodeDown > 0)  

          87.                                 {  

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

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

          90.                                 }  

          91.                         }  

          92. if (_pBtn->LongTime > 0)  

          93.                         {  

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

          95.                                 {  

          96. /* 發(fā)送按鈕持續(xù)按下的消息 */

          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發(fā)送1個(gè)按鍵 */

          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. /* 發(fā)送按鈕彈起的消息 */

          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. //功能說(shuō)明: 檢測(cè)所有按鍵。10MS 調(diào)用一次

          146. void Pannelkey_Polling(void)  

          147. {  

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

          149. }  

          150. void Pannelkey_Put(void)  

          151. {  

          152. // 定義一個(gè)隊(duì)列 放入按鍵值        

          153. }  


          2、遙控器按鍵,遙控器解碼的一般就有兩種:脈寬調(diào)制和脈沖調(diào)制,這里就不細(xì)講解碼的過(guò)程了。這里詳細(xì)解碼之后,如何處理遙控器按鍵實(shí)現(xiàn)遙控器按鍵的長(zhǎng)短按功能和連續(xù)按鍵功能。代碼裁剪過(guò),大家根據(jù)實(shí)際需要改動(dòng)。其實(shí)AD按鍵,通過(guò)AD采樣獲得按鍵值之后,可以采取如下面的一樣方法處理,提一個(gè)函數(shù)接口即可

           

          1. typedefstruct

          2. {  

          3.   unsigned char count;//

          4.   unsigned char LongkeyFlag;/*是否長(zhǎng)按鍵,1代表是*/

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

          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個(gè)接口函數(shù),如下。 

          12. unsigned char get_irkey(void);  

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

          14. unsigned char changeSeriesKey(unsigned char temp);//轉(zhuǎn)換連續(xù)按鍵值

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

          16. unsigned char changeToLongKey(unsigned char temp);//轉(zhuǎn)換連續(xù)按鍵值

          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)) //處理連續(xù)按鍵

          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; // 無(wú)效按鍵

          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; //無(wú)效按鍵

          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. }  



          關(guān)鍵詞: MCU 按鍵處理

          評(píng)論


          相關(guān)推薦

          技術(shù)專(zhuān)區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();