Files
SyncHome/trunk/workspace/00_Lib/Misc/debounce_keys.c
topicchi 0b6afad8fe
2023-09-22 06:03:48 +00:00

118 lines
3.4 KiB
C

/****************************************************************************
Title: Debouncing 8 Keys
Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury,
based on algorithm of Peter Dannegger <danni@specs.de>
Date: December 2003
Software: AVR-GCC 3.3
Hardware: AT90S8515 at 4 Mhz, STK200 compatible starter kit
Description:
Demonstrates debouncing 8 keys. The state of the eight keys is sampled
four times using a timer interrupt. If a key is pressed longer than
four seconds, the corresponding bit in the key_press global variable is set.
The main loop checks if a bit is set in this global variable and resets
the bit.
Pressing the key connected to PIND2 increments a counter, while pressing
the key connected to PIND3 decrements the counter.
The value of this counter is displayed using LEDs on PORTB.
*****************************************************************************/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#ifndef CTC1
#define CTC1 WGM12 // for compatibility with ATmega
#endif
#define XTAL 4000000L // Crystal frequency in Hz
#define DEBOUNCE 200L // debounce clock 200Hz = 5msec
/*
* Module global variable, informs the main programm when a key is pressed.
* This variable must be declared 'volatile, since it is accessed from
* both interrupt und main loop.
*/
static volatile uint8_t key_press;
SIGNAL (SIG_OUTPUT_COMPARE1A)
{
static uint8_t key_state; // debounced and inverted key state:
static uint8_t ct0, ct1; // holds two bit counter for each key
uint8_t i;
/*
* read current state of keys (active-low),
* clear corresponding bit in i when key has changed
*/
i = key_state ^ ~PIND; // key changed ?
/*
* ct0 and ct1 form a two bit counter for each key,
* where ct0 holds LSB and ct1 holds MSB
* After a key is pressed longer than four times the
* sampling period, the corresponding bit in key_state is set
*/
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
/*
* To notify main program of pressed key, the correspondig bit
* in global variable key_press is set.
* The main loop needs to clear this bit
*/
key_press |= key_state & i; // 0->1: key press detect
}
int main( void )
{
uint8_t count = 0;
TCCR1B = _BV(CTC1) + _BV(CS10); // clear timer on compare match, no prescaler
OCR1A = XTAL/DEBOUNCE; // timer = 5 msec
TIMSK = _BV(OCIE1A); // enable Output Compare 1 overflow interrupt
DDRB = 0x00; // use all pins on PortD for input
PORTD = 0xff; // with pull-up enabled
DDRB = 0xff; // use all pins on PortB for output
PORTB = 0xff; // turn all LED off
sei(); // enable interrupt
for(;;)
{
if (key_press & _BV(2) )
{
// key 2 pressed, increment counter
count++;
PORTB = ~count;
key_press = 0;
}
else if ( key_press & _BV(3) )
{
// key 3 pressed, decrement counter
count--;
PORTB = ~count;
key_press = 0;
}
}
}