Нужна помощь с таймером

В течение последних 2 недель я пытаюсь изучить таймер и прерывание и написал программу (с моим пониманием), чтобы мигать светодиодами на ATMEGA2560, но независимо от того, что я делаю, 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;
  }
 }

person sneezy    schedule 04.11.2010    source источник
comment
К сведению: чтобы отформатировать блок кода, выберите его и нажмите кнопку code; тот, который выглядит как двоичные цифры.   -  person meagar    schedule 04.11.2010


Ответы (3)


Глобальная переменная delay_timer совместно используется кодом прерывания и кодом без прерывания. Он должен быть объявлен как volatile, так как значение может измениться за пределами delay().

Если вы посмотрите на сгенерированный код для delay(), вы, вероятно, увидите, что значение delay_timer не перечитывается во время вращения в цикле while.

Кроме того, volatile недостаточно. У вас есть код без прерывания и код прерывания, которые записываются в одну и ту же переменную (delay_timer). Вам нужно защитить запись в переменную в коде без прерывания, там есть состояние гонки. Простой/ленивый способ - отключить прерывания и восстановить их в коде без прерываний.

(Что касается настройки ваших прерываний и запуска вашего таймера, эта информация должна быть в техническом описании чипа. Обычно это та часть, которую легче сделать правильно, это общие данные, которые кусают людей.)

person Dan    schedule 04.11.2010
comment
Я на самом деле взволнован, потому что я должен представить этот проект к завтрашнему дню, и я все еще не понимаю таймеры и прерывания в совершенстве. (Это не фактический проект, который я должен представить). Я должен связать светодиоды и переключатели, прокрутить светодиоды и при нажатии переключателя... зажечь соответствующий светодиод с помощью таймера и прерывания и без использования файлов заголовков avr. Дэн.. то, что ты сказал в своем посте, я все еще думаю над этим. - person sneezy; 04.11.2010

3-4 дня назад я написал ту же программу немного по-другому, и светодиоды начали мигать, но я все еще не уверен, что это правильный способ использования таймера и прерывания. Может ли кто-нибудь увидеть это и сказать мне, правильно это или нет? Мне удалось написать эту программу, читая программы таймеров, прерываний.

#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 */
}

Если это правильный путь, я могу начать работу над следующим шагом.

Спасибо

person sneezy    schedule 04.11.2010
comment
Я не знаком с продуктами Atmega/Arduino, поэтому не могу сказать наверняка, но похоже, что вы устанавливаете частоту таймера (TCCROB), включаете прерывания таймера (TIMSK0), сбрасываете счетчик (TCNT0), и включение системных прерываний (sei). Это должно быть все, что обычно необходимо для работы таймера. Что касается вашей исходной программы, я не уверен, почему она не работает, поскольку вы, похоже, установили все те же регистры, плюс еще несколько. Возможно, в исходной программе timer0_interrupt_isr не был должным образом связан с прерыванием переполнения таймера? - person Sam Skuce; 09.11.2010

Если может случиться так, что ваш цикл 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!!
  } 
 } 
person D.R.    schedule 04.11.2010