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
}