Внешние прерывания в архитектуре AVR сбивают с толку, но не невозможны.Я обнаружил, что лучшим ресурсом для меня была страница libc AVR с прерываниями .Я думаю, что вы сделали код слишком сложным для того, что вы хотите, чтобы он делал.Давайте начнем с нуля:
#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>
void main() {
sei();
while(1) {};
}
AVR libc фактически делает обработку прерываний довольно безболезненной.На странице, на которую я ссылался выше, есть список всех поддерживаемых векторов прерываний на каждом чипе AVR.Давайте предположим, что вы используете Mega32, и теперь вы хотите, чтобы светодиоды мигали с помощью прерывания по таймеру.Давайте добавим в программу:
uint8_t led_state;
ISR(TIMER0_COMP_vect) {
led_state = ~led_state;
PORTB = led_state;
}
void setup_timer_interrupt() {
TCCR0B = 0x03;
TIMSK0 = 0x01;
TCNT0 = 0x00;
}
Это должно мигать светодиодами на PORTB
каждый раз, когда происходит прерывание таймера.Обратите внимание, что его нужно настроить с помощью макроса ISR(...)
;используемые вами __vector_...
вызовы устарели и немного более запутанны.
Наконец, вы хотите использовать набор переключателей для удержания светодиода, если я правильно понимаю ваш вопрос.На самом деле я бы не использовал для этого внешнее прерывание, просто прочитал значение переключателей, используя PINK
во время ISR(TIMER0_COMP_vect)
, но мы можем использовать его, если хотите.Нам нужно добавить следующий код:
uint8_t switch_state;
void setup_switch_interrupt() {
// I'm assuming this code to enable external interrupts works.
DDRK = 0x00;
PORTK = 0xff;
PCMSK2 = 0xff; // set to all 1s
PCICR = 0x04;
PCIFR = 0x04;
}
ISR(INT0_vect) {
switch_state = PINK;
}
Что это делает?Мы будем сохранять состояние переключателей в switch_state
, читая каждый раз, когда запускается внешнее прерывание (я полагаю, у вас есть этот набор, чтобы происходить как при переходах 0-> 1, так и 1-> 0).Осталось только настроить выход светодиода на значение switch_state
.Мы сделаем это при прерывании по таймеру, так как именно там мы до сих пор переключали светодиоды.Новая версия выглядит так:
ISR(TIMER0_COMP_vect) {
led_state = ~led_state | switch_state;
PORTB = led_state;
}
И это должно сработать!
Сноска: Ранее я говорил, что использование внешнего прерывания для чтения переключателей недействительно необходимо.Это потому, что вы можете просто прочитать значения переключателя во время прерывания таймера, используя PINK
.Вы можете избавиться от switch_state
, setup_switch_interrupt()
и ISR(INT0_vect)
и просто изменить прерывание по таймеру следующим образом:
ISR(TIMER0_COMP_vect) {
led_state = ~led_state | PINK;
PORTB = led_state;
}
Это должно сделать программу немного проще.