切换DEbouncing

时间:2011-11-01 16:24:39

标签: switch-statement avr

有人可以帮助我解决开关抖动问题吗?我读过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; 
}

谢谢!

1 个答案:

答案 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;
}

在尝试使用计时器之前,你应该阅读更多关于它是什么以及它是如何工作的。