雷竞技注册
技术文章

Switch Bounce和如何处理它

2015年9月03日通过Jens Christoffersen

在本文中,我将讨论什么是开关反弹以及一些处理它的方法。首先,我将向您介绍这个理论,然后我将向您展示一些在硬件和软件中处理它的方法。

在本文中,我将讨论什么是开关反弹以及一些处理它的方法。首先,我将向您介绍这个理论,然后我将向您展示一些在硬件和软件中处理它的方法。

推荐的水平

初学者

理论

什么是开关弹跳?当你按下一个按钮,按下一个微开关或拨动一个开关时,两个金属部件就会结合在一起。对于用户来说,这似乎是即时的联系。这并不完全正确。开关内部有活动部件。当你按下开关时,它最初会与另一个金属部分接触,但只是在一微秒的短暂间隔内。然后它会让接触持续一段时间,然后再持续一段时间。最后,开关完全闭合。开关在接触和非接触之间弹跳。“当开关关闭时,两个触点实际上分离并重新连接,通常在大约1毫秒的时间内进行10到100次。” ("The Art of electronics", Horowitz & Hill, Second edition, pg 506.) Usually, the hardware works faster than the bouncing, which results in that the hardware thinks you are pressing the switch several times. The hardware is often an integrated circuit. The following screenshots illustrates a typical switch bounce, without any sort of bounce control:

点击图片以获得完整的尺寸。

对于弹跳,每个开关都有自己的特点。如果你比较两个相同的开关,很有可能它们反弹的方式不同。

我将展示4个不同的开关是如何弹跳的。我有2个微开关,1个按钮,1个拨动开关:

硬件设置

所有的开关将以相同的方式连接(如果我们要比较结果,这是必要的)。首先,我们将看到开关在原始形式下的行为。我们电路的基础是HCF4017BE。这是意法半导体制造的10年计数器/分压器。雷竞技最新app他们不再生产这种IC了,所以这种型号已经过时了。然而,还有许多其他制造商仍在生产这种小型集成电路,而且它们通常是引脚兼容的。您可以找到4017类型IC的数据表在这里

IC接收PIN 14上的时钟信号,然后点亮Q1上的LED。当接收到下一个时钟信号时,IC关闭Q1,点亮Q2,以此类推。当计数达到Q8 (pin9),它时钟pin15,这是复位引脚。这使得整个计数从Q0开始。

我们的基本电路:

关于电路的更多细节将不会被解释。

首先,我们将尝试没有反弹控制。这是时钟电路:

时钟针保持低脉冲高 时钟针保持高脉冲低

在视频中,我们使用的是右边的电路。时钟针保持高脉冲低。

视频:

现在,让我们看一些来自示波器的屏幕截图。

这是开关A:

这是开关B:

这是开关C:

这是开关D:

这是开关C,时钟引脚保持高,我们脉冲低:

点击图片以获得更好的分辨率。屏幕截图来自左边的时钟电路,时钟引脚保持低。

如你所见,小IC感应到的似乎是按压开关的很多。但事实并非如此,因为开关只按了一次。

让我们添加一个陶瓷电容器,像这样:

时钟针保持低脉冲高 时钟针保持高脉冲低

在增加电容器的同时,我们正在制作一个rc电路。这里不讨论R-C电路。

示波器的截图与上面的截图非常不同。这表明R-C电路过滤掉了反弹。

这段视频展示了0.1uF陶瓷电容器的情况:

开关:

B:切换

开关C:

开关D:

这是开关C,时钟引脚高,脉冲低:

点击图片以获得更好的分辨率。屏幕截图来自左边的时钟电路。时钟针保持低脉冲高。

屏幕截图告诉我们,弹跳已经停止,IC只能“看到”一次推或一次翻转。这就是我们想要的。

软件防反跳

当使用微控制器时,我们可以用不同的方式处理开关反弹,这将节省硬件空间和金钱。有些程序员不太关心弹跳开关,只是在第一次弹跳后增加一个50ms的延迟。这将迫使微控制器等待50毫秒的弹跳停止,然后继续程序。这实际上不是一个好做法,因为它会让微控制器忙于等待延迟。

另一种方法是使用中断来处理开关反弹。请注意,中断可能同时在上升和下降边缘被触发,一些微控制器可能会叠加一个等待中断。对于如何使用它有不同的意见,但中断驱动开关去振在这里将不讨论。

