自学单片机第二十二篇:延时消抖
按键的延时消抖是初学单片机的必经之路,因为只要是机械开关所传递的信号,都会存在波动,有时这些波动是"致命"的,所以消除其影响就是一门手艺了。硬件消抖有其优点,同样的也有不方便的地方,开发成本高,操作难度大,可移植性差。软件消抖就相对较好些,新手即可操作,延时消抖,并非消抖的最终最优方法,但好在简单易懂,我们先认识消抖的方法和目的。
按键在按下和抬起时,都会出现短暂的抖动,称之为前沿抖动和后沿抖动,他们持续的时间大致在5-10毫秒,键稳定时间会在100毫秒以上,就人的操作速度来看,键稳定的时间不会低于100毫秒,因为,1秒十次的操作,估计手都受不了。除非科幻世界或武侠世界的人。
既然抖动时间基本不变,那么,我们就有这样一种方法,当按键出现第一个电位变化,假设是高电位转变成低电位,那么我们就延时一段时间,设置10毫秒,10毫秒以后,我们再次判断此时的电位状态,是否是低电位,如果是低电位,那么就认为按键按下了,如果是高电位,就认为按键是抖动。从低电位变成高电位也是一样。
我们就是用延时来,把抖动的时间空过去了,这样就不用担心抖动产生的电位频繁变化了。接下来,我们看下程序如何写。
按流程来,基本上就能写出来,程序分为两大块,一个是主函数,处理开关状态,一个是延时函数。
我们先定义一个开关,然后我又声明了一个位变量,其实这个位变量在这里可以不用,不过习惯如此,对采集来的数据我习惯让其保存在特定的变量中,这样方便后期使用,以防自己改变变量值,造成端口的电位随之改变。
主函数中,先把开关采集端口置1,这是读取数据的前提条件,然后把需要采集的io的状态转移给中间变量,接着判断此时中间变量是否为零,也就是按键是否按下,如果没有按下,那就跳出,继续赋值,接着判断,直到判断为零,进入语句中,先延时一段时间,让抖动空过去,延时结束,再判断一次,由于此时程序还没走出去,所以中间变量的值也没有实时切换,我们此时要判断按键实时状态是否为零,就需要判断端口的实际值,当key10为零,就说明按键确实处于按下状态,这就可以执行,移位指令。
需要说明,如果使用函数,在调用时,只需写出函数名即可。但是在程序最开始位置,需要声明函数,声明时,要写全,尤其是返回值的类型和变量名,不能省略。可以把函数直接复制到前方,然后加一个冒号即可。
程序看完,我们仿真一下测试下程序是否执行。
这是之前我们使用的仿真电路,直接使用就好。我没有改变工程文件,所以无需重新导入可执行文件,程序会直接读取我保存好的新的可执行文件,文件名没有改变。
这是软件的初始状态,所有端口都是高电位,我们按下P10.
按键随着按下,可以稳定的响应,我们再通过实际电路测试一下。
测试发现,我按下按键,还没松手,就已经流水般的熄灭了5个灯了,什么情况?
我们可以看程序的这里
keybuff=key10; //赋值
if(keybuff==0) //判断开关是否按下
{
delay(50); //延时一段时间
if(key10==0) //再次判断开关是否按下
{
P3=P3>>1; //P3左移一位
}
}
从这一段可以看出,只要我能满足keybuff为零,key10为零,那么程序就会在延时结束再次进入程序,如此循环,就造成了,按键按下,P3被连续执行动作。我们怎么才能让这种情况不发生呢?这就需要我们不仅检测按键按下,还需要检测按键弹起,只有按键弹起我们才允许它执行下一步,这样就能按下一次,抬起手,才会停止,保证了操作的准确。
执行流程如下:
判断按键按下》按键按下》延时》判断按键按下》按键按下》执行动作》判断按键抬起》按键抬起》结束。
我们再次测试,此时发现,按下后,不松开,按键不再连续动作,但是松开按键后,原本熄灭的小灯又点亮了,我们梳理程序,可以发现,是不存在错误的,流程也没有问题。其实这就涉及我们的硬件了,我们使用软件仿真时,这些问题都是没有的,但硬件跟仿真的区别就在这里,在单片机中,如果我们没有规定执行下一步的位置,单片机就会在流程走完后,随机进入我们无法控制的流程,这在专业中称之为跑飞。为了防止跑飞,我们一般会在结束添加循环语句,让程序停止在我们设定的位置,这样就不会有问题了。
此处我们需要连续监测按键状态,所以就让程序不断的循环判断按键即可。
再次测试,一切就按照程序执行了,动作也正常了。
这就是为什么我们之前的测试程序,都会在主函数中添加循环的作用。通过这个示例,也是告诉大家,仿真只是学习的方法,最终目的还是要在实际的硬件上进行。不然你永远不知道自己的程序能不能完成真正的功能,设计不能光纸上谈兵哦。
单片机键盘消抖“独门”汇编方案分享,不用延时还能用什么?
用单片机或ARM做的产品经常会遇到有键盘输入的产品,而键盘输入有一个绕不过去的问题就是:键盘去抖。见下图
当按键开关闭合或者断开时各有一段电平不稳定的时期,按键开关在闭合时不会马上就稳定的接通,在断开时也不会一下子彻底断开,而是在闭合和断开的瞬间伴随了一连串的电平抖动。这种抖动一般都在 10ms 左右。为了确保程序对按键的一次闭合或者一次断开只响应一次,必须进行按键的去抖处理。当检测到按键状态变化时,不是立即去响应动作,而是先等待闭合或断开稳定后再进行处理。
按键去抖方法可分为硬件去抖和软件去抖,硬件去抖不在本文的讨论中,本文只讨论软件去抖。
一般的软件去抖就是程序在检测到按键闭合或断开时调用一段延时子程序(在 C 语言中叫函数),程序在此死等 10ms 或更长。延时过后再检测按键的状态是否与延时前的状态一致,若一致就执行键盘程序部分,若不一致,则跳过执行键盘程序。
这种方法在程序工作量不是很大时是没有问题的。但在一些 CPU负荷量比较大的程序中,特别是在一些程序运转中有比较多的在不确定时间就会发生的中断的情况下(外部中断、串口中断、定时器中断等),在这里死等,就有可能造成某部分程序不能很好地被执行,甚至程序跑飞等严重问题。
本人经过多年的编程,总结了一套解决这问题的方法,供大家参考。
程序是用 51 汇编语言写的,大家若要用 C 语言编写,参考这流程图改一下就成。
先解释这流程图中的变量和子程序:
KSTEP:步进指示变量,当程序从主程序进入到此子程序后,立刻根据这 KSTEP 的值跳到相应的程序段。
KEYSCAN:读键盘子程序,若你的按键数量不多的话,直接读 IO 口。按键数量多的话,就要用矩阵方式读键盘,这里不作赘述。
HASK:位变量,读键盘子程序中的位变量,当读键盘子程序 KEYSCAN 检测到有键闭合时置“1”,反之置“0”。
R2:键值变量,读键盘子程序 KEYSCAN 读出的键值。
KVALU:键值变量,R2 的键值送到这里,供此子程序下一次判断或主程序使用。
K20MS:20ms 计时器变量,当第一次检测到有键闭合时往里面送值 10。程序初始化中设定定时器中断为 2ms 时间间隔。进入定时器中断后,首先判断 K20MS 是否为 0?若为 0 则直接退出定时器中断;若不为 0 则将 K20MS 减 1 后再退出定时器中断。这样 K20MS 变量从 10 减到 0 时间为 20ms。键断开时也是一样地执行。
KAVA:位变量,告诉主程序:键闭合(断开)有效。
程序解释:
1. 程序初始化时 KSTEP 的值为 0,所以一进入本子程序,程序马上就跳到标号 KSC0 处,在此处调用读键盘子程序 KEYSCAN。
1.1 从 KEYSCAN 出来后,若位变量 HASK 的值为 0,说明没有键闭合,程序直接跳到标号 RET 处退出。
1.2 若位变量 HASK 的值为 1,就是有键闭合,此时将数值 1 送入步进指示变量 KSTEP 中,便于下次进入本子程序时,程序直接跳到标号 KSC1 处。再将从 KEYSCAN 子程序读出来的键值送入变量 KVALU 中,用于下次再调用读键盘子程序 KEYSCAN 时与 R2 读出的键值进行比较。
最后将数值 10 送入 20ms 计时器变量 K20MS 中,用于 2ms 定时器中断后减 1,然后退出子程序。
2. 当主程序再次调用本子程序时,程序马上就跳到标号 KSC1 处。
2.1 在此处首先判别 20ms 计时器变量 K20MS 是否减到 0(也就是判别 20ms 延时到了没有?),若 K20MS 不为 0(20ms 延时还没有到),则立即退出。
2.2 若 K20MS 为 0(说明 20ms 延时时间到了),再次调用读键盘子程序 KEYSCAN。调用 KEYSCAN 子程序后,再次判别位变量 HASK 是否有效?
2.2.1 若 HASK 无效,说明上次(KSC0 处)可能是受到一次干扰。于是复位 KSTEP(清 0),退出。使下次调用本程序时,又从头开始。
2.2.2 若 HASK 有效,则将这次从 KEYSCAN 读出的键值与上次读出并存在 KVALU 中的键值进行比较。
2.2.2.1 若比较值不同,则程序跳到标号 KE1 处,将新的键值存入 KAVALU 中,20ms 后再调用 KEYSCAN 子程序,再次比较。
2.2.2.2 若比较值相同,则说明本次键闭合有效,于是置位 KAVA(当主程序是键按下执行时),告诉主程序,键闭合有效,可以执行此键所要做的程序了。同时将数值 2 送入步进指示变量 KSTEP 中,便于下次进入本子程序时,程序直接跳到标号 KSC2 处。最后将数值 10 送入 20ms 计时器变量 K20MS 中,在下次进入 KSC2 标号处,也得等 20ms 之后再判别键是否断开。
3. 现在主程序调用本子程序时,程序马上就跳到标号 KSC2 处,在此也一样,首先判别 20ms 计时器变量 K20MS 是否减到 0(也就是判别 20ms 延时到了没有?),若 K20MS 不为 0(20ms 延时还没有到),则立即退出。若 K20MS 为 0,调用读键盘子程序 KEYSCAN。
调用 KEYSCAN 子程序后,判别位变量 HASK 是否有效?
3.1 若 HASK 无效,说明按键可能被释放断开,于是将数值 3 送入步进指示变量 KSTEP 中,便于下次进入本子程序时程序可以直接跳到标号 KSC3 处。最后将数值 10 送入 20ms 计时器变量 K20MS 中,在下次进入 KSC3 标号处,也得等 20ms 之后再判别键是否继续断开状态。
3.2 若 HASK 有效,说明按键继续闭合状态,再比较 KEYSCAN 读出的键值与上次读出在 KVALU 中的键值进行比较。
3.2.1 若比较值不同,则程序跳到标号 KE0 处,重新开始。
3.2.1 若比较值相同,则说明按键还没有断开,继续将数值 10 送入 20ms 计时器变量 K20MS 中,等 20ms 之后再进入标号 KSC2 处,再次判别按键是否断开。
4. 当主程序调用本子程序时,程序程序马上跳到标号 KSC3 处,还是首先判别 20ms 计时器变量 K20MS 是否减到 0,若 K20MS 不为 0(20ms 延时还没有到),则立即退出。若 K20MS 为 0,调用读键盘子程序 KEYSCAN。
调用 KEYSCAN 子程序后,判别位变量 HASK 是否有效?
4.1 若 HASK 无效,说明按键已经完全释放断开,于是将数值 0 送入步进指示变量 KSTEP 中,便于下次进入本子程序时,程序从头开始,同时置位 KAVA(当主程序是键释放执行时),告诉主程序,键释放有效,可以执行此键所要做的程序了。
4.2 如果位变量 HASK 继续有效,说明又有键闭合了(虽然这种概率比较小,但程序得编进去),根据新键值与老键值的相同与不同,分别跳到标号 KE3 处,或者标号 KE0 处执行。
说明:KE3 标号和 KE7 标号下面都有 SETBKAVA,实际编程时只用一次,根据你的主程序是在键按下执行还是键释放执行选用。
本程序的特点就是:在等键闭合或断开去抖的那 20ms 时间,不是死等,而是做好标记及置好必要的变量值后立即退出到主程序去做其他事情。程序每次从进入到退出这个子程序中所花的时间一般为十几微秒(不含读键盘子程序 KEYSCAN 所花的时间,KEYSCAN 花的时间根据按键数量的多少而不同,一般为几个微秒到几十微秒)。
相关问答
51 单片机 ,用按键实现外部中断,软件如何去抖?定时中断里设置一个记录按下时间的static变量t按下按键则将t++(注意不要加到溢出)松开按键,检测tt定时中断里设置一个记录按下时间的static变量t按下...
单片机 程序:用一个开关按钮控制一个灯,... -ZOL问答直接把电源接给单片机不太好,建议稍微改下电路有用(0)回复那个可以用~~~有用(0)回复程序里按键检测应该加延时消抖,在第一个if()下面加延时10毫秒,再检测...
51 单片机 按键释放时候为什么不用消抖?释放就释放了,程序只管往下走,抖动又有什么关系由于按键按下有消抖,所以按键释放的抖动绝对不会又被当作按键按下的信号按键按实了,就不会抖动既然检测...
单片机 按键去抖啥意思?单片机按键去抖,就是单片机的按键在正常操作中在按压过程时不能一下完全接通,就是按压抖动,单片机在接收这种信息时会判断错误,所有要去掉这种抖动因...
谢谢!如果真是从电源线回流冲击 单片机 ,应如何清除该电磁波呢?在单片机的电源上多做功夫:1.单片机使用独立变压器供电,而且变压器初级并联0.1u~250V以上的电容,同时最好串上二型滤波线圈,消除高频电磁波.2.在低压端最好...
单片机 用的无线遥控器按一下相当桉几下怎么像按键一样消抖?按键前,后都会有抖动,所以前后都要加延时效果会好一些,还有一种可能是芯片速度快,导致多次识别按键,你可以在识别一次后加一个标志位按键前,后都会有抖动,所...
单片机 的按键开关抖动的产生原因,抖动的特点和如何消除抖动 ...——如果是就判定打开,软件解决可以降低成本,但是有时候硬件劣化超出延时的范围会造成故障。硬件解决:专用的去抖芯片或者自己组装一个双稳态消抖电...
能否说明独立式键盘的特点及适用场合,是如何用软件法消除按键的?朋友们好,我是电子及工控技术,我来回答这个问题。键盘作为一种输入设备,它是人机交换的重要入口。通过键盘的机械按键的断开与闭合可以向单片机输入各种命令和...
单片机 33v供电干扰怎么解决?单片机供电电源出现干扰纹波,消除的方法如下:1、在交流电源端加装交流电源滤波器。2、直流电源加设LC滤波电路。3、在直流电源输出端加大滤波电容,消除电路...
单片机 51,出现按一次按键,得到多次按键的情况,怎么处理-ZOL问答delayxms(15);//消除抖动if(key==0)//再次判断{while(key==0);//等待按键释...不玩网游和单机,至多玩棋牌游戏和影音。喜欢摄影,需要修图。附加:纠结...