標題: 狀態(tài)機按鍵掃描,看懂了會增長你的功力。。。。 [打印本頁]

作者: xiao_yp2014    時間: 2014-12-14 21:19
標題: 狀態(tài)機按鍵掃描,看懂了會增長你的功力。。。。
本帖最后由 xiao_yp2014 于 2016-1-21 14:37 編輯

大家好!我叫肖亞平,從小熱愛上了電子技術(shù),讀書時陰差陽錯的選擇了電子這方面的專業(yè),學習電子技術(shù)。對于我的理解來說,學校里面學到的技術(shù)不是全部實用,但是必須有用,所以一直奮斗在前線。我對學習總結(jié)出一句話“壓力不是有人努力,而是比你牛X N倍的人依然在努力
說在前面:
              做單片機開發(fā)少不了的就是通過按鍵和單片機交流,按鍵是單片機交流的一個橋梁,所以狀態(tài)機按鍵掃描猶如嵌入式一樣的火爆,在網(wǎng)上一搜一大把,一說起按鍵,學了單片機的人都知道有個叫做“狀態(tài)機掃描的方法”,這個方法確實比其它的按鍵方法要好得多,我記得在星期五的一個下午,一個網(wǎng)友叫我?guī)退{(diào)一個程序,他當時說按下按鍵顯示就不顯示了,我一想,按鍵肯定有問題,我打開程序一看,里面居然還有像這樣的語句存在“ while(!Key); ”這明顯是給自己找麻煩,給CPU挖陷阱嘛,下面分享一個狀態(tài)機的按鍵掃描方法,據(jù)說這種方法是實時最高的,今天我也是親自試過,確定如此。





程序如下:main.c
  1. /********************************************************************************************
  2. 名    稱:狀態(tài)機按鍵掃描
  3. 功    能:運用狀態(tài)機思想,實現(xiàn)按下按鍵LED點亮,再按一下LED燈熄滅。
  4. 作    者:肖亞平
  5. 創(chuàng)建時間:2014年12月14日
  6. 修改時間:
  7. 備    注:
  8. **************************************************************************************************/
  9. #include<reg52.h>                 //頭文件
  10. #include"Key_State.h"         //按鍵掃描頭文件

  11. sbit Led = P0^7;                 //LED燈輸出

  12. unsigned char Key_Number = 0; //按鍵值

  13. /********************************************************************************************
  14. 函數(shù)名稱:主程序
  15. 功    能:程序執(zhí)行的入口
  16. 返 回 值:無
  17. 時    間:2014-12-14        
  18. 備    注:
  19. **************************************************************************************************/
  20. void main()
  21. {
  22.    while(1)
  23.    {
  24.        Key_Number = read_key();        //調(diào)用按鍵掃描函數(shù),取得按鍵值,10MS調(diào)用一次,這里我沒有計時

  25.            if(Key_Number == 1)                //按鍵返回值是1
  26.            {
  27.               Led = ~Led;                        //LED燈取反
  28.            }
  29.    }
  30. }
復制代碼

Key_State.c
  1. #include<reg52.h>

  2. sbit key_sr1 = P1^6;  // 按鍵輸入口

  3. #define key_state_0        0   //按鍵的初始狀態(tài)
  4. #define key_state_1        1   //按鍵按下的狀態(tài)
  5. #define key_state_2        2   //按鍵釋放的狀態(tài)

  6. /********************************************************************************************
  7. 函數(shù)名稱:按鍵掃描程序
  8. 功    能:檢測按鍵,并返回按鍵值
  9. 返 回 值:key_press
  10. 時    間:2014-12-14        
  11. 備    注:
  12. **************************************************************************************************/
  13. unsigned char read_key(void)
  14. {
  15.     static char key_state = 0;     //按鍵的狀態(tài)
  16.     unsigned char key_press;       //按鍵是否被按下
  17.         unsigned char key_return = 0;  //按鍵返回值
  18.     key_press = key_sr1;         // 讀按鍵I/O電?
  19.    
  20.     switch (key_state)
  21.     {
  22.         case key_state_0:                 // 按鍵初始態(tài)
  23.                 if (!key_press)
  24.                 {
  25.                                 key_state = key_state_1;// 鍵被按下,狀態(tài)轉(zhuǎn)換到鍵確認態(tài)
  26.                         }
  27.                         break;
  28.                                 
  29.         case key_state_1:                   // 按鍵確認態(tài)
  30.             if (!key_press)
  31.             {
  32.                 key_return = 1;         // 按鍵仍按下,按鍵確認輸出為“1”
  33.                 key_state = key_state_2;// 狀態(tài)轉(zhuǎn)換到鍵釋放態(tài)
  34.             }
  35.             else
  36.             {
  37.                                 key_state = key_state_0; // 按鍵已抬起,轉(zhuǎn)換到按鍵初始態(tài)
  38.                         }
  39.             break;
  40.                                 
  41.         case key_state_2:
  42.             if (key_press)
  43.                         {
  44.                             key_state = key_state_0;//按鍵已釋放,轉(zhuǎn)換到按鍵初始態(tài)
  45.             }
  46.             break;
  47.    }
  48. return key_return;                            //返回按鍵值
  49. }
復制代碼

Key_State.h
  1. #ifndef __Key_State_H__
  2. #define __Key_State_H__

  3. unsigned char read_key(void);

  4. #endif
復制代碼


Key_State.zip (34.43 KB, 下載次數(shù): 1414)   

程序在這里下載


低調(diào),低調(diào)才是最牛逼的炫耀。。。。。。
由于水平能力有限,紕漏之處,不望各位讀者指出。。。。。。





作者: aabbcc    時間: 2014-12-15 02:27
大師的解說風趣幽默,簡單易懂。又學到了知識,謝謝,萬分感謝
作者: xiao_yp2014    時間: 2014-12-15 09:27
aabbcc 發(fā)表于 2014-12-15 02:27
大師的解說風趣幽默,簡單易懂。又學到了知識,謝謝,萬分感謝

希望對你有幫助,相互學習。。。。
作者: zouli415    時間: 2014-12-15 11:10
學習了
作者: xiao_yp2014    時間: 2014-12-15 11:36
zouli415 發(fā)表于 2014-12-15 11:10
學習了

相互學習,希望對你有幫助,。。。。
作者: zgs660429    時間: 2014-12-18 08:14
學習一下。
作者: xiao_yp2014    時間: 2014-12-18 08:23
zgs660429 發(fā)表于 2014-12-18 08:14
學習一下。

相互學習,希望對你有幫助,。。。。
作者: 1250455243    時間: 2014-12-21 22:03
好東西  贊一個
作者: 1250455243    時間: 2014-12-21 22:04
回去好好看
作者: shgdd520com    時間: 2014-12-24 22:46
好好研究下,聽說過狀態(tài)機按鍵很好,一直還沒學會,謝謝樓主講解。
作者: xiao_yp2014    時間: 2014-12-25 12:14
shgdd520com 發(fā)表于 2014-12-24 22:46
好好研究下,聽說過狀態(tài)機按鍵很好,一直還沒學會,謝謝樓主講解。

其實也不難,只是把一個按鍵,分成了幾個狀態(tài)。在不同的狀態(tài)下需要作不同的判斷。。。。
作者: wsx9711    時間: 2014-12-28 15:08
好東西  贊一個
作者: amgpj    時間: 2014-12-28 21:45
下載學習,謝謝分享
作者: ydmxyz    時間: 2015-2-5 22:31
下載學習,謝謝分享
作者: fontex    時間: 2015-2-7 08:49
學習了,謝謝!
作者: zrb5688    時間: 2015-2-7 15:03
學無止境,謝謝。
作者: 正本清源    時間: 2015-2-13 20:56
學習一下
作者: chenjun44369    時間: 2015-3-1 15:10
學習學習,
作者: DChan    時間: 2015-3-2 16:51
學習學習一下,謝謝樓主
作者: xdl    時間: 2015-3-3 22:42
又學到了知識,萬分感謝,太感動了
作者: fontex    時間: 2015-3-4 13:24
謝謝!
作者: 周安松    時間: 2015-3-5 06:31
l謝謝樓主講解
作者: 子慕love    時間: 2015-3-6 10:42
正好最近一直為這個問題煩憂,多謝分享;厝ヂ芯垦芯
作者: 飛蓬    時間: 2015-3-16 11:31
學習了,很好的方法
作者: zjjhy053341    時間: 2015-3-21 16:47
hehehe學習下
作者: zengmiao    時間: 2015-3-24 16:59
很不錯的思路
作者: likaienjoy    時間: 2015-7-21 22:02
支持長按么
作者: yufewng    時間: 2015-8-3 01:29
好東西啊,下來看看!~
作者: 騰飛的龍    時間: 2015-8-3 18:29
獨立按鍵,那矩陣按鍵呢?
作者: 袁潔棟    時間: 2015-8-4 09:13
已下載,看看,謝謝LZ
作者: nuptyangt    時間: 2015-8-5 13:15
正好需要,多謝摟住
作者: jnu1214    時間: 2015-8-6 20:37
正在學習,很好的資料,謝謝分享
作者: jnu1214    時間: 2015-8-6 20:38
很好的資料,代碼整潔,可讀性高,謝謝樓主
作者: 286458071    時間: 2015-8-8 10:18
很有用謝謝啦
作者: 神臨天下    時間: 2015-8-8 19:29
樓主問一下,這個程序是只可以掃描一個按鍵嗎?因為我只看到一個按鍵定義。還有正常的判斷按鍵是否按下的程序不是應該有檢測到按鍵按下之后有一個延時躲避抖動嗎?這樣的設(shè)計會使按鍵判斷不準確嗎?謝謝樓主,我小白一個……
作者: absflash    時間: 2015-8-10 17:18
看看是何神器,,贏得一樓如此美贊
作者: ivychiao    時間: 2015-9-1 10:04
最近在研究這個狀態(tài)機按鍵,下來看下
作者: ivychiao    時間: 2015-9-1 10:09
下下來看了一下,寫的很簡單明了,便于理解!
作者: lychengs    時間: 2015-9-16 08:42
感覺很有幫助,現(xiàn)在就是需要規(guī)范程序
作者: zhflyaa    時間: 2015-9-16 21:30
這個怎么用。我也下來看看
作者: scm_beginner    時間: 2015-9-16 22:17
正在學,很需要。謝了。
作者: wcx6270    時間: 2015-9-17 10:52
好東西,學習中
作者: sf116    時間: 2015-9-17 20:25
狀態(tài)機
作者: eclidtf    時間: 2015-9-19 06:51
不錯,這次直接上壓縮包了
作者: tt98    時間: 2015-10-25 12:28
看看怎樣區(qū)分長短按的?
作者: 曾為男人    時間: 2015-10-28 15:09
好東西  贊一個
作者: hzyong    時間: 2015-11-25 16:56
支持樓主!!!!!!
作者: zh3251241    時間: 2015-11-26 16:15
看看吧 和avr的一樣不
作者: yjansrg    時間: 2015-11-27 12:49
正好,看看能不能學到新知識
作者: 820784527    時間: 2015-12-4 16:29
  好屌
作者: ning    時間: 2015-12-9 12:28
學習學習,很好的樣子!
作者: ning    時間: 2015-12-9 12:29
為什么下載不了呢!

作者: ning    時間: 2015-12-9 12:46
終于下載了,謝謝樓主!正好需要!

作者: xiao_yp2014    時間: 2015-12-9 13:03
ning 發(fā)表于 2015-12-9 12:29
為什么下載不了呢!

需要登錄才可以下載。
作者: eqihfui··    時間: 2016-1-11 17:17
不錯不錯,看一下。以前知道這個就是沒去研究,還是自己在撲捉那幾個狀態(tài),弄得代碼有點長
作者: eqihfui··    時間: 2016-1-11 17:30
這個例子是不錯,再加個按鍵的入口參數(shù)會好一些,比較省事,不用每次都來更改按鍵定義
作者: xiao_yp2014    時間: 2016-1-12 09:50
eqihfui·· 發(fā)表于 2016-1-11 17:30
這個例子是不錯,再加個按鍵的入口參數(shù)會好一些,比較省事,不用每次都來更改按鍵定義

謝謝你的建議。
作者: wfzdx    時間: 2016-1-14 15:15
下載了,向樓主學習!
作者: 小易    時間: 2016-1-14 16:06
非常感謝樓主,我現(xiàn)在感覺延時消抖的按鍵程序不好用了,正好學習下你的
作者: 小易    時間: 2016-1-14 16:08
謝謝樓主的分享,我老是叫我不要用延時消抖,可我不會其他方法,正好學習下你的
作者: wjwjwjwj    時間: 2016-1-20 22:30
終于下載了,謝謝樓主!
作者: dnstwjc    時間: 2016-3-1 17:40
謝謝!第一次聽到"狀態(tài)按鍵"的說法。學習了。
作者: jovian_yu    時間: 2016-7-8 10:48
資料不錯,稍后評價,加好友不?qq2372696853
作者: FRING_HU    時間: 2016-7-17 22:30
你好,我定時器設(shè)置10MS中斷一次,有時按鍵按一下會響應兩次,我嘗試增加中斷時間到20MS,還是有這種現(xiàn)象,請問這個問題要怎么解決呢?
作者: FSLTKJ    時間: 2016-7-18 12:43
樓主,怎么沒有看到,防抖處理呢?
作者: xiao_yp2014    時間: 2016-7-21 09:33
FSLTKJ 發(fā)表于 2016-7-18 12:43
樓主,怎么沒有看到,防抖處理呢?

按鍵掃描在主程序里面,每次判定一種按鍵狀態(tài)后,都會到主程序里面去,這樣就會有延時,達到防抖的效果。
作者: xiao_yp2014    時間: 2016-7-21 09:34
FRING_HU 發(fā)表于 2016-7-17 22:30
你好,我定時器設(shè)置10MS中斷一次,有時按鍵按一下會響應兩次,我嘗試增加中斷時間到20MS,還是有這種現(xiàn)象, ...

這個中斷時間太快,到中斷時間調(diào)長,按鍵不需要這么多時間。
作者: xiao_yp2014    時間: 2016-7-21 09:35
小易 發(fā)表于 2016-1-14 16:08
謝謝樓主的分享,我老是叫我不要用延時消抖,可我不會其他方法,正好學習下你的

這是一個好方法。
作者: 024huayuan    時間: 2016-8-23 09:22
先來看看,
作者: aviro    時間: 2016-9-11 22:57
學習按鍵控制。
作者: bbxyzzj    時間: 2016-9-12 16:53
感謝!
作者: 883    時間: 2016-9-21 16:28
很好。但貌似沒有消抖作用,下載到實驗板試試,果真沒有。
作者: ctwarmer    時間: 2016-9-26 18:57
883 發(fā)表于 2016-9-21 16:28
很好。但貌似沒有消抖作用,下載到實驗板試試,果真沒有。

主程序while里加一個delay,可以起到消抖的作用(樓主注釋里已經(jīng)說了:“這里我沒有計時”)
--不知道我這樣理解對不對,初學者。
作者: xiao_yp2014    時間: 2016-9-27 09:13
ctwarmer 發(fā)表于 2016-9-26 18:57
主程序while里加一個delay,可以起到消抖的作用(樓主注釋里已經(jīng)說了:“這里我沒有計時”)
--不知道我 ...

不是這樣理解,這種方式只是一種掃描按鍵按下的狀態(tài),這個地方分為了三步,如果不是很明白,可以參考一下switch語句,這兒是有去抖動的,去抖動延時的時間,取決于你調(diào)用read_key();函數(shù)的時間。
作者: 883    時間: 2016-9-27 20:52
xiao_yp2014 發(fā)表于 2016-9-27 09:13
不是這樣理解,這種方式只是一種掃描按鍵按下的狀態(tài),這個地方分為了三步,如果不是很明白,可以參考一下 ...

哦,似乎明白了。也就是說,程序掃描時間必須大于按鍵抖動時間,謝謝樓主。
作者: ctwarmer    時間: 2016-9-30 14:40
xiao_yp2014 發(fā)表于 2016-9-27 09:13
不是這樣理解,這種方式只是一種掃描按鍵按下的狀態(tài),這個地方分為了三步,如果不是很明白,可以參考一下 ...

我想表達的意思,和您所述一樣。
去抖動的延時時間,取決于調(diào)用read_key()的時間,所以我說在主程序while里加一個delay。例如抖動時間為20ms,那么delay的時間大于等于20ms,也就相當于每20ms+去調(diào)用一次read_key()。
也許我表達的不夠嚴謹,delay()和sleep()我還沒太搞清楚?傊,如果是單線程,這里讓cpu睡個20ms+;如果是多線程,則每20ms+調(diào)度該線程一次就可以了。
去抖動應該是“去抖動邏輯”+“去抖動延時”,兩者不可缺一,這樣會否更嚴謹些,多謝指正。
作者: 袁潔棟    時間: 2016-10-12 22:00
下載,學習學習
作者: smallriver    時間: 2016-10-13 13:00
感覺太復雜,就一個簡單的按鍵何必寫那么多代碼,如果真的做一個項目,就一個簡單的按鍵就那么多代碼,那要是多幾個按鍵那還怎么辦、。不知道要寫多少了,還不如就用中斷或直接掃描按鍵就可以了
作者: 779613083    時間: 2016-10-14 00:40
回去好好看看
作者: 黑夜的星    時間: 2017-2-27 14:40
學習一下,
作者: aa1151953633    時間: 2017-3-14 09:46
已收藏,這個我之前也有玩過,不過你的寫得更簡潔
作者: sky6595418    時間: 2017-3-17 13:58
謝謝啊,
作者: 1033941024    時間: 2017-3-18 08:38
謝謝樓主分享,學習了
作者: goty2000    時間: 2017-4-1 19:21
哈哈  學習中,可以徹底擺脫 while(KEY==0); 了
作者: xiuyueyuan2013    時間: 2017-4-2 21:11
收藏了學習學習
作者: dzbj    時間: 2017-4-3 10:56
一直用這種方法 但這種方法有個問題是switch每次只執(zhí)行一個 完畢后跳出 下次再進入才又匹配執(zhí)行哪個分支 所以在程序多的時候效率很低

一般僅僅是按鍵檢測我是用if+bit一個標記來做 if一個語句開銷的cpu時間少 順序檢測一下再做個標記 整體比用狀態(tài)機快

多任務用狀態(tài)機更好
作者: asiont    時間: 2017-5-19 23:45
感謝Lzzzzzz
作者: TDS    時間: 2017-5-22 19:26
學習了
作者: zhang00956    時間: 2017-9-18 16:49
正好最近一直為這個問題煩憂,多謝分享。回去慢慢研究研究
作者: zhang00956    時間: 2017-9-18 17:24
非常好的東西值得學習
作者: 天使之淚雨揚    時間: 2018-1-4 21:44
學習了,以前不明白,現(xiàn)在終于豁然開朗
作者: liqinag750622    時間: 2018-1-15 08:47
好東西  贊一個
作者: 范兒——    時間: 2018-1-15 09:35
666,果然大佬。
作者: Quim11    時間: 2018-3-21 14:08
likaienjoy 發(fā)表于 2015-7-21 22:02
**** 作者被禁止或刪除 內(nèi)容自動屏蔽 ****

長按的話只需要在第二狀態(tài)里加個if(!key_press)里面弄個i來記進入該狀態(tài)的次數(shù),比如說記到100(100*10ms),及長按1s的時間,然后你就可以設(shè)置長按的動作了。
作者: bhjyqjs    時間: 2018-3-23 09:22
狀態(tài)機檢測按鈕程序?qū)懙倪是很好的,條理清晰,注釋清楚,很不錯。但在主程序中反復檢測按鈕,就有些違背樓主設(shè)計初衷了,手一抖,就是幾次按鍵了。應該設(shè)計一個10mS的定時,在定時中斷里調(diào)用按鍵檢測程序。
作者: zhnjun63    時間: 2018-3-23 16:56
sbit key_sr1 = P1^6;  // 按鍵輸入口

這是只有一個按鈕的情況下的編程,現(xiàn)實應用中,使用一個按鈕的應用極少。如果按鈕多于2個,這個程序應該如何擴展?

求賜教!
作者: qq3417    時間: 2018-4-14 21:21
謝謝分享
作者: 奮斗de小青年    時間: 2018-4-14 21:49
對于狀態(tài)機我更多是在FPGA中用到,在單片機中使用我倒是第一次看到,感覺很不錯
作者: 熱帶雨林    時間: 2018-4-14 23:41
不錯,值得學習
作者: 持勤補拙    時間: 2018-4-15 00:21
學習了,感謝大師




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1