下面是一个简单的Arduino软件跳出代码。(代码源。

/* SoftwareDebounce * *在每个从低到高或从高到低的过渡*输入信号是通过采样*多个读取在几毫秒。输入*不会被认为是高或低,直到输入信号*在新的状态下被采样至少“debounce_count”(10)*毫秒。* *注:*调整debounce_count反映输入信号的时间尺度* *前可能反弹成为稳态基于:* * * http://www.arduino.cc/en/Tutorial/Debounce * * Jon Schlueter http://playground.arduino.cc/Learning/SoftwareDebounce * 2008年12月30日* * * / int inPin = 7;//输入引脚的编号int outPin = 13;//输出引脚的数量int counter = 0;//我们有多少次看到new value int读取;//从输入引脚读取的当前值int current_state = LOW;//下面的变量是一个很长的变量,因为时间(以毫秒为单位)很快就会变成一个比int型变量还大的数。长时间= 0;//最后一次采样输出引脚int debounce_count = 10; // number of millis/samples to consider before declaring a debounced input void setup() { pinMode(inPin, INPUT); pinMode(outPin, OUTPUT); digitalWrite(outPin, current_state); // setup the Output LED for initial state } void loop() { // If we have gone on to the next millisecond if(millis() != time) { reading = digitalRead(inPin); if(reading == current_state && counter > 0) { counter--; } if(reading != current_state) { counter++; } // If the Input has shown the same value for long enough let's switch it if(counter >= debounce_count) { counter = 0; current_state = reading; digitalWrite(outPin, current_state); } time = millis(); } }

以上代码是在Arduino IDE中编写的。

下面的程序切换连接到PIC微控制器的两个led。代码可以是这样的:

//包含#include <stdio.h> #include <stdlib.h> #include <xc.h> //配置#pragma配置FOSC = INTOSCIO //振荡器选择位(INTOSC振荡器:RA6/OSC2/CLKOUT引脚的I/O功能,I / O功能RA7 / OSC1 CLKIN) # pragma配置WDTE = / /看门狗定时器使钻头(WDT禁用)# pragma配置PWRTE = / /升高定时器使钻头(PWRT禁用)# pragma配置MCLRE = / / RA5 / MCLR / VPP销函数选择钻头(RA5 / MCLR / VPP销函数MCLR) # pragma配置BOREN = / /暗光检测使钻头(BOD启用)#pragma config LVP = ON //低压编程使能位(RB4/PGM引脚有PGM功能,#pragma config CPD = OFF // Data EE Memory Code Protection bit (Data Memory Code Protection OFF) #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code Protection OFF) // definition #define _XTAL_FREQ 4000000 #define LED1 portbits。RB3 #define LED2 portbits。RB2 #定义BTN portbits。RB5 //变量char BTN_pressed = 0;char BTN_press = 0;char BTN_release = 0;char bouncvalue = 500;//主程序int MAIN (int argc, char** argv){//比较器关闭CMCON = 0x07; // Port directions, RB5 input, the rest is output TRISA = 0b00000000; TRISB = 0b00100000; // Port state, all low PORTA = 0b00000000; PORTB = 0b00000000; // Starting with LED1 high and LED2 low LED1 = 1; LED2 = 0; while (1) { // If BTN is pressed if (BTN == 1) { // Bouncing has started so increment BTN_press with 1, for each "high" bounce BTN_press++; // "reset" BTN_release BTN_release = 0; // If it bounces so much that BTN_press is greater than Bouncevalue // then button must be pressed if (BTN_press > Bouncevalue) { // This is initial value of BTN_pressed. // If program gets here, button must be pressed if (BTN_pressed == 0) { // Toggle the LEDs LED1 ^= 1; LED2 ^= 1; // Setting BTN_pressed to 1, ensuring that we will // not enter this code block again BTN_pressed = 1; } // LEDs toggled, set BTN_pressed to 0, so we can enter // toggle code block again BTN_press = 0; } } else { // Increment the "low" in the bouncing BTN_release++; BTN_press = 0; // If BTN_release is greater than Bouncevalue, we do not have a // pressed button if (BTN_release > Bouncevalue) { BTN_pressed = 0; BTN_release = 0; } } } return (EXIT_SUCCESS); }

main_debounce.c.zip

这个示例是使用XC8编译器用MPLAB X编写的。微控制器是PIC 16F628A,我使用的是4MHz的内部振荡器。你需要尝试debouncvalue。我发现500是最好的。

单片机无任何开关弹跳控制:

这是一个开关如何“混淆”微控制器的例子。没有很好的led切换。当开关按下时,他们似乎在过着自己的生活。

带有开关弹跳控制的单片机:

正如你所看到的,led根据开关很好地开启和关闭。

结论

在本文中,我讨论了什么是debounce,它如何影响您的系统,以及处理它的不同方法。所使用的例子非常简单,但是当你按下开关时,它们应该能让你感觉到发生了什么。当你在设计一个系统时,你应该总是考虑开关跳出。

11日评论
  • 尤尔的说法 2015年9月19日

    伟大的文章,与实际的例子如何电路表现与没有弹跳的问题!

    喜欢的。 回复
  • P
    palpurul 2015年11月5日

    很好的文章,谢谢你的努力

    喜欢的。 回复