Гораздо сложнее устроены команды установки бит в регистрах общего назначения. Взгляните на фрагмент ранее приведенного кода, где вы встретите команду sbr Flag, 0b00010000, устанавливающую бит номер 4 в единицу. Почему так сложно, да еще и в двоичной системе? Дело в том, что команды эти на самом деле не устанавливают никаких битов, а просто осуществляют некую логическую операцию между значением регистра и заданным байтом, который в этом случае называют битовой маской. Указанная команда расшифровывается как Flag OR ob00010000. Если вы вернетесь к главе 7, то сообразите, что при такой операции четвертый бит (нумерация начинается с нуля) установится в единицу, какое бы значение он ни имел ранее, а все остальные останутся в старом состоянии. Понятно также, почему я предпочел использовать двоичное представление маски: так легче отсчитывать биты. Так, разумеется, можно за один раз установить хоть все биты в регистре — в этом отличие команды sbr от sbi, которая устанавливает только по одному биту.

Аналогично работает команда сброса бита cbr Flag, 0b000010000. Только для того, чтобы ее можно было записывать в точности в том же виде, что и sbr, логическая операция, которую она осуществляет, сложнее: Flag AND (NOT 0b000100000). Здесь сначала в маске инвертируются все биты (реально это производится вычитанием ее из числа $FF, т. е. нахождением дополнения до 1), а затем полученное число и значение регистра комбинируются операцией логического умножения (а не сложения, как в предыдущем случае). В результате четвертый бит обнулится обязательно, а все остальные останутся в неприкосновенности. Кстати, обнулять все биты некоего регистра R удобнее и нагляднее не командой cbr R, $FF, а с помощью инструкций clr R или ldi R,0.

Призываю вас об этой разнице между регистрами общего назначения и регистрами ввода/вывода не забывать. Я и сам до сих пор «попадаюсь» на том, что в случае необходимости обнуления бита 1 в рабочем регистре temp записываю cbr temp, 1 (аналогично верной команде cbi portB,1), хотя такая операция обнулит не первый, а нулевой бит в temp. А операция cbr R, 0 (как и операция sbr R, 0) вообще ничего не делает, и такая запись бессмысленна.

Команды переноса данных

Последнее, что мы рассмотрим в этом разделе — команды, которые употребляются для переноса данных из одной области памяти в другую (здесь память рассматривается в широком смысле этого слова, и в нее включаются также и регистры). Некоторые команды из этой группы нам уже знакомы — это ldi и mov. Первая загружает в регистр непосредственное число (но действует только для регистров, начиная с r16), а вторая — значение другого регистра. Отметим еще, что для ldi очень часто применяется форма записи, которую можно пояснить следующим практическим примером:

ldi temp, (1<

Смысл этого выражения в том, что мы устанавливаем в единицы для регистра temp только биты с указанными именами (естественно, последние должны быть где-то определены, в данном случае это сделано в inc-файлах). Обратите внимание, что в отличие от команды sbi, остальные биты будут одновременно обнулены, а не останутся при своих значениях. Такая форма очень удобна для задания поименованных битов в процессе инициализации служебных регистров (при использовании «законной» команды sbi нужные биты пришлось бы указывать в числах, и предварительно обнулять регистр). В данном случае мы хотим инициализировать последовательный порт UART, и приведенная форма записи означает, что устанавливается разрешение приема (RXEN) и передачи (TXEN), причем и для того и для другого устанавливается 8-битный режим (RXB8 и TXB8). Подробнее мы в этом разберемся в главе 16, когда будем «проходить» программирование UART, а пока заметим, что еще. не все доделали: установили биты в регистре temp, но он-то какое отношение имеет к последовательному порту?

Потому следующей по тексту программы командой мы обязаны перенести установленное значение в соответствующий регистр ввода/вывода, для которого, собственно, поименованные биты и имеют значение, называющийся UCR. Это делается традиционной для всех ассемблеров командой out:

out UCR,temp

Замечу, что указанные команды по отношению к UART справедливы для семейства Classic, для Mega это делается несколько сложнее (a Tuny, кроме модели 2313, вообще UART не имеют), но сейчас это неважно. В паре к команде out идет симметричная команда in (чтения данных из I/О-регистра).

Перейти на страницу:

Поиск

Похожие книги