所有关于电路
技术文章

切换弹跳以及如何处理它

2015年9月03日通过Jens Christoffersen.

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

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

推荐的水平

初学者

理论

什么是切换弹跳?按下按钮时,按MICO开关或翻转TogglesWitch,两个金属部件一起举起。对于用户来说,似乎联系人立即进行。这不太正确。开关内部有动作部件。当您按下开关时,它最初会与其他金属部分接触,但只是简要分配微秒。然后它使接触稍长,然后再次稍长。最后,开关完全关闭。该开关在接触之间弹跳,而不接触。“当开关关闭时,两个触点实际上分离并重新连接,通常在大约1ms的周边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。这是意法半导体制造的十年期计数器/除法器。他们不再生产这种IC了,所以这种型号已经过时了。然而,还有许多其他制造商仍在制造这种小的IC,而且它们通常是引脚兼容的。您可以找到4017类型IC的数据表在这里

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

我们的基本电路:

不会解释电路的进一步细节。

首先,我们完全会尝试没有弹跳控制。这是时钟电路:

时钟引脚保持低脉冲高 时钟引脚保持高脉冲低

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

视频:

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

这是开关A:

这是开关B:

这是开关C:

这是Switch D:

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

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

正如你所看到的,这个小的集成电路感觉到了开关上似乎有很多压力。但事实并非如此,因为开关只被按了一次。

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

时钟引脚保持低脉冲高 时钟引脚保持高脉冲低

当添加电容时,我们正在做一个R-C电路。R-C电路不在这里讨论。

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

这段视频展示了0.1uF的陶瓷电容是如何工作的:

开关:

切换B:

开关C:

Switch D:

这是开关C,时钟针helt高,脉冲低:

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

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

软件防反跳

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

另一种方法是使用中断来处理交换机反弹。请注意,中断可能会在上升沿和下降沿上触发,一些微控制器可能会堆叠一个等待中断。关于如何使用有不同的意见,但中断驱动开关的解调不在这里讨论。

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

/ * Softwaredebounce * *在每个从低到高或高到低电平的过渡到低*通过在几毫秒上采样,通过采样逐个读取输入信号。输入*不被认为是高或低,直到输入信号*已被采样至少在新状态中的“deboune_count”(10)*毫秒。* *注意:*调整DECOUCK_COUNT以反映输入信号的时间尺寸*以前可能会反弹*稳定状态* *基于:* http://www.arduino.cc/en/tutorial/debounce * * jon schlueter *2008年12月30日* * * //playground.arduino.cc/learning/softwaredebounce * / int Inpin = 7;//输入引脚int inpin = 13的数量;//输出引脚INT计数器的数量= 0;//我们看到了新的价值int读数;//从输入引脚int current_state = low读取的当前值;// Debounced输入值//以下变量是很长的,因为它以毫秒为单位测量的时间,//将快速变为比可以存储在int中的更大数量。长时间= 0; // the last time the output pin was sampled 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&ltstdlib.h> #include&ltxc.h> // config #pragma config fosc = Intoscio //振荡器选择位(Intosc振荡器:RA6 / OSC2 / CLKOUT引脚上的I / O功能,I / O在RA7 / OSC1 / CLKIN上的功能)#Pragma Config WDTE = OFF //看门狗定时器使能位(WDT禁用)#pragma config pwrte =关闭//上电定时器使能位(PWRT禁用)#pragma配置mclre= ON // RA5 / MCLR / VPP引脚功能选择位(RA5 / MCLR / VPP引脚功能为MCLR)#pragma config boren =上//棕色输出检测启用位(bod启用)#pragma config lvp =上//低压编程使能位(RB4 / PGM引脚具有PGM功能,启用低压编程)#Pragma Config CPD = OFF //数据EE存储器码保护位(数据存储器代码保护OFF)#Pragma Config CP = OFF //Flash程序内存代码保护位(代码保护)//定义#define _Xtal_freq 4000000 #define LED1 portbbits.rb3 #define led2 portbbits.rb2 #define btn portbbits.rb5 //变量charbtn_presspress = 0;char btn_press = 0;char btn_release = 0;Char BounceValue = 500;//主程序int main(int argc,char ** argv){//比较器关闭cmcon = 0x07;//端口方向,RB5输入,其余输出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使用内部振荡器。您需要与DebounceValue进行体验。我发现500件效果最好。

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

这是交换机将如何“混淆”微控制器的示例。没有好转的LED。当按下开关时,它看起来像是自己的生活。

微控制器与开关弹跳控制:

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

结论

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

11日评论
  • juul. 2015年9月19日

    很好的文章,有实际的例子,关于电路如何表现与不反弹的问题!

    喜欢。 回复
  • P
    Palpurul. 2015年11月5日

    感谢你的努力

    喜欢。 回复