Переключатель DEbouncing
Может ли кто-нибудь, пожалуйста, помогите мне с переключателем debouncing? Я читал статьи Гансле и Авра, но все еще не очень ясно. Не понимаю, как подходить к использованию прерывания по переполнению таймера!!
Я хочу выполнить следующие задачи на STK600:
1) Прочитайте ключи, отмените любой из них 2) Отмените оба края действия переключателя, сделайте и сломайте.
У меня есть этот код:
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;
}
Спасибо!
1 ответ
"Отключение" переключателя - это в основном ожидание перехода переключателя из (например) цифрового высокого состояния в цифровое низкое состояние.
Вы должны прочитать больше о том, что debounce здесь: http://all-electric.com/schematic/debounce.htm
Вы можете сделать это двумя способами: Прерывание по таймеру или просто опрос состояния коммутатора. В вашем случае, если вы хотите использовать таймер int, вам нужно настроить его, а затем, когда вы обнаружите, что коммутатор меняет состояние, таймер начинает отсчет, чтобы отменить коммутатор.
Метод опроса намного проще, но не всегда лучший:
if( switch_is_pressed() ){
delay_ms(DEBOUNCE_TIME);
if( switch_is_pressed() ) return 1;
}
Вы должны прочитать больше о том, что это такое и как это работает, прежде чем пытаться использовать таймер для этого.