3

在过去的两周里,我试图学习定时器和中断,并编写了一个程序(以我的理解)来闪烁 ATMEGA2560 上的 LED,但无论我做什么,TCNT0 都不会递增,并且 ISR() 函数永远不会被调用。我哪里出错了,我该如何解决?这是我的代码:

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

#define READ_ATMEGA(ADDR) *((P_CHAR)(BASE_ADDR + ((ADDR) * ADDR_MULTIPLIER)))
#define WRITE_ATMEGA(ADDR, DATA) *((P_CHAR)(BASE_ADDR + ((ADDR) * ADDR_MULTIPLIER))) = DATA

#define BASE_ADDR 0x20

void init_timer0_ovf_interrupt(void);
void timer0_interrupt_isr(void);
void initialize_ports(void);
 void delay(unsigned int no_65_5ms_interrupts);

 void __attribute__((ISR)) timer0_interrupt_isr(void);

 //#pragma interrupt_handler timer0_interrupt_isr:24

 unsigned int delay_timer;

 int main(void)
 {
  initialize_ports();
 init_timer0_ovf_interrupt();
 delay(46);
 return 0;
  }

 void initialize_ports(void)
 {
  READ_ATMEGA(4) = 0xff;
  WRITE_ATMEGA(5, 0x00);
 }

 void delay(unsigned int no_65_5ms_interrupts)
 {
  TCNT0 = 0x00;
  delay_timer = 0;
  while(delay_timer <= no_65_5ms_interrupts)
  {
   ;
  }
 }

 void init_timer0_ovf_interrupt(void)
 {
  TCCR0A = 0X00;
  TCCR0B = 0x02;
  TIMSK0 = 0x01;
  TIFR0 = 1<<0;
  OCR0A = 25;
   sei();
 }

 void timer0_interrupt_isr(void)
 {
  delay_timer++;
  if(delay_timer >= OCR0A)
  {
   PORTB = ~(PORTB);
   delay_timer = 0;
  }
 }
4

3 回答 3

1

全局变量delay_timer在中断代码和非中断代码之间共享。它应该被声明为volatile值可以在delay().

如果您查看生成的代码,delay()您可能会发现 delay_timer 的值在while循环中旋转时没有被重新读取。

还有,volatile还不够。你有非中断代码和中断代码都写入同一个变量(delay_timer)。您需要保护在非中断代码中对变量的写入,那里存在竞争条件。简单/懒惰的方法是禁用中断并在非中断代码中恢复它们。

(至于设置中断和启动定时器,该信息应该在芯片的数据表中。通常这是更容易正确处理的部分,它是咬人的共享数据的东西。)

于 2010-11-04T18:34:52.737 回答
1

3-4 天前,我编写了相同的程序,略有不同,并且 LED 闪烁,但仍不确定这是否是使用定时器和中断的正确方法。谁能看到这个并告诉我它是否正确?我设法通过阅读定时器、中断程序来编写这个程序。

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

volatile uint8_t intrs;

ISR(TIMER0_OVF_vect) {
    /* this ISR is called when TIMER0 overflows */
    intrs++;

    /* strobe PORTB.5 - the LED on arduino boards */
    if (intrs >= 61){
        PORTB = ~PORTB;
        intrs = 0;
    }

}


int main(void) {

    TCCR0B = 0x02;

    /* Enable Timer Overflow Interrupts */
    TIMSK0 = 0x01;

    /* other set up */
    DDRB = 0xff;
    TCNT0 = 0;
    intrs = 0;

    /* Enable Interrupts */
    sei();

    while (1)
        ; /* empty loop */
}

如果这是正确的方法,那么我可以开始下一步。

谢谢

于 2010-11-04T20:51:27.070 回答
0

如果可能是你在延迟函数中的while循环没有做任何事情并且不会增加delay_timer,所以你陷入了一个无限循环:

void delay(unsigned int no_65_5ms_interrupts) 
 { 
  TCNT0 = 0x00; 
  delay_timer = 0; 
  while(delay_timer <= no_65_5ms_interrupts) 
  { 
   ; //Nothing is happening here!!
  } 
 } 
于 2010-11-04T18:01:21.583 回答