Прерывания микроконтроллеров семейства AVR
Меня самого мучал вопрос что ж это такое, искал информацию, но из-за того, что в русскоязычном интернете нету ни одного толкового сайта наполненного информацией, структурированного и ухоженного, кроме конечно easyelectronics.ru пришлось потратить довольно много времени на освоение данного вопроса.
Еще одна сложность изучения прерываний в том, что наилучший показатель по освоению материала достигается примерами рабочего кода программы. Такие хоть и есть, НО!!! Из-за того, что многие в основном ленивые проггеры начинают работу с компилятором CV-AVR, в котором хоть и есть предварительный редактор кода с помощью которого перед написанием программы можно предварительно сконфигурировать те же таймеры, модули USART, TWI, но все же крайне не удобный интерфейс, с моей точки зрения и вообще CV-AVR мне крайне не симпатичен. Другое дело AVR Studio в связке с WinAVR :-)
Так очень распространены примеры программ на ассемблере, у него куча преимуществ но один значительный недостаток, при изучении с нуля необходимо присутствие специалиста. Так же в интернете есть еще куча различных вариантов для написания управляющей программы микроконтроллера такие как: Basic, Flow Code и тд. тп. Но как-то так сложилось, как в своё время с операционной системой Windows, она не самая лучшая но никому нет до этого дела. Кстати о Windows советую посмотреть фильм "Пираты силиконовой долины".
И так, прерывание - это событие, после которого выполняется подпрограмма (обработчик прерываний).
Пример:
Основная программа - бегущий огонек из 8-ми светодиодов, выполняется при включении питания микроконтроллера.
К микроконтроллеру подключена кнопка к ножке int0 (смотри datasheet на конкретный микроконтроллер).
При нажатии на кнопку программа бегущего огонька останавливается и восемь светодиодов начинают мигать - это и есть программа обработки прерывания. Светодиоды мигают столько, сколько задано в подпрограмме, после окончания выполнения подпрограммы обработки прерывания микроконтроллер возвращается к выполнению основной программы - бегущего огонька, при том с места, на котором он ранее остановился.
Подпрограмму обработки прерываний желательно делать как можно короче, то есть не делать ей по времени выполнения особо длинной, не пихать в частности паузы в 1секунду и более.
Для того чтобы микроконтроллер учитывал(выполнял) прерывания в программе необходимо их включить, то есть инициализировать обработку прерываний. Для языка C выглядит следующим образом:
SIGNAL (SIG_INTERRUPT1)//программа-обработчик прерываний { ... } int main (void)//основная программа { sei(); //Разрешаем глобально прерывания ... }
Так же предусмотрен вариант, когда необходимо на время запретить выполнение прерываний, для это используют следующую запись в языке C:
{ cli(); //запрещаем выполнение прерываний ... }
Вызвать прерывание можно несколькими способами, верней даже это не способы а причины появления прерывания. В datasheet имеется таблица прерывания микроконтроллера, и в ней можно посмотреть все источники этих самых прерываний.
Таблица прерываний микроконтроллера ATtiny2313:
Номер вектора | Адрес подпрограммы | Источник прерывания | Описание прерывания |
---|---|---|---|
1 | 0x0000 | RESET | Внешний сброс, сброс при включении питания, сброс по срабатыванию охранного таймера |
2 | 0x0001 | INT0 | Внешний запрос на прерывание по входу INT0 |
3 | 0x0002 | INT1 | Внешний запрос на прерывание по входу INT1 |
4 | 0x0003 | TIMER1 САРТ | Прерывание по захвату таймера/счетчика 1 |
5 | 0x0004 | TIMER1 COMPA | Прерывание по совпадению таймера/счетчика 1. Канал А |
6 | 0x0005 | T1MER1 OVF | Прерывание по переполнению таймера/счетчика 1 |
7 | 0x0006 | TIMER0 OVF | Прерывание по переполнению таймера/счетчика 0 |
8 | 0x0007 | USART0, RX | USART0, прием завершен |
9 | 0x0008 | USART0, UDRE | USART0 буфер данных пуст |
10 | 0x0009 | USART0, TX | USART0, передача завершена |
11 | 0x000A | ANALOG COMP | Прерывание от аналогового компаратора |
12 | 0x000B | PCINT | Прерывание по изменению на любом из выводов |
13 | 0x000C | TIMER1 COMPB | Прерывание по совпадению таймера/счетчика 1. Канал В |
14 | 0x000D | TIMER0 COMPA | Прерывание по совпадению таймера/счетчика 0. Канал В |
15 | 0x000E | TIMER0 COMPB | Прерывание по совпадению таймера/счетчика 0. Канал А |
16 | 0x000F | USI START | Прерывание по USI. Готовность к старту |
17 | 0x0010 | USI OVERFLOW | Прерывание по USI, Переполнение |
18 | 0x0011 | ЕЕ READY | Готовность EEPROM |
19 | 0x0012 | WDT OVERFLOW | Переполнение охранного таймера |
Пример синтаксиса объявления подпрограммы-обработчика прерываний:
Обработка прерываний INT1
SIGNAL (SIG_INTERRUPT1) { ... }
Обработка прерываний по переполнению таймера 0
ISR (TIMER0_OVF_vect) { ... }
Обработка прерывания по приходу байта на модуль USART
ISR(USART_RXC_vect) { ... }
SIGNAL (SIG_OVERFLOW0) { ... }
Синтаксис для компилятора WinAVR в CV-AVR немножко по другому будет выглядеть, обратите внимание.
Прерывания очень полезны если программа довольно большая и имеет разветвленную структуру, прерывания могут облегчить её написание уменьшить размер.
Прерывания имеют свой приоритет, так если например в программе используется несколько прерываний и так получилось что в один и тот же момент времени случаются два прерывания, то в первую очередь будет выполнено прерывание с приоритетом выше. Приоритет прерываний указан в таблице прерываний, чем меньше адрес подпрограммы прерывания, тем выше приоритет.
Наглядный пример работы с прерываниями int0 и int1 с исходным кодом и комментариями.
С чем связано ограничение
С чем связано ограничение размера и(или) времени выполнения подпрограммы обработки прерывания?
Специфика микроконтроллера
Специфика микроконтроллера такова, что он приостанавливает выполнение основной программы но данные, которые он обрабатывал хранит в оперативной памяти. То есть ограничение исходит отсюда.
Работа с прерываниями,
Работа с прерываниями, довольно подробно, описана в литературе, посвящённой МК АВР. Например, "Применение МК АВР.Схемы, алгоритмы, программы" Н. В. Баранов.
Использование макроса SIGNAL ()
Использование макроса SIGNAL() является устаревшим (deprecated). В руководстве к avr-libc сказано "Do not use SIGNAL() in new code. Use ISR() instead."
Это да, ноу меня работает, а
Это да, ноу меня работает, а по сему пока не пропадет поддержка SIGNAL() буду им пользоваться.
И нигде не сказано что
И нигде не сказано что прерывания надо сначала включить =)
исправим обязательно,
исправим обязательно, спасибо!