Прерывания микроконтроллеров семейства AVR

Меня самого мучал вопрос что ж это такое, искал информацию, но из-за того, что в русскоязычном интернете нету ни одного толкового сайта наполненного информацией, структурированного и ухоженного, кроме конечно easyelectronics.ru пришлось потратить довольно много времени на освоение данного вопроса.

Еще одна сложность изучения прерываний в том, что наилучший показатель по освоению материала достигается примерами рабочего кода программы. Такие хоть и есть, НО!!! Из-за того, что многие в основном ленивые проггеры начинают работу с компилятором CV-AVR, в котором хоть и есть предварительный редактор кода с помощью которого перед написанием программы можно предварительно сконфигурировать те же таймеры, модули USART, TWI, но все же крайне не удобный интерфейс, с моей точки зрения и вообще CV-AVR мне крайне не симпатичен. Другое дело AVR Studio в связке с WinAVR :-)
Так очень распространены примеры программ на ассемблере, у него куча преимуществ но один значительный недостаток, при изучении с нуля необходимо присутствие специалиста. Так же в интернете есть еще куча различных вариантов для написания управляющей программы микроконтроллера такие как: Basic, Flow Code и тд. тп. Но как-то так сложилось, как в своё время с операционной системой Windows, она не самая лучшая но никому нет до этого дела. Кстати о Windows советую посмотреть фильм "Пираты силиконовой долины".

И так, прерывание - это событие, после которого выполняется подпрограмма (обработчик прерываний).
Пример:
Основная программа - бегущий огонек из 8-ми светодиодов, выполняется при включении питания микроконтроллера.
К микроконтроллеру подключена кнопка к ножке int0 (смотри datasheet на конкретный микроконтроллер).
При нажатии на кнопку программа бегущего огонька останавливается и восемь светодиодов начинают мигать - это и есть программа обработки прерывания. Светодиоды мигают столько, сколько задано в подпрограмме, после окончания выполнения подпрограммы обработки прерывания микроконтроллер возвращается к выполнению основной программы - бегущего огонька, при том с места, на котором он ранее остановился.

Подпрограмму обработки прерываний желательно делать как можно короче, то есть не делать ей по времени выполнения особо длинной, не пихать в частности паузы в 1секунду и более.

Для того чтобы микроконтроллер учитывал(выполнял) прерывания в программе необходимо их включить, то есть инициализировать обработку прерываний. Для языка C выглядит следующим образом:

  1. SIGNAL (SIG_INTERRUPT1)//программа-обработчик прерываний
  2. {
  3. ...
  4. }
  5.  
  6. int main (void)//основная программа
  7. {
  8. sei(); //Разрешаем глобально прерывания
  9. ...
  10. }

Так же предусмотрен вариант, когда необходимо на время запретить выполнение прерываний, для это используют следующую запись в языке C:

  1. {
  2. cli(); //запрещаем выполнение прерываний
  3. ...
  4. }

Вызвать прерывание можно несколькими способами, верней даже это не способы а причины появления прерывания. В 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

  1. SIGNAL (SIG_INTERRUPT1)
  2. {
  3. ...
  4. }

Обработка прерываний по переполнению таймера 0

  1. ISR (TIMER0_OVF_vect)
  2. {
  3. ...
  4. }

Обработка прерывания по приходу байта на модуль USART

  1. ISR(USART_RXC_vect)
  2. {
  3. ...
  4. }

  1. SIGNAL (SIG_OVERFLOW0)
  2. {
  3. ...
  4. }

Синтаксис для компилятора WinAVR в CV-AVR немножко по другому будет выглядеть, обратите внимание.

Прерывания очень полезны если программа довольно большая и имеет разветвленную структуру, прерывания могут облегчить её написание уменьшить размер.

Прерывания имеют свой приоритет, так если например в программе используется несколько прерываний и так получилось что в один и тот же момент времени случаются два прерывания, то в первую очередь будет выполнено прерывание с приоритетом выше. Приоритет прерываний указан в таблице прерываний, чем меньше адрес подпрограммы прерывания, тем выше приоритет.
Наглядный пример работы с прерываниями int0 и int1 с исходным кодом и комментариями.

С чем связано ограничение

С чем связано ограничение размера и(или) времени выполнения подпрограммы обработки прерывания?

Специфика микроконтроллера

Специфика микроконтроллера такова, что он приостанавливает выполнение основной программы но данные, которые он обрабатывал хранит в оперативной памяти. То есть ограничение исходит отсюда.

Работа с прерываниями,

Работа с прерываниями, довольно подробно, описана в литературе, посвящённой МК АВР. Например, "Применение МК АВР.Схемы, алгоритмы, программы" Н. В. Баранов.

Использование макроса SIGNAL ()

Использование макроса SIGNAL() является устаревшим (deprecated). В руководстве к avr-libc сказано "Do not use SIGNAL() in new code. Use ISR() instead."

Это да, ноу меня работает, а

Это да, ноу меня работает, а по сему пока не пропадет поддержка SIGNAL() буду им пользоваться.

И нигде не сказано что

И нигде не сказано что прерывания надо сначала включить =)

исправим обязательно,

исправим обязательно, спасибо!