有人可以帮助我解决开关抖动问题吗?我读过Ganssle的& avr的文章,但仍然不是很清楚。不明白如何使用定时器溢出中断!!
我想在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;
}
谢谢!
答案 0 :(得分:1)
“去抖”开关基本上是等待开关从(例如)数字高状态变为数字低状态。
你应该阅读更多关于debounce的内容:http://all-electric.com/schematic/debounce.htm
您可以通过两种方式实现:定时器中断或简单地轮询交换机的状态。在你的情况下,如果你想使用一个计时器int,你需要设置它然后,当你检测到开关改变状态时,计时器开始计数去抖动开关。
轮询方法要简单得多,但不总是最好的:
if( switch_is_pressed() ){
delay_ms(DEBOUNCE_TIME);
if( switch_is_pressed() ) return 1;
}
在尝试使用计时器之前,你应该阅读更多关于它是什么以及它是如何工作的。