Mechanical switches do not make or break a connection cleanly due to microscopic conditions on the contact surface. This is referred to as "Switch Bounce" and can cause problems in digital circuits. In this tutorial we will build a circuit that demonstrates this problem, then modify it slightly to resolve it.

Image

We will be reusing the circuit from the ATmega8 breadboard circuit tutorial. The schematic is shown below.

Image

Next we write and upload some code to the microcontroller. This program waits for you to press a button, then records how many times you press
that button until it senses a quiet period. At this point it flashes the LED for as many times as button presses were recorded.

  1.  
  2. #include <avr/io.h>
  3. #include <util/delay.h>
  4.  
  5.  
  6. //Define functions
  7. //======================
  8. void ioinit(void);
  9. void led_on(void);
  10. void led_off(void);
  11. //======================
  12.  
  13. int main (void)
  14. {
  15.    ioinit(); //Setup IO pins and defaults
  16.  
  17.    while (1)
  18.    {
  19.       int num_presses;                  //Number of times button has been iterations
  20.       int num_nopress_iterations;       //Number of loop iterations since last button press
  21.       char button_state;                //1=pressed, 0=not pressed
  22.    
  23.          //Wait for button to be pressed
  24.          while (!bit_is_clear(PINC, 5)) {}
  25.          num_presses=1;
  26.          button_state=1;
  27.          
  28.          while (1)
  29.          {
  30.             if (bit_is_clear(PINC, 5)) //button is pressed
  31.             {
  32.                if (button_state==0) //was previously not pressed)
  33.                {
  34.                   num_presses++;
  35.                }
  36.                button_state=1;
  37.             }
  38.             else //button is not pressed
  39.             {
  40.                if (button_state==1) //was previously pressed
  41.                {
  42.                   num_nopress_iterations=0;
  43.                }
  44.                num_nopress_iterations++;
  45.                button_state=0;
  46.                if (num_nopress_iterations>20000) //If we haven't seen a button press for a while, terminate the loop
  47.                {  
  48.                   break;
  49.                }
  50.             }
  51.          }
  52.          
  53.          for (int i=0;i<num_presses;i++)
  54.          {
  55.             led_on();
  56.             _delay_ms(300);
  57.             led_off();
  58.             _delay_ms(300);
  59.          }
  60.      
  61.          if (bit_is_clear(PINC, 5))
  62.          {
  63.          }
  64.    }
  65. }
  66.  
  67.  
  68. void ioinit (void)
  69. {
  70.     DDRC  = 0b11011111; //1 = output, 0 = input
  71.    PORTC = 0b00100000; //Enable pin 5 internal pullup
  72. }
  73.  
  74. void led_on(void)
  75. {
  76.    PORTC |= _BV(PC4);
  77. }
  78.  
  79. void led_off(void)
  80. {
  81.    PORTC &amp;= ~_BV(PC4);
  82. }
  83.  

When you run the program and press the button, you will often notice the LED blinking too many times. This is due to the button bounce.

The figure below shows how we normally think a button press looks like.

Image

Whereas this one is closer to the truth (even this one is a bit too clean and elegant)

Image

Fixing the problem is very easy. All you need to do is add a capacitor. I used a 100nF capacitor, but experiment with what works best for you.

Image
Image

Note: The problem isn't too pronounced on a breadboard as it has a lot of natural capacitance. On a PCB the problem is much more severe.