.def temp = r16;рабочая переменная, от слова temporary (временный)

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

;программа зажигания светодиода

;процессор Tiny2313, частота 4 МГц

.include "tn2313def.inc"

.def temp = r16;рабочая переменная

ldi temp,0b01100000;устанавливаем биты номер 5 и 6 в temp

out DDRD,temp;выводим это значение в регистр направления порта D

sbi PortD,6;устанавливаем в единицу бит 6 регистра данных порта D

sleep

.exit

Программа займет в памяти программ контроллера ровно 8 байтов. Последняя команда sleep означает остановку процессора и выход в режим экономии — ведь должен процессор что-то делать по окончании программы? Директива .exit предназначена для ассемблера и означает конец программы, указывать ее необязательно.

А зачем мы в заголовочном комментарии указали тактовую частоту процессора?

В данном случае она не имеет значения (лишь бы контроллер работал), но при использовании любых процедур, связанных со временем, это критично. И поскольку можно забыть, на какую частоту вы рассчитывали при написании программы, следует ее на всякий случай указывать в комментариях.

Таймер без прерываний

Давайте теперь заставим наш МК управлять этим светодиодом так, чтобы он мигал с частотой примерно один раз в секунду из красного в зеленый. И сначала сделаем это самым простым способом — так, как это делали в те времена, когда микропроцессоры еще не были микроконтроллерами и не содержали никаких дополнительных узлов вроде таймеров. Для отсчета времени тогда пользовались тем фактом, что команды выполняются строго определенное время. Причем в AVR этот способ применять особенно удобно, поскольку большинство команд занимают один такт, за исключением команд передачи управления. Этим способом часто пользуются и по сей день для отсчета программных задержек (не станешь же заводить таймер по каждому случаю), потому урок окажется не совсем бесполезным. Заодно познакомимся с понятием процедур (подпрограмм) и с самими командами передачи управления.

Не вникая в подробности, сразу напишем «правильную» процедуру, позволяющую формировать заданные задержки без таймера. Назовем ее Delay, тогда она запишется так:

Здесь Razr0-Razr2 — рабочие регистры. Отведем для них регистры r17, r18 и r19. В начало программы тогда следует внести их определения через команду def (по образцу .def Razr0 = r17). Delay с двоеточием — метка, в данном случае обозначающая начало процедуры, команда ret — выход из процедуры (зачем она нужна, пояснено далее). Команда subi вычитает из регистра константу, в данном случае единицу. А команды sbci работают хитрее — они также вычитают константу, но с учетом переноса. Если переноса нет, то они просто ничего не делают (ибо вычитаемое значение равно нулю). Перенос же возникает тогда, когда в результате предыдущей команды вычиталась единица из нуля. Тогда значение регистра меняется с нулевого на все единицы (255), а перенос записывается в специальный бит переноса и учитывается следующей командой sbci. В этой схеме легко узнать принцип работы соединенных между собой двоичных счетчиков из главы 16, в которых выход старшего разряда предыдущего счетчика соединен со входом переноса следующего. В данном случае счетчик состоит из трех отдельных байтовых регистров, т. е. всего имеет 24 двоичных разряда.

Нам не надо, чтобы счет продолжался до бесконечности, и для этой цели служит команда brcc, которая относится к группе команд передачи управления (branch) и работает по очень простому правилу — если в момент ее исполнения бит переноса (он обозначается буквой С, от слова саnу, что и значит «перенос») равен нулю (clear, т. е. очищен), то далее выполняется возврат к команде по метке Delay. To есть название команды (brcc) расшифровывается так: branch if carry clear (перейти, если перенос очищен). В противном случае управление передается на следующую команду — выхода из процедуры ret, счет заканчивается.

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату