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

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

3 голосов
/ 04 ноября 2010

Последние 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;
  }
 }

Ответы [ 3 ]

1 голос
/ 04 ноября 2010

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

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

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

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

1 голос
/ 04 ноября 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 */
}

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

Спасибо

0 голосов
/ 04 ноября 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!!
  } 
 } 
...