Здесь 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, счет заканчивается.
Легко сообразить, что в момент выполнения команды brcc перенос станет равен единице только тогда, когда все регистры в предыдущем такте были равны нулю. Поэтому вся процедура работает так: перед ее началом в счетчики Razr0-Razr2 записывается некое заданное число, которое в каждом такте уменьшается на единицу, и вся процедура заканчивается при достижении нулевого значения во всех разрядах. Отсюда, зная тактовую частоту МК и время выполнения команд (по такту на вычитание и два такта на возврат к начальной метке), легко вывести формулу: записываемое в счетчики число N, соответствующее нужному интервалу времени T (с) при тактовой частоте F (Гц), рассчитывается, как T·F/(M + 2), где М — число регистров-счетчиков, в данном случае 3.
Число N в данном случае трехбайтовое. Старший байт записывается в Razr2, младший — в Razr0. При тактовой частоте 4 МГц мы можем получить задержку до 4,19 с, если запишем в регистры все единицы: число 16 777 215 = $FFFFFF. Если же нам требуется, например, задержка в 1 секунду, то придется записать число 800 000 или $0С3500, если в полсекунды — число 400 000 или $061А80.
Вооружившись этими знаниями, попробуем соорудить программу мигалки. Сначала давайте определимся с алгоритмом переключения из красного в зеленый. Наиболее универсальный метод здесь такой: каждый раз будем определять, в каком состоянии в данный момент находится светодиод (по состоянию какого-нибудь из задействованных выводов порта), и переключать его в противоположное. Это может выглядеть таким образом:
Не углубляясь в подробности, заметим, что такой алгоритм (он, конечно, не единственно возможный) будет устойчив к начальным условиям — в каком бы состоянии к моменту его начала ни находились биты 5 и 6 (даже если светодиод был совсем погашен), максимум через один цикл они придут в противоположное состояние, и мигание начнется. Теперь осталось соединить все это в законченную программу — повторять процедуру мигания через промежуток времени, определяемый процедурой Delay. Программа будет выглядеть таким образом:
О назначении первых двух операторов программы мы поговорим позднее. Rcall — команда вызова процедуры (в данном случае Delay). После этой команды всегда должна где-то встретиться команда ret (возврата из процедуры), иначе программа к основной последовательности операторов вернуться не «сумеет». Сама программа представляет собой бесконечный цикл, т. к. заканчивается оператором безусловного перехода обратно в начало (rjmp Migbegin). В данном случае мигание будет происходить с периодом в секунду (полсекунды красный, полсекунды зеленый), для другого периода нужно изменить записываемое в счетчики значение. Программа может служить хорошей основой для любимого развлечения радиолюбителей — конструирования елочных гирлянд.
* * *