3

過去2週間、タイマーと割り込みを学び、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

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 に答える
1

グローバル変数delay_timerは、割り込みコードと非割り込みコードで共有されます。volatileの外部で値が変更される可能性があるため、 として宣言する必要がありdelay()ます。

生成されたコードをdelay()見ると、ループ内でのスピン中に delay_timer の値が再読み取りされていないことがわかるでしょうwhile

また、十分でvolatileはありません。非割り込みコードと割り込みコードの両方が同じ変数 (delay_timer) に書き込みます。非割り込みコードで変数への書き込みを保護する必要があります。競合状態があります。簡単で怠惰な方法は、割り込みを無効にして、非割り込みコードでそれらを復元することです。

(割り込みの設定とタイマーの開始に関しては、その情報はチップのデータシートにあるはずです。通常、それは正しく取得するのが簡単な部分であり、人々を噛むのは共有データのものです。)

于 2010-11-04T18:34:52.737 に答える
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 に答える