Simple code for debouncing a switch:



/*--------------------------------------------------------------------------
Author: Jeff Loughlin (jeff@jloughlin.net)

Based loosely on a debouncing function by Peter Dannegger:
    http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=189356#189356
 
This is useful for detecting and debouncing button presses on an AVR
microcontroller, and should be adaptable to other microcontroller
architectures.  It can detect and debounce up to 8 buttons on a single
port, and should be relatively easy to modify to use all 4 ports for
up to 32 buttons.


The ISR tests the buttons every 10ms and detects a button press that lasts
at least 40ms (4 interrupt cycles).

--------------------------------------------------------------------------*/
 
// F_CPU used by debounce to calculate 10ms interrupts
#define F_CPU 1200000
 
#include <avr/io.h>
#include <avr/interrupt.h>
 
// Define the pins used by the buttons
#define KEY_DDR     DDRB
#define KEY_PORT    PORTB
#define KEY_PIN     PINB
#define KEY0        1   // Button on PB1
#define KEY1        2   // Button on PB2
#define KEY2        3   // Button on PB3
#define KEY3        4   // Button on PB4
#define KEY4        5   // Button on PB5
#define KEY5        6   // Button on PB6
#define KEY6        7   // Button on PB7
#define KEY7        8   // Button on PB8

 
unsigned char debounce_cnt = 0;
volatile unsigned char key_press;
unsigned char key_state;
 
unsigned char get_key_press(unsigned char key_mask);
void init_timers(void);
void init_io(void);
 
unsigned char get_key_press(unsigned char key_mask)
{
    cli();
    key_mask &= key_press;
    key_press ^= key_mask;
    sei();
    return key_mask;
}
 
void init_timers(void)
{
    cli();
    TCCR0B |= 1<<CS02 | 1<<CS00;  // Set timer prescaler to 1024
    TIMSK0 |= 1<<TOIE0;                 // Enable timer overflow interrupt
    sei();
}
 
void init_io(void)
{
    // Set all 8 pins in Port B as input and enable the pullups
    KEY_DDR &= ~((1<<KEY0) | (1<<KEY1) | (1<<KEY2) | (1<<KEY3) | (1<<KEY4) | (1<<KEY5) | (1<<KEY6) | (1<<KEY7));
    KEY_PORT |= (1<<KEY0) | (1<<KEY1) | (1<<KEY2) | (1<<KEY3) | (1<<KEY4) | (1<<KEY5) | (1<<KEY6) | (1<<KEY7);
}
 

int main(void)
{
    init_timers();    // Start the timer
    init_io();        // Set up the buttons
 
    for (;;)
    {
        if( get_key_press( 1<<KEY0 ))
        {
            // KEY0 press detected. Do something useful here.
        }
        if (get_key_press( 1<<KEY1 ))
        {
            // KEY1 press detected. Do something useful here.
        }
        if (get_key_press( 1<<KEY2 ))
        {
            // KEY2 press detected. Do something useful here.
        }
        if (get_key_press( 1<<KEY3 ))
        {
            // KEY3 press detected. Do something useful here.
        }
        if (get_key_press( 1<<KEY4 ))
        {
            // KEY4 press detected. Do something useful here.
        }
        if (get_key_press( 1<<KEY5 ))
        {
            // KEY5 press detected. Do something useful here.
        }
        if (get_key_press( 1<<KEY6 ))
        {
            // KEY6 press detected. Do something useful here.
        }
        if (get_key_press( 1<<KEY7 ))
        {
            // KEY7 press detected. Do something useful here.
        }
    }
}
 
// Interrupt Service Routine called every 10 ms
ISR(TIM0_OVF_vect)
{
    static unsigned char ct0, ct1;
    unsigned char i;
 
    //TCNT0 is where TIMER0 starts counting. This calculates a value based on
    //the system clock speed that will cause the timer to reach an overflow
    //after exactly 10ms
    TCNT0 = (unsigned char)(signed short)-(((F_CPU / 1024) * .01) + 0.5);   // preload for 10ms interrupts
 
    i = key_state ^ ~KEY_PIN;     // key changed?
    ct0 = ~( ct0 & i );           // reset or count ct0
    ct1 = ct0 ^ (ct1 & i);        // reset or count ct1
    i &= ct0 & ct1;               // count until roll over
    key_state ^= i;               // then toggle debounced state
    key_press |= key_state & i;   // 0->1: key press detected
}