Could anyone please help me with switch debouncing? I read Ganssle’s & avr’s articles but still not very clear. Don’t understand how to approach using Timer Overflow Interrupt!!
I want to do following tasks on STK600:
1) Read the switches, debounce any one of them
2) Debounce both edges of the switch action, make and break.
I have this code:
main.c
#include <avr/io.h>
#include <avr/interrupt.h>
#include "timer.h"
#include "debounce.h"
/************* Constant definitions **********************/
#define NUM_SWITCHES 8
/************* External Variable ******************/
/***************************************************************/
int main(void)
{
uint8_t LEDs = 0; // displayed data
uint8_t i; // loop counter
uint8_t temp; // used for detecting switch changes from off to on
uint8_t switchData; // present switch data
uint8_t lastSwitchData = 0x00; // previous switch data
/*
* INITIALIZATIONS
*/
DDRB = 0x00; /* Initialize port B for input (switches) */
DDRD = 0xff; /* Initialize port D for output (LEDs) */
PORTD = ~LEDs; /* All LEDs initially OFF */
InitTimer0();
sei();
for ( ; ;) /* BEGIN forever loop */
{
switchData = GetSwitchData();
if (switchData != lastSwitchData)
{
temp = switchData & ~lastSwitchData;
for (i=0; i<NUM_SWITCHES; i++)
{
switch (temp & _BV(i))
{
case 0x01: // count down
LEDs--;
break;
case 0x02: // count up
LEDs++;
break;
case 0x04: // rotate right
temp = LEDs & 0x01; // LSB
LEDs >>= 1;
LEDs |= temp << 7; // LSB rotates into MSB
break;
case 0x08: // rotate left
temp = LEDs & 0x80; // MSB
LEDs <<= 1;
LEDs |= temp >> 7; // MSB rotates into LSB
break;
case 0x10: // 1's complement
LEDs = ~LEDs;
break;
case 0x20: // 2's complement
LEDs = ~LEDs;
LEDs++;
break;
case 0x40: // swap nibbles:
temp = LEDs & 0x0F; // low nibble
LEDs >>= 4; // high nibble -> low nibble
LEDs |= temp << 4; // low nibble -> high nibble
break;
default: // switch 7, or no switches, do nothing
break;
}
PORTD = ~LEDs;
lastSwitchData = switchData;
}
}
}
}
Timer.c
#include <avr/interrupt.h>
#include <util/delay.h>
#include "Timer.h"
#include "debounce.h"
/*
* We want to generate a timer-overflow interrupt every 5ms. The clock rate
* is 8 MHz, which gives a tick time of 125 nanoseconds. The maximum count
* is 256, which gives a maximum time span of 256 x 0.125 = 32 us. This is too
* short, so use the pre-scaler and set it to /256. That lets us count to 256 x
* 32us = 8.192 ms. The clock ticks are now 125ns x 256 = 32 us. We need to
* count for 5ms/32us = 156.25 counts. That means the counter must be
* pre-set to 256 - 156 = 100 so that it will generate an overflow when it rolls
* over from 0xFF to 0. There will be 200 interrupts per second.
*/
void InitTimer0(void)
{
cli( ); // no interrupts while we're changing timer params!
TIMSK0 = 0; /* disable OCIE2A, OCIE2B, TOIE2 */
TCNT0 = TIMER0_INIT_VAL; /* init count register */
TCCR0A = 0;
TCCR0B = (1 << CS02 ); /* select prescaler: = 8 MHz / 256 => 32 us */
TIFR0 = (1 << OCF0A) | (1 << OCF0B) | (1 << TOV0); /* clear interrupt-flags */
TIMSK0 = (1 << TOIE0); /* enable Timer0 overflow interrupt */
}
/*
* Timer0 overflow interrupt handler.
*/
ISR(TIMER0_OVF_vect)
{
TCNT0 = TIMER0_INIT_VAL; /* re-initialize timer count */
DebounceSwitches();
}
/*
* This handler for unused interrupts will cause the program to stall with
* the four middle LEDs ON.
*/
ISR(__vector_default)
{
PORTB = 0xC3;
for ( ; ; ); // null statement - loop forever here
}
Debounce.c
#include "types.h"
#include "debounce.h"
#include <avr/io.h> // needed for definition of uint8_t and PINE
/*********** Constant definitions *********************/
#define DEBOUNCE_MAKE_DELAY 10 /* milliseconds */
#define DEBOUNCE_BREAK_DELAY 100 /* milliseconds */
#define CHECK_DELAY 5 /* milliseconds */
#define WHICH_SWITCH 1 /* This switch is debounced */
/* ************* Public data definitions *****************/
static uint8_t SwitchData;
/********************* Function prototypes ******************/
/***************** Function bodies **********************/
void DebounceSwitches(void)
{
**//Don't know what to put here??**
}
uint8_t GetSwitchData(void)
{
return SwitchData;
}
Thanks!
“Debouncing” a switch is basically wait for a switch to go from (for example) digital high state to a digital low state.
You should read more about what debounce is here: http://all-electric.com/schematic/debounce.htm
You can do it by two ways: Timer interrupt or simply polling the state of the switch. In your case, if you want to use a timer int, you need to setup it and then, when you detect that the switch changes the state, the timer start counting to debounce the switch.
The polling method is far more simple, but not the best always:
You should read more about what is it and how it works before trying to use a timer to do it.