Применение прерываний
Для того чтобы сделать все то же самое, но «по‑настоящему», придется воспользоваться таймером, а значит – прерываниями. Заметим, что в большинстве проектов Arduino прерывания в явном виде не используются, что относится к одному из главных недостатков этой платформы. Наличие аппаратных прерываний – одно из главных преимуществ современных контроллеров, и если в Arduino мы этим подходом часто жертвуем ради простоты, то в обычном программировании такое недопустимо.
Если помните, я говорил, что при возникновении прерывания процессор обращается по некоторому фиксированному адресу. Для каждой модели МК количество и типы прерываний различаются, потому эти адреса фиксированы для каждой модели процессора. Это первые адреса памяти программ, начиная с адреса 0:0 и дальше, – столько адресов, сколько имеется прерываний.
В МК ATtiny2313 имеется 19 прерываний (в его классическом аналоге было всего 11), соответственно, они занимают первые 19 адресов памяти программ. Напомним: поскольку коды команд двухбайтовые, то память программ организована по 16‑битовым словам, поэтому адреса в памяти программ означают адреса слов, а байтовый адрес будет в два раза больше (т. е. не 0, 1, 2…., а 0, 2, 4…). Это вас ни в коей мере не должно волновать, потому что абсолютные адреса вам отсчитывать не придется, – достаточно правильно оформить первые 19 строк кода, после секции всех определений. Поэтому использующая прерывания программа для ATtiny2313 всегда должна начинаться с последовательности команд, представляющих векторы прерываний, по следующему образцу:
* * *
Подробности
Если сравнить таблицы прерываний «классического» AT90S2313 и ATtiny2313, то окажется, что первые 11 векторов у них полностью совпадают. Отсутствующие в «классическом» аналоге остальные 8 векторов можно просто проигнорировать: если соответствующие прерывания не задействованы, то к ним никогда не произойдет обращения. По этой причине программы, написанные для AT90S2313, почти без оговорок совместимы с ATtiny2313 (не требуется даже заменять файл определений констант 2313def.inc). В дальнейшем мы будем без пояснений употреблять программы для обеих версий этого МК.
* * *
Здесь rjmp – знакомая нам команда безусловного перехода, a RESET, EXT_INTO и т. п. – метки в тексте программы, откуда начинается текст процедуры (подпрограммы) обработки прерывания. Метки могут быть обозначены и по‑иному, тут полный произвол. Сам переход осуществляется автоматически, если в процессе выполнения программы возникнут условия для возникновения соответствующего прерывания, для чего и его отдельно, и прерывания вообще надо еще разрешить.
Все прерывания и особенности их вызова мы рассматривать, конечно, не будем, а некоторые из них рассмотрим далее на практике.
Сначала заметим, что подобным образом должна выглядеть программа, если вы используете все 19 прерываний, чего на самом деле, конечно, не бывает. Но каждой записи rjmp <метка> должно соответствовать наличие метки далее в тексте, иначе ассемблер укажет на ошибку (посылать по неизвестному адресу нехорошо!). Поэтому если некоторые прерывания не используются, то, вообще говоря, можно вместо безусловных переходов наставить в соответствующих строках команд nор (nо operation – ее код равен просто нулям во всех разрядах), однако на практике вместо них чаще ставят команду reti , которая означает возврат из процедуры прерывания к выполнению основной программы, если вдруг оно возникнет.
* * *
Заметки на полях
На самом деле в общем случае не имеет значения, какую именно команду в этих строках ставить – выполняться они никогда не будут, если соответствующие прерывания не активированы, нам только нужно занять память, чтобы командаrjmp используемого нами прерывания оказалась по нужному адресу, – например, можно поставить команду rjmp $0000. Есть и другие, более корректные способы размещения команд по конкретным адресам памяти (с помощью директивы .org ), но не будем усложнять. Кстати, надо учесть, что данный способ относится, строго говоря, лишь к МК с памятью не более 8 Кбайт, уже для ATmega16 команды будут другими: вместо 2‑байтовойrjmp там применяется 4‑байтовая jmp (а вместо команды вызова подпрограммы rcall – call ).
* * *
Особое место занимает вектор, расположенный по самому первому, нулевому адресу, у нас он именуется RESET. Вообще говоря, вектор по нулевому адресу – это даже не совсем прерывание, а так называемый вектор сброса – мы ведь неоднократно говорили, что МК начинает выполнение программы с нулевого адреса. Программа из предыдущего раздела с него прямо начиналась (т. е. при включении питания сразу выполнялся первый оператор, потом второй и т. д.), но если задействованы прерывания, мы не можем так поступить. Поэтому в самом первой строке программы обязательно должен стоять указатель на процедуру, которая осуществляется в самом начале работы, и обычно так и называется: RESET. Эта процедура должна начинаться со следующих обязательных строк:
Если указатель стека не установить, то прерывания не заработают. Установка указателя стека для ряда моделей Tiny (в которых отсутствует SRAM) не требуется, а вот для других, в том числе и всех Mega , где количество SRAM превышает 256 байтов, эта загрузка будет протекать иначе, т. к. константа RAMEND там размером больше байта:
* * *
Подробности
Как мы уже отмечали в главе 18 , стек – область памяти, куда будут записываться адреса точек возврата при вызове подпрограмм по команде rcall или перехода к обработчикам прерываний. По окончании процедуры обработки прерывания (по команде reti ) или обычной подпрограммы (по команде ret ) этот адрес считывается в программный счетчик, и выполнение основной программы продолжается. Если во время выполнения обработчика данного прерывания происходит другое прерывание с большим приоритетом (это нужно специально разрешать, по умолчанию в AVR любое прерывание будет ожидать окончания обработки предыдущего), то в стек записывается также и этот текущий адрес команды, таким образом ошибиться при последовательном возврате невозможно. Стек устроен по принципу «последним вошел – первым вышел», т. е. извлекается всегда последнее записанное туда значение. Программист может использовать стек и для своих целей (командами push и pop – например, для сохранения текущего значения рабочих регистров), но неопытным программистам лучше активно этим способом не пользоваться – вероятность допустить трудно обнаруживаемую ошибку значительно возрастает. Тем более что в AVR и без того достаточно РОН (в отличие, например, от х51, где без стека обойтись практически невозможно), а при необходимости можно еще и хранить текущие значения в SRAM.
Дата добавления: 2016-05-11; просмотров: 1022;