标题: 状态机按键扫描,看懂了会增长你的功力。。。。 [打印本页]

作者: xiao_yp2014    时间: 2014-12-14 21:19
标题: 状态机按键扫描,看懂了会增长你的功力。。。。
本帖最后由 xiao_yp2014 于 2016-1-21 14:37 编辑

大家好!我叫肖亚平,从小热爱上了电子技术,读书时阴差阳错的选择了电子这方面的专业,学习电子技术。对于我的理解来说,学校里面学到的技术不是全部实用,但是必须有用,所以一直奋斗在前线。我对学习总结出一句话“压力不是有人努力,而是比你牛X N倍的人依然在努力
说在前面:
              做单片机开发少不了的就是通过按键和单片机交流,按键是单片机交流的一个桥梁,所以状态机按键扫描犹如嵌入式一样的火爆,在网上一搜一大把,一说起按键,学了单片机的人都知道有个叫做“状态机扫描的方法”,这个方法确实比其它的按键方法要好得多,我记得在星期五的一个下午,一个网友叫我帮他调一个程序,他当时说按下按键显示就不显示了,我一想,按键肯定有问题,我打开程序一看,里面居然还有像这样的语句存在“ while(!Key); ”这明显是给自己找麻烦,给CPU挖陷阱嘛,下面分享一个状态机的按键扫描方法,据说这种方法是实时最高的,今天我也是亲自试过,确定如此。





