Проблема с таймером 0

Я делаю первые неуверенные шаги вне Arduino IDE, и у меня не очень получается с таймерами/прерываниями. Я могу настроить вывод на вывод и зажечь светодиод с регистрами, но я не могу заставить его мигать с помощью таймера. Я изучил множество руководств и очень внимательно следил за техническими данными Atmel ATmega328.

Использование платы Arduino Uno R3 & Atmel ICE (ISP.) Моя система разработки — Raspbian (Debian) с набором инструментов GNU AVR (avr-gcc, avr-objcopy, avrdude). Помимо отсутствия загрузчика, это стандартная плата болота (включая предохранители.)

Вот мой текущий код:

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

ISR(TIMER0_COMPA_vect)
{
    PORTB ^= (1 << PB5); // Переключить контакт Arduino № 13
}

int main (void)
{
    DDRB = (1 << DDB5); // Arduino Pin #13 является выходом

    cli(); // Очистить прерывания

    OCR0A = (unsigned char)0xFF; // Сравнить регистр A = 255
    TIMSK0 = (1 << OCIE0A); // Включить прерывание для комп. Рег. А
    TCCR0A = (1 << WGM01); // Режим СТС

    sei(); // Установка прерываний
    TCCR0B = (1 << CS02) | (1 << CS00); // Делим на 1024 Предделитель (ВПЕРЕД!)

    return 0;
}

Не знаю, то ли я чего-то не вижу, то ли я установил регистры в неправильном порядке, но это сводит меня с ума.

, 👍5

Обсуждение

return 0 не сбрасывает устройство? Попробуйте while(1);, чтобы он ждал бесконечно., @Gerben

Я буду кричать. Спасибо! (Ты делаешь ответ на вопрос или я?), @Ashlyn Black

Комментатор должен преобразовать его в ответ., @dlu


2 ответа


Лучший ответ:

4

return 0 перезагружает устройство. Вместо этого используйте while(1);, чтобы заставить его ждать бесконечно.

,

Просто чтобы уточнить, возврат из main **не** сбрасывает устройство, как я показал в своем ответе. Я упоминаю об этом на случай, если люди прочитают этот ответ и подумают, что возврат из «основного» — это простой способ добиться перезагрузки устройства., @Nick Gammon


4

Возврат из main не приводит к сбросу устройства (в этом случае оно запустится снова и повторит все заново). Он вызывает exit, который отключает прерывания и зацикливается на неопределенный срок.

00000068 <__ctors_end>:
  68:   11 24           eor r1, r1
  6a:   1f be           out 0x3f, r1    ; 63
  6c:   cf ef           ldi r28, 0xFF   ; 255
  6e:   d8 e0           ldi r29, 0x08   ; 8
  70:   de bf           out 0x3e, r29   ; 62
  72:   cd bf           out 0x3d, r28   ; 61
  74:   0e 94 52 00     call    0xa4    ; 0xa4 <main>
  78:   0c 94 61 00     jmp 0xc2    ; 0xc2 <_exit>

...

000000a4 <main>:
  a4:   80 e2           ldi r24, 0x20   ; 32
  a6:   84 b9           out 0x04, r24   ; 4
  a8:   f8 94           cli
  aa:   8f ef           ldi r24, 0xFF   ; 255
  ac:   87 bd           out 0x27, r24   ; 39
  ae:   82 e0           ldi r24, 0x02   ; 2
  b0:   80 93 6e 00     sts 0x006E, r24
  b4:   84 bd           out 0x24, r24   ; 36
  b6:   78 94           sei
  b8:   85 e0           ldi r24, 0x05   ; 5
  ba:   85 bd           out 0x25, r24   ; 37
  bc:   80 e0           ldi r24, 0x00   ; 0
  be:   90 e0           ldi r25, 0x00   ; 0
  c0:   08 95           ret

000000c2 <_exit>:
  c2:   f8 94           cli

000000c4 <__stop_program>:
  c4:   ff cf           rjmp    .-2         ; 0xc4 <__stop_program>

Вы можете видеть, что по адресу 0x74 он вызывает main, а затем переходит к выходу. exit отключает прерывания.

Если прерывания отключены, ваш ISR не будет переключать контакт 13.

,