====== Прерывания ======
В микроконтроллере AVR прерывания (на английском языке interrupt) могут создавать счетчики, интерфейсы передачи данных, аналого-цифровой преобразователь, компаратор, специальные входные-выходные выводы и многие другие функции, в зависимости от контроллера. Каждое прерывание можно разрешить или запретить в его генерируемой единице. Независимо от разрешения или запрета для каждого прерывания в соответствующей единице контроллера имеется 1-битное поле данных (флаг, на английском языке interrupt flag), которое обозначается истинным при совершении события вызывающего прерывание. В случае если происходит изменение упомянутого поля данных и прерывание разрешено, то контроллер станет выполнять код,
В микроконтроллере AVR каждое прерывание связано с определенным событием. У каждого события в регистре состояния есть флаговый бит, который указывает происхождение события. Вдобавок к этому есть ещё регистры маскировки прерываний и соответствующие биты, связанные с событиями. Если бит события прерывания не замаскирован и происходит событие, то процессор в течение нескольких рабочих тактов откладывает выполнение запущенной программы и начинает выполнения программы прерывания.
Для использования прерываний необходимо выбрать файл interrupt.h с помощью библиотеки AVR LibC. Программный код, идущий на выполнение прерывания, добавляется после ключевого слова „ISR“. После „ISR“ в скобках пишется имя прерывания. Пример кода на языке Си:
#include
ISR(XXX_vect)
{
// Сделай что-нибудь
}
Разрешение глобального, т.е. совершение всех прерываний, определяется в управляющем регистре и регистре состояния SREG. Возможность запрета или разрешения всех прерываний обуславливает необходимость защиты данных. Поскольку прерывания прерывают выполнение запущенной программы, то они могут помешать или испортить данные, которые использовала основная программа во время прерывания. Во избежание данной проблемы необходимо запретить все прерывания до начала работы с чувствительными данными. После выполнения критической части программы можно снова разрешить прерывания.
Предположим, что в программе используется 16-битная переменная, значение которой изменяет, как основная программа, так и отрезок программы прерывания, и впоследствии значение этой переменной присваивается другой переменной:
#include
// Глобальные 16-битные переменные x и y
unsigned short x, y;
// Случайное прерывание, которое изменяет значение x
ISR(XXX_vect)
{
x = 0x3333;
}
int main()
{
// Присваивание значения переменной x
x = 0x1111;
// Разрешение глобального прерывания
sei();
// Загрузка значения x в переменную y
y = x;
}
Программа очень простая - сначала присваивается значение 0x1111 переменной x, а затем это же значение переменной y. Так как происходит прерывание, то значение x становится 0x3333. По правилам логики у переменной y в конце программы может быть две возможных значений, но у 8-битного AVR имеется и третья возможность. При 8-битной архитектуре происходит перемещение 16-битных данных в течение 2 тактов, и создаваемое прерывание может повредить целостность данных. Поэтому может возникнуть помимо 0x1111 и 0x3333 значение 0x3311. Для того чтобы таких проблем не возникало, необходимо перед операцией временно запрещать прерывания, которые длятся дольше чем течении одного такта.
Ниже приведен пример присваивания переменной y значение x по безопасному методу:
// Запрет глобального прерывания
cli();
// Загрузка
y = x;
// Разрешение глобального прерывания
sei();