Заметки на полях
У многих представителей семейства Tuny (кроме, насколько я знаю, Tuny2313), в том числе тех, у которых объем SRAM также не превышает 256 байт, стек аппаратный, а не программный, потому там его расположение специально указывать не требуется (отметим, что в [2] в этой части допущена ошибка). По этой причине, в частности, для семейства Tuny не определены команды push и pop, которые для остальных моделей позволяют временно сохранять в стеке значение какого-либо регистра (а для некоторых процессоров, вроде i8086, в которых регистров общего назначения мало, это вообще одни из самых употребительных команд). Размер же аппаратного стека строго фиксирован, и в нем умещается только адрес возврата из подпрограммы или обработчика прерывания.
После задания стека желательно поставить следующие строки:
ldi temp,1<
out ACSR,temp ;выкл. аналог, компаратор
Почему желательно, а не обязательно? Потому что по умолчанию аналоговый компаратор всегда включен и, соответственно, расходует питание. Если вы его не используете, то зачем лишнее потребление? Правда, это практически не скажется на потреблении в нормальном режиме работы, т. к. доля компаратора здесь очень мала. Вставка этих строк становится критичной только в том случае, если применяются режимы энергосбережения. С другой стороны, если компаратор нужен (см.
После всего этого в процедуре reset обычно идет секция инициализации, где разрешаются прерывания, устанавливаются состояния выводов портов, инициализируются начальные значения переменных и т. п. Примеры мы еще встретим в тексте этой книги неоднократно. Эта секция обязательно должна заканчиваться командой sei — общим разрешением прерываний, т. к. по умолчанию они запрещены.
Теперь вроде бы все готово к работе, но что будет делать контроллер в ожидании прерываний? Ведь основная функциональность большинства микропрограмм сосредоточена именно в их обработчиках, и в простейшем случае контроллер попросту ничего не должен делать, пока не придет сигнал очередного прерывания. Поэтому простейшая программа должна заканчиваться пустым циклом:
…
sei ;разрешаем прерывания
STOP:
rjmp STOP
На самом деле в этом цикле можно делать и что-то полезное, например, войти в один из режимов энергосбережения, или отслеживать изменение состояния какого-то вывода, или момент прихода байта через UART и т. п. — в дальнейшем мы увидим примеры подобных действий. Именно внутри такого цикла работают немногочисленные программы, вообще не использующие прерываний.
Определения переменных, констант и подключение внешних файлов
Определения играют в процессе написания ассемблерной программы важную роль, не менее важную, чем секция объявления переменных в программе на языке высокого уровня. Сравните две записи:
….
mov r16,r11
cpi r1l6,$11
…
и
…
mov temp,counter
cpi temp,max_value
…
И та, и другая запись верна, но вторая значительно более «читабельна», правда? Одно дело иметь программу, в которой фигурируют регистры (еще слава богу, что не их абсолютные адреса) и числа, совсем другое — работать с «говорящими» именами переменных и констант. Идентификатором temp (от слова «temporary» — временный) обычно обозначают рабочую переменную, которая не предназначена для долговременного хранения данных, counter — в переводе «счетчик», max_vaiue — «максимальное значение». Но если команды компилятор «знает» (мнемоника команд фиксирована и их смысл мы расшифруем немного далее), то как ему узнать, что мы имели имели в виду под этими самыми temp и counter?
Для этого служит секция определений имен переменных и констант, которую чаще всего располагают в самом начале текста программы, еще до векторов прерываний, или в отдельном внешнем файле, если определений много, и они очень загромождают текст. Именно такие макроопределения и содержат те самые файлы с расширением inc, которые мы копировали из AVR Studio, — для каждого контроллера свои. В результате чего мы можем писать mov GIMSK, temp вместо mov $3F,r16.