ATmega2560-使用计时器使多个按钮的LED闪烁

问题描述

因此,任务是使LED多次闪烁,具体取决于所按下的按钮,例如如果按下sw3,LED必须闪烁3秒钟,并每1/4秒产生一次中断。

如果按下任何按钮,是否有任何激活计时器的方法?并且只要计时器正在运行就不应该读取按钮?

我已经编写了以下代码,但是我不确定它是否可以在实验室中正常工作,因此如果有任何人可以提供帮助,那就太好了。将不胜感激。谢谢。

    #include <avr/io.h>
    #include <avr/interrupt.h>

    #define LEDs PORTB
    #define KEYs PORTA
    #define OUTPUT 0b11111111
    #define INPUT  0b00000000

    volatile uint8_t count = 0;
    volatile uint8_t ready = 0;
    volatile uint8_t seconds;

    void set_up_the_timer(void);
    void blink_or_flash(void);

    int main(void)
    {
      DDRA = INPUT;
      DDRB = OUTPUT;
      LEDs = 0xFF;
      if(!(PINA & (1 << PINA0))) {
        set_up_the_timer();
        sei(); 
       }

      while (1) 
     {
        switch(KEYs) {
          case 0b11111110:
            seconds = 7;                                        // 0.15 * 7 = 1.05s
            blink_or_flash();
            break;
          case 0b11111101:
            seconds = 13;                                       // 0.15 * 13 = 1.95s;
            blink_or_flash();
            break;
          case 0b11111011:
            seconds = 20;                                       // 0.15 * 20 = 3s;
            blink_or_flash();
            break;
          case 0b11110111:
            seconds = 27;                                       // 0.15 * 27 = 4.05s
            blink_or_flash();
            break;
          case 0b11101111:
            seconds = 33;                                       // 0.15 * 33 = 4.95s
            blink_or_flash();
            break;
          case 0b11011111:
            seconds = 40;                                       // 0.15 * 40 = 60s
            blink_or_flash();
            break;
          case 0b10111111:
            seconds = 47;                                       // 0.15 * 47 = 7.05s
            blink_or_flash();
            break;
          case 0b01111111:
            seconds = 53;                                       // 0.15 * 53 = 7.95s
            blink_or_flash();
            break;  
          default:
            break;
        }
    }
 }


   void set_up_the_timer() {
        TCCR1A |= (1 << WGM12);
        OCR1A = 2344;                               // an interrupt occurring every 0.15 second
   

        TimsK1 |= (1 << OCIE1A);
        TCCR1B |= (1 << CS12) | (1 << CS10);
  }

    void blink_or_flash() {
        if(ready == 1) {
            LEDs = 0x00;
            count = 0;
     }
   }

    ISR(TIMER0_COMPA_vect) {
       count++;
       LEDs = ~(LEDs);
       if(count >= seconds) {
       ready = 1;
       }
    }

    

解决方法

我不确定我对您的问题的解释是否正确,但这也许有帮助:

// Datasheet
// https://ww1.microchip.com/downloads/en/devicedoc/atmel-2549-8-bit-avr-microcontroller-atmega640-1280-1281-2560-2561_datasheet.pdf
 
// Not necessary but important for calculations
#define F_CPU 16000000UL
 
#define HIGH 0xFF
#define LOW 0x00
 
#include <avr/io.h>
#include <avr/interrupt.h>

volatile unsigned char loop = 0;
volatile unsigned long counter = 0;     // Need be of type long to prevent overflow
volatile unsigned long milliseconds;    // Need be of type long to prevent overflow

void timer_setup(void);
void timer_start();
void timer_stop();
void timer_blink(void);

ISR(TIMER1_COMPA_vect)
{
    PORTB = ~(PORTB);
    
    counter++;
    
    if(counter > milliseconds)
        loop = 1;
}

 int main(void)
 {
    // Setup PORTA to input (no pullup resitors)
    // @startup alle pins on the controller are inputs,// so setup pins as input can be omitted
    DDRA = LOW;
     
    // Setup PORTB to output and switch all LEDs on
    DDRB = HIGH;
    PORTB = HIGH;

    timer_setup();

    while (1)
    {
        switch(PINA) {
            case 0b11111110:    milliseconds = 1005;    // 1.05s
                                timer_blink();
                                break;
            case 0b11111101:    milliseconds = 1950;    // 1.95s;
                                timer_blink();
                                break;
            case 0b11111011:    milliseconds = 3000;    // 3s;
                                timer_blink();
                                break;
            case 0b11110111:    milliseconds = 4050;    // 4.05s
                                timer_blink();
                                break;
            case 0b11101111:    milliseconds = 4950;    // 4.95s
                                timer_blink();
                                break;
            case 0b11011111:    milliseconds = 60000;   // 60s
                                timer_blink();
                                break;
            case 0b10111111:    milliseconds = 7005;    // 7.05
                                timer_blink();
                                break;
            case 0b01111111:    milliseconds = 7950;    // 7.95
                                timer_blink();
                                break;
            default:
            break;
        }
    }
}


void timer_setup()
{
    // Timer 1 (16 Bit)
    // Mode: CTC
    // Prescaler: 64 (will be accurate because there is no remainder @datasheet page 146)
    // Compare match:            F_CPU                      16000000 Hz
    //                 OCR1A = -------------------- - 1 = -------------- = 249
    //                            1                          1
    //                         ------- * PRESCALER        ------- * 64
    //                          T_INT                     0.001 s
    // Control: Compare Match Interrupt every 1 ms
     
    OCR1A = 249;
     
    TCCR1A = (1<<WGM12);
    TIMSK1 = (1 << OCIE1A);
     
    sei();
}

void timer_start()
{
    TCNT1 = 0;
    TCCR1B |= (1<<CS11) | (1<<CS10);
    TCCR1B &= ~(1<<CS12);
}

void timer_stop()
{
    TCCR1B &= ~((1<<CS12) | (1<<CS11) | (1<<CS10));
    TCNT1 = 0;
}

void timer_blink()
{
    loop = 0;
    counter = 0;
     
    timer_start();
     
    // Wait until sequence ended
    while(loop != 1)
        asm volatile("NOP");
     
    timer_stop();
    
    // Reset LEDs
    PORTB = 0x00;
}

目前我无法测试解决方案,因此可能存在一些错误...