程序如下:main.c
  1. /********************************************************************************************
  2. 名    称:状态机按键扫描
  3. 功    能:运用状态机思想,实现按下按键LED点亮,再按一下LED灯熄灭。
  4. 作    者:肖亚平
  5. 创建时间: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. 函数名称:主程序
  15. 功    能:程序执行的入口
  16. 返 回 值:无
  17. 时    间:2014-12-14        
  18. 备    注:
  19. **************************************************************************************************/
  20. void main()
  21. {
  22.    while(1)
  23.    {
  24.        Key_Number = read_key();        //调用按键扫描函数,取得按键值,10MS调用一次,这里我没有计时

  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   //按键的初始状态
  4. #define key_state_1        1   //按键按下的状态
  5. #define key_state_2        2   //按键释放的状态

  6. /********************************************************************************************
  7. 函数名称:按键扫描程序
  8. 功    能:检测按键,并返回按键值
  9. 返 回 值:key_press
  10. 时    间:2014-12-14        
  11. 备    注:
  12. **************************************************************************************************/
  13. unsigned char read_key(void)
  14. {
  15.     static char key_state = 0;     //按键的状态
  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:                 // 按键初始态
  23.                 if (!key_press)
  24.                 {
  25.                                 key_state = key_state_1;// 键被按下,状态转换到键确认态
  26.                         }
  27.                         break;
  28.                                 
  29.         case key_state_1:                   // 按键确认态
  30.             if (!key_press)
  31.             {
  32.                 key_return = 1;         // 按键仍按下,按键确认输出为“1”
  33.                 key_state = key_state_2;// 状态转换到键释放态
  34.             }
  35.             else
  36.             {
  37.                                 key_state = key_state_0; // 按键已抬起,转换到按键初始态
  38.                         }
  39.             break;
  40.                                 
  41.         case key_state_2:
  42.             if (key_press)
  43.                         {
  44.                             key_state = key_state_0;//按键已释放,转换到按键初始态
  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, 下载次数: 1414)   

程序在这里下载


低调,低调才是最牛逼的炫耀。。。。。。
由于水平能力有限,纰漏之处,不望各位读者指出。。。。。。





作者: aabbcc    时间: 2014-12-15 02:27
大师的解说风趣幽默,简单易懂。又学到了知识,谢谢,万分感谢
作者: xiao_yp2014    时间: 2014-12-15 09:27
aabbcc 发表于 2014-12-15 02:27
大师的解说风趣幽默,简单易懂。又学到了知识,谢谢,万分感谢

希望对你有帮助,相互学习。。。。
作者: zouli415    时间: 2014-12-15 11:10
学习了
作者: xiao_yp2014    时间: 2014-12-15 11:36
zouli415 发表于 2014-12-15 11:10
学习了

相互学习,希望对你有帮助,。。。。
作者: zgs660429    时间: 2014-12-18 08:14
学习一下。
作者: xiao_yp2014    时间: 2014-12-18 08:23
zgs660429 发表于 2014-12-18 08:14
学习一下。

相互学习,希望对你有帮助,。。。。
作者: 1250455243    时间: 2014-12-21 22:03
好东西  赞一个
作者: 1250455243    时间: 2014-12-21 22:04
回去好好看
作者: shgdd520com    时间: 2014-12-24 22:46
好好研究下,听说过状态机按键很好,一直还没学会,谢谢楼主讲解。
作者: xiao_yp2014    时间: 2014-12-25 12:14
shgdd520com 发表于 2014-12-24 22:46
好好研究下,听说过状态机按键很好,一直还没学会,谢谢楼主讲解。

其实也不难,只是把一个按键,分成了几个状态。在不同的状态下需要作不同的判断。。。。
作者: 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
楼主问一下,这个程序是只可以扫描一个按键吗?因为我只看到一个按键定义。还有正常的判断按键是否按下的程序不是应该有检测到按键按下之后有一个延时躲避抖动吗?这样的设计会使按键判断不准确吗?谢谢楼主,我小白一个……
作者: absflash    时间: 2015-8-10 17:18
看看是何神器,,赢得一楼如此美赞
作者: ivychiao    时间: 2015-9-1 10:04
最近在研究这个状态机按键,下来看下
作者: ivychiao    时间: 2015-9-1 10:09
下下来看了一下,写的很简单明了,便于理解!
作者: lychengs    时间: 2015-9-16 08:42
感觉很有帮助,现在就是需要规范程序
作者: 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
状态机
作者: eclidtf    时间: 2015-9-19 06:51
不错,这次直接上压缩包了
作者: tt98    时间: 2015-10-25 12:28
看看怎样区分长短按的?
作者: 曾为男人    时间: 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 发表于 2015-12-9 12:29
为什么下载不了呢!

需要登录才可以下载。
作者: eqihfui··    时间: 2016-1-11 17:17
不错不错,看一下。以前知道这个就是没去研究,还是自己在扑捉那几个状态,弄得代码有点长
作者: eqihfui··    时间: 2016-1-11 17:30
这个例子是不错,再加个按键的入口参数会好一些,比较省事,不用每次都来更改按键定义
作者: xiao_yp2014    时间: 2016-1-12 09:50
eqihfui·· 发表于 2016-1-11 17:30
这个例子是不错,再加个按键的入口参数会好一些,比较省事,不用每次都来更改按键定义

谢谢你的建议。
作者: wfzdx    时间: 2016-1-14 15:15
下载了,向楼主学习!
作者: 小易    时间: 2016-1-14 16:06
非常感谢楼主,我现在感觉延时消抖的按键程序不好用了,正好学习下你的
作者: 小易    时间: 2016-1-14 16:08
谢谢楼主的分享,我老是叫我不要用延时消抖,可我不会其他方法,正好学习下你的
作者: wjwjwjwj    时间: 2016-1-20 22:30
终于下载了,谢谢楼主!
作者: dnstwjc    时间: 2016-3-1 17:40
谢谢!第一次听到"状态按键"的说法。学习了。
作者: jovian_yu    时间: 2016-7-8 10:48
资料不错,稍后评价,加好友不?qq2372696853
作者: FRING_HU    时间: 2016-7-17 22:30
你好,我定时器设置10MS中断一次,有时按键按一下会响应两次,我尝试增加中断时间到20MS,还是有这种现象,请问这个问题要怎么解决呢?
作者: FSLTKJ    时间: 2016-7-18 12:43
楼主,怎么没有看到,防抖处理呢?
作者: xiao_yp2014    时间: 2016-7-21 09:33
FSLTKJ 发表于 2016-7-18 12:43
楼主,怎么没有看到,防抖处理呢?

按键扫描在主程序里面,每次判定一种按键状态后,都会到主程序里面去,这样就会有延时,达到防抖的效果。
作者: xiao_yp2014    时间: 2016-7-21 09:34
FRING_HU 发表于 2016-7-17 22:30
你好,我定时器设置10MS中断一次,有时按键按一下会响应两次,我尝试增加中断时间到20MS,还是有这种现象, ...

这个中断时间太快,到中断时间调长,按键不需要这么多时间。
作者: xiao_yp2014    时间: 2016-7-21 09:35
小易 发表于 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 发表于 2016-9-21 16:28
很好。但貌似没有消抖作用,下载到实验板试试,果真没有。

主程序while里加一个delay,可以起到消抖的作用(楼主注释里已经说了:“这里我没有计时”)
--不知道我这样理解对不对,初学者。
作者: xiao_yp2014    时间: 2016-9-27 09:13
ctwarmer 发表于 2016-9-26 18:57
主程序while里加一个delay,可以起到消抖的作用(楼主注释里已经说了:“这里我没有计时”)
--不知道我 ...

不是这样理解,这种方式只是一种扫描按键按下的状态,这个地方分为了三步,如果不是很明白,可以参考一下switch语句,这儿是有去抖动的,去抖动延时的时间,取决于你调用read_key();函数的时间。
作者: 883    时间: 2016-9-27 20:52
xiao_yp2014 发表于 2016-9-27 09:13
不是这样理解,这种方式只是一种扫描按键按下的状态,这个地方分为了三步,如果不是很明白,可以参考一下 ...

哦,似乎明白了。也就是说,程序扫描时间必须大于按键抖动时间,谢谢楼主。
作者: ctwarmer    时间: 2016-9-30 14:40
xiao_yp2014 发表于 2016-9-27 09:13
不是这样理解,这种方式只是一种扫描按键按下的状态,这个地方分为了三步,如果不是很明白,可以参考一下 ...

我想表达的意思,和您所述一样。
去抖动的延时时间,取决于调用read_key()的时间,所以我说在主程序while里加一个delay。例如抖动时间为20ms,那么delay的时间大于等于20ms,也就相当于每20ms+去调用一次read_key()。
也许我表达的不够严谨,delay()和sleep()我还没太搞清楚。总之,如果是单线程,这里让cpu睡个20ms+;如果是多线程,则每20ms+调度该线程一次就可以了。
去抖动应该是“去抖动逻辑”+“去抖动延时”,两者不可缺一,这样会否更严谨些,多谢指正。
作者: 袁洁栋    时间: 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每次只执行一个 完毕后跳出 下次再进入才又匹配执行哪个分支 所以在程序多的时候效率很低

一般仅仅是按键检测我是用if+bit一个标记来做 if一个语句开销的cpu时间少 顺序检测一下再做个标记 整体比用状态机快

多任务用状态机更好
作者: 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
学习了,以前不明白,现在终于豁然开朗
作者: liqinag750622    时间: 2018-1-15 08:47
好东西  赞一个
作者: 范儿——    时间: 2018-1-15 09:35
666,果然大佬!!
作者: Quim11    时间: 2018-3-21 14:08
likaienjoy 发表于 2015-7-21 22:02
**** 作者被禁止或删除 内容自动屏蔽 ****

长按的话只需要在第二状态里加个if(!key_press)里面弄个i来记进入该状态的次数,比如说记到100(100*10ms),及长按1s的时间,然后你就可以设置长按的动作了。
作者: bhjyqjs    时间: 2018-3-23 09:22
状态机检测按钮程序写的还是很好的,条理清晰,注释清楚,很不错。但在主程序中反复检测按钮,就有些违背楼主设计初衷了,手一抖,就是几次按键了。应该设计一个10mS的定时,在定时中断里调用按键检测程序。
作者: zhnjun63    时间: 2018-3-23 16:56
sbit key_sr1 = P1^6;  // 按键输入口

这是只有一个按钮的情况下的编程,现实应用中,使用一个按钮的应用极少。如果按钮多于2个,这个程序应该如何扩展?

求赐教!
作者: qq3417    时间: 2018-4-14 21:21
谢谢分享
作者: 奋斗de小青年    时间: 2018-4-14 21:49
对于状态机我更多是在FPGA中用到,在单片机中使用我倒是第一次看到,感觉很不错
作者: 热带雨林    时间: 2018-4-14 23:41
不错,值得学习
作者: 持勤补拙    时间: 2018-4-15 00:21
学习了,感谢大师




欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1