Technical Article

Switch Bounce and How to Deal with It

September 03, 2015 by Jens Christoffersen

In this article I will discuss what switch bounce is and some ways to deal with it. First I will take you through the theory, and later I will show you some ways to handle it in both hardware and in software.

In this article I will discuss what switch bounce is and some ways to deal with it. First I will take you through the theory, and later I will show you some ways to handle it in both hardware and in software.

Recommended level

Beginner

 

Theory

What is switch bounce? When you push a button, press a mico switch or flip a toggleswitch, two metal parts come together. For the user, it might seem that the contact is made instantly. That is not quite correct. Inside the switch there are moving parts. When you push the switch, it initially makes contact with the other metal part, but just in a brief split of a microsecond. Then it makes contact a little longer, and then again a little longer. In the end the switch is fully closed. The switch is bouncing between in-contact, and not in-contact. "When the switch is closed, the two contacts actually separate and reconnect, typically 10 to 100 times over a periode of about 1ms." ("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:

 

Click on image for full size.

Each switch has its own characteristics regarding the bounce. If you compare two of the same switches, there is a great chance that they will bounce differently.

 

I will show you how 4 different switches bounce. I have 2 micro switches, 1 push button, and 1 toggle switch:

Hardware setup

All the switches will be connected the same way (this is essential if we are going to compare the results). First we will see how the switches behave in their raw form. The basic of our circuit will be the HCF4017BE. This is a decade counter/divider made by STMicroelectronics. They do not produce this IC anymore, so this actual type is obsolete. However, there are many other manufacturers that still make this little IC, and they are often pin compatible. You can find a datasheet for the 4017-types IC here.

The IC receives a clock signal on PIN 14 and then lights the LED on Q1. When the next clock signal is received, the IC turns off Q1 and lights Q2, and so on. When the counting reaches Q8 (PIN 9), it clocks PIN 15, which is the reset pin. That makes the whole counting start at Q0.

Our basic circuit:

Further details of the circuit will not be explained.

 

First we will try with no bounce control at all. This is the clock circuit:

Clock pin held low - pulse high Clock pin held high - pulse low

 

In the video we are using the circuit on the right. Clock pin held high - pulse low.

Video:

Now, let us see some screenshots from the oscilloscope.

This is switch A:

This is switch B:

This is switch C:

This is switch D:

This is switch C, with the clock pin held high, and we pulse low:

Click on images for better resolution. The screenshots are from the clock circuit on the left, where the clock pin is held low.

As you can see, the small IC is sensing what seems to be a lot of pressing on the switch. This is not the case, since the switch was pressed only one time.

Let us add a ceramic capacitor, like this:

Clock pin held low - pulse high Clock pin held high - pulse low

 

While adding the capacitor, we are maknig a R-C circuit. R-C circuits will not be discussed here.

The screenshots from the oscilloscope, are very different from the above screenshots. This shows that the R-C circuit is filtering out the bounces.

This video shows how it is with a 0.1uF ceramic capacitor:

Switch A:

Switch B:

Switch C:

Switch D:

This is switch C,, with the clock pin helt high, and pulse low:

Click on images for better resolution. The screenshots are from the clock circuit on the left. Clock pin held low - pulse high.

The screenshots tells us that the bouncing has stopped, and that the IC is only "seeing" one push or one flip. This is what we want.

Software debounce

When working with microcontrollers, we can deal with switch bounce in a different way that will save both hardware space and money. Some programmers do not care much about bouncing switches and just add a 50ms delay after the first bounce. This will force the microcontroller to wait 50ms for the bouncing to stop, and then continue with the program. This is actually not a good practice, as it keeps the microcontroller occupied with waiting out the delay.

Another way is to use an interrupt for handling the switch bounce. Be aware that the interrupt might be fired on both the rising and falling edge, and some microcontrollers might stack up one waiting interrupt. There are different opinions on how to use it, but interrupt driven switch debouncing will not be discussed here.

The following is a simple software debounce code for Arduino. (Code source.)

/* SoftwareDebounce
 * 
 * At each transition from LOW to HIGH or from HIGH to LOW 
 * the input signal is debounced by sampling across
 * multiple reads over several milli seconds.  The input
 * is not considered HIGH or LOW until the input signal 
 * has been sampled for at least "debounce_count" (10)
 * milliseconds in the new state.
 *
 * Notes:
 *   Adjust debounce_count to reflect the timescale 
 *     over which the input signal may bounce before
 *     becoming steady state
 *
 * Based on:
 *   http://www.arduino.cc/en/Tutorial/Debounce
 *
 * Jon Schlueter
 * 30 December 2008
 *
 * http://playground.arduino.cc/Learning/SoftwareDebounce
 */

int inPin = 7;         // the number of the input pin
int outPin = 13;       // the number of the output pin

int counter = 0;       // how many times we have seen new value
int reading;           // the current value read from the input pin
int current_state = LOW;    // the debounced input value

// the following variable is a long because the time, measured in milliseconds,
// will quickly become a bigger number than can be stored in an int.
long time = 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();
  }
}

The above code is written in Arduino IDE.

The following program toggles two LEDs connected to a PIC microcontroller. The code can be something like this:

// INCLUDES
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>

// CONFIG
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN = ON       // Brown-out Detect Enable bit (BOD enabled)
#pragma config LVP = ON         // Low-Voltage Programming Enable bit (RB4/PGM pin has PGM function, low-voltage programming enabled)
#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)

// DEFINITIONS
#define _XTAL_FREQ 4000000
#define LED1 PORTBbits.RB3
#define LED2 PORTBbits.RB2
#define BTN PORTBbits.RB5

// VARIABLES
char BTN_pressed = 0;
char BTN_press = 0;
char BTN_release = 0;
char Bouncevalue = 500;

// MAIN PROGRAM
int main(int argc, char** argv) {
    // Comparators off
    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

This example is written in MPLAB X with the XC8 compiler. The microcontroller is a PIC 16F628A, and I am using the internal oscillator at 4MHz. You need to experiement with the Debouncevalue. I found that 500 works best.

Microcontroller without any switch bounce control:

This is an example of how the switch will "confuse" the microcontroller. There is no nice toggling of the LEDs. It looks like they are living their own lives when the switch is pressed.

Microcontroller with switch bounce control:

As you can see, the LEDs toggle nicely on and off according to the switch.

Conclusion

In this article I have discussed what debounce is, how it affects your system, and different ways to deal with it. The examples that are used are very simple, but they should give you a feeling of what is happening when you push a switch. You should allways consider switch debounce when you are designing a  system.

17 Comments
  • Juul September 19, 2015

    Great article, with practical examples on how the circuit behaves with and without the bouncing problem!

    Like. Reply
  • P
    palpurul November 05, 2015

    great article thanks for the effort

    Like. Reply