您的位置:首页 > 编程语言 > C语言/C++

按键切换状态的不同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就有很好的效果。而我又尝试将按下阶段的消抖语句去除,发现没有任何影响。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息