当你拨动开关或按下按钮时,两个金属触点就会合在一起。看起来它们会立即接触并完成一个电路。然而,在现实中,当它们接触时,它们会机械地反弹,在建立牢固的联系之前,会进行几次短暂的接触。在某些情况下,如果由于开关接触不良或腐蚀而产生电弧,这种反弹也可能是电性质的。这种反弹可能会导致一些电路出现问题,这将导致硬件不正确地读取多个开关按下,而实际上只有一个发生。我们通过解除电路来解决这个问题!
解码器可以在硬件或软件中完成,每种方法都有各自的优缺点。我们会介绍两种方法并讨论它们的区别。
开关反弹特征
我们首先需要了解开关弹跳及其特性。这并不是一项简单的任务,因为它看起来!这是因为不同的开关有不同的反射特性。即使两个完全相同的开关也会有不同的弹跳!
许多人还认为弹跳只是瞬时开关的问题,但事实是弹跳影响所有类型的瞬时和维护开关,包括切换、锁存和摇杆开关。
如果我们拿出可靠的示波器,我们就可以看到屏幕上发生的弹跳!
在这个例子中,我使用了一个简单的瞬间切换Arduino Starter Kit.你可以看到开关在保持稳定接触之前弹了两次。许多电路可以将此解释为多次按压,即使你只按了一次开关。不是很好!
在第二个例子中,我使用了我为移除LCD面板按钮购买的一个瞬时开关桌面商场建立.这个开关在保持稳定之前到处弹跳!
所以你可以看到为什么关闭开关是如此重要!
很多电子初学者通常开始在网上搜索电路的问题,但他们没有意识到开关反弹是他们的问题,因为他们甚至不知道这可能是一个问题。提示:这很常见!
这里是我们弹跳开关的电路原理图,没有去振硬件到位:
消除抖动在硬件
解除开关最常见的方法是在硬件中进行。这涉及到在电路中添加一个电容,以使弹跳变得更平缓。
取决于电路,它的工作电压,电流等,你可能需要一个更大或更小的电容,你可能需要做一点实验,以找到什么工作最好。在我们的例子中,我们只是使用了一个9V的电池和一个10K欧姆的限流电阻。我们应该可以很容易地得到一个0.1µF电容器。我将使用陶瓷电容器,因为这是我有什么方便的价值,但几乎任何类型的工作都会很好。
我们的新原理图添加了去势电容,看起来像这样:
当我们在示波器上尝试这个时,事情看起来非常不同!
而不是一堆反弹,我们可以看到一个相当平滑的曲线!这正是我们所期待的!电容器存储和充电,并在每次反弹时释放它,从而平滑连接过程(至少从任何连接设备、集成电路或微控制器的角度来看)。
相关的:电容器的工作原理
不过,用硬件破坏开关是有代价的。字面上!对于我们的小一个off项目,它只是一个单一的电容器的成本。但对于一个生产数百万块电路板的大型项目来说,这意味着数百万个电容器,成本会迅速增加!此外,电容会占用空间,这在制造小型设备时也是一个问题。
消除抖动在软件
另一种解除开关的方法是在软件中进行。如果你将开关连接到一个智能设备,如微控制器或单板计算机(即。Arduino或覆盆子π),然后你有选择在软件反弹和节省额外电容的成本。
在软件中解除开关的最简单方法是简单地告诉微控制器在检测到第一个脉冲后等待50ms,然后再检查。它看起来像这样:
阅读= digitalRead (12);延迟(50);
阅读= digitalRead (12);延迟(50);
这种方法非常可靠,但也不是没有缺点。当Arduino等待50ms时,项目中可能会发生很多事情,您可能会错过一些其他输入。如果你按了很多按钮,那么50毫秒的时间就会让你的项目变慢。如果这些对你或你的项目都不重要,那么在第二次阅读按钮之前,只需等待50毫秒。
在软件中,更好的反弹方式是稍微复杂一点,看起来像这样:
//初始化并声明变量const int ledPin = 13;//连接到该引脚的led const int buttonPin = 2;//按钮连接到这个引脚int buttonState = LOW;//这个变量跟踪按钮的状态,如果没有按下则为低,如果按下则为高int ledState = -1;//该变量跟踪LED的状态,如果off为负,如果on为正lastDebounceTime = 0;//最后一次输出引脚被切换长debounceDelay = 50;//反弹时间;void setup(){//设置引脚的模式…pinMode (ledPin、输出);pinMode (buttonPin、输入); } void loop() { //sample the state of the button - is it pressed or not? buttonState = digitalRead(buttonPin); //filter out any noise by setting a time buffer if ((millis() - lastDebounceTime) > debounceDelay) { //if the button has been pressed, lets toggle the LED from "off to on" or "on to off" if ( (buttonState == HIGH) & (ledState < 0) ) { digitalWrite(ledPin, HIGH); //turn LED on ledState = -ledState; //now the LED is on, we need to change the state lastDebounceTime = millis(); //set the current time } else if ( (buttonState == HIGH) & (ledState > 0) ) { digitalWrite(ledPin, LOW); //turn LED off ledState = -ledState; //now the LED is off, we need to change the state lastDebounceTime = millis(); //set the current time } } }
这段代码的基本前提是跟踪一个变量中的按钮的状态。我们检查从上次按下按钮到现在有多久了。如果它小于50毫秒,我们将忽略“按压”,因为这将是一个错误的反弹。
这里有一个弗里茨图,如果你想构建这个电路,并尝试Arduino软件的debounce代码:
好了,这就是我们的减压教程。如果你有任何问题,请在下方留言,我们将尽力帮助你!
下一个步骤
现在让我们继续或回到索引!
我还是不明白为什么50毫秒的等待还不够好?
这也许足够好了。但是,如果您正在循环代码,而程序的一部分是检查按钮,而您每次延迟50毫秒,那么这种延迟可能会成为负担。想象一下,如果你在《Galaga》中每次开火都有50毫秒的延迟,因为所有的外星人都停了下来,你的飞船就停在那里。这真的会破坏游戏的动态。
哇。我不知道有这么回事。我敢打赌,我知道为什么我的一些老项目失败了!
设置一个中断时间为50ms的定时器,通过使用状态机检查ISR中的所有按钮-以正确的方式。
或者创建一个任务,有50ms的睡眠时间,检查任务中的所有按钮,如果你使用的是RTOS -更好的方法。
我浴室的电灯开关也有类似的问题。120V交流电,我觉得里面有点火花,我的灯泡很快就烧坏了。(每个开关上有两个或三个60W的灯泡。)等效的硬件修复是什么?谢谢。