按键切换状态的不同C写法对比
2017-01-24 19:35
330 查看
一个容易被忽视却并不简单的问题
给定一个按键,以及一个状态输出(如一个LED),按下一次按键后LED灯改变一次状态,再按一次按键LED再次切换状态,这是嵌入式编程中一个很简单的任务,但要想达到很好的效果并不容易,一下对比几种C写法(以arduino为例):程序一
bool buttonState = 1; bool x = 1; void loop(){ buttonState = digitalRead(buttonPin);//read the key button if (buttonState == LOW && x==1) { digitalWrite(LedPin , 1); //light the led x=0; } else if (buttonState == LOW && x==0){ digitalWrite(LedPin, 0); //off the led x=1; } delay(1); }
这种写法使用一个x变量来希望使得每次按键后切换一次led状态,但这个程序有一个问题是当按键按下时间较长时,程序会不断进入判断并不断切换led的状态,导致每次按下按键后led都会闪烁多次,松开后的状态也是随机的,尽管可以通过增加两次判断的延时稍稍改善,但改善效果很低,过大的时延也使得其他程序和按键本身响应速度降低,基本是不可取的。
程序二
bool newbuttomState = 1; bool oldbuttonState = 1; bool ledState = 1; void loop() { newbuttonState = digitalRead(buttonPin); //read current key if (newbuttonState == LOW && oldButtonState == HIGH) //key pin must from high to low, can work even the key is press without a break { delay(100); newbuttonState = digitalRead(buttonPin); if (newbuttonState == LOW && oldButtonState == HIGH) { ledState = !ledState; digitalWrite(ledPin, ledState); } } oldButtonState = newbuttonState; //record the old key state }
程序二通过检测按键之前的状态,每次切换led时都需要判断按键之前的状态(高电平)和按下的状态(低电平)同时满足。这样效果比程序一要好了很多,即使按键一直被按下也不会反复进入判断语句切换led的状态,同时考虑到按键消抖,每次判断后延时一段时间,再判断一次。这个程序本身应该考虑比较周全了,但实际试验中发现,当按下按键时间较长时再松开,led常常出现连续开关两次,且改变延时时间仍然不能有所改善,仔细考虑和查阅一些资料后,改进为第三种程序写法,终于得到比较好的效果
程序三
bool newbuttomState = 1; bool oldbuttonState = 1; bool ledState = 1; void loop() { newbuttonState = digitalRead(buttonPin); if (newbuttonState == LOW && oldButtonState == HIGH) { ledState = !ledState; digitalWrite(ledPin, ledState); } oldButtonState = newbuttonState; delay(1); //the delay'position is very very important }
程序三和程序二似乎没有什么区别,而且反而还去掉了按下状态延时消抖的语句,似乎应该反而效果不如程序二,但实际上我用一个抖动很差的开关做了多次试验的结果是,程序三基本达到了接近完美的效果。响应非常迅速而几乎没有出现过任何错误(程序二大约会出现一半的错误响应)。
这其中的奥秘到底在哪呢,仔细观察程序三,除了去掉了按键按下的再次判断的延时消抖,唯一的区别就是在末尾加了一个时延语句,而正是这个延时语句的位置使得它有着远远优于程序二的效果。
原因在于实际中使用的物理按键的抖动特点。实际上大多数常用按键在按下时(触点闭合)的抖动并不显著,而抖动主要出现在按下后松开的阶段(触点离开),这个大家可以自己用示波器做一些相关实验(以后有时间我可以另外开帖用示波器做一系列试验)。因此基于这个特点,我在程序末尾,即按键松开后的阶段添加一个延时就可以有效防止松开阶段的抖动影响,这个延时值很小,对于我用的按键,我设置延时1ms就有很好的效果。而我又尝试将按下阶段的消抖语句去除,发现没有任何影响。
相关文章推荐
- 几种不同oracle数据库启动方式的对比,及启动状态的切换、查询
- hadoop-2.6.0+zookeper-3.4.6之HA模式两个namenode不同状态active和standby的切换
- Vim实战手册(2)常用的状态切换按键
- Button按钮实现按下不同状态切换功能
- Portlet通过标签在不同的模式(PortletMode)窗口状态间切换
- mfc按键显示不同状态背景
- UIButton 不同状态图片来回切换
- Vim实战手册(2)常用的状态切换按键
- Qt自定义按钮及不同状态下图片的切换
- Vim实战手册——常用的状态切换按键
- Android 让你的布局飞起来 -View切换显示不同的状态
- 基于Java语言的安卓编程之十一状态切换按键的实现
- Gtk+实现非规则按钮的不同状态图片切换
- C# 不同状态下鼠标状态的切换
- 小功能:下拉框里为不同的7天,复选框里为旅游点,每一天可以选择多个旅游点,每一天已选择的点其他天不能选,切换下拉框,当天选择好的点为以勾选状态
- android:Activity中切换不同状态页:加载中,加载失败,数据页,空页面……
- 关于android中尺寸的获取,获取自定义属性值, 切换状态的标准写法
- Android 视图不同状态下的轻松切换 特别适用于listview
- 按键通过css切换状态
- 用ToggleButton和ImageView实现不同状态下显示的切换