Главная страница
Библиотека (скачать книги)
Скачать софт
Введение в программирование
Стандарты для C++
Уроки по C#
Уроки по Python
HTML
Веб-дизайн
Ассемблер в среде Windows
ActiveX
Javascript
Общее о Линукс
Линукс - подробно
Линукс - новое
Delphi
Паскаль для начинающих
Турбопаскаль
Новости
Партнеры
Наши предложения
Архив новостей





Если вы посмотрите таблицу команд в приложении 2, то можете обратить внимание, что из восьмибитовых арифметических операций с константой доступно только вычитание (subi, suci), напрашивающейся операции сложения с константой нет. Это не упущение автора при формировании выборочной таблицы, а действительная особенность системы команд AVR. Ограничение легко обходится вычитанием отрицательного числа (например, команда subi temp,-ю прибавит 10 к temp), но практике такая операция не очень-то требуется, потому что разработчики семейства AVR решили облегчить жизнь пользователям, добавив в перечень арифметических команд две очень удобные команды — adiw и sbiw — по сути они делают то же самое, что пары команд add/adc (sub/sbc), только за одну операцию, и притом складывают с константой, а не с регистром.

Единственный их недостаток— работают они только с определенными парами регистров: с четырьмя парами, начиная с г24-г25. Три старшие пары (r26-r27, г28-г29 и r30-r3l) носят еще название х, Y и z, и мы их будем "проходить" далее в этой главе — они задействованы в операциях обмена данными с SRAM. Но, к счастью, точно так же работает и пара г24-г25, которая более нигде вместе не употребляется, и это очень удобно. Независимо от используемой пары, старшим регистром считается тот, что с большим номером, а операцию нужно проводить с младшим, при этом перенос учтется автоматически. Например, в результате выполнения последовательности команд- clr г25 ldi г24,100 adiw г24,200
в регистрах г25:г24 окажется число 300 (в г25 будет записано $01, что эквивалентно 256 для 16-разрядного числа, а в r24 ^ $2С = 44, что в сумме и даст 300). Аналогично работает и процедура вычитания константы sbiw.

Команды пересылки данных
Здесь мы рассмотрим команды, которые переносят данные из одной области памяти в другую (память рассматривается в широком смысле этого слова, и в нее включаются также и регистры). Некоторые команды из этой группы нам уже знакомы — это ldi и mov. Первая загружает в регистр непосредственно число-константу (но действует только для регистров, начиная с г1б), а вторая — значение другого регистра. Повторим, что ldi очень часто записывают с использованием выражений, что можно пояснить следующим практическим примером:
ldi temp, (1«RXEN 11«TXEN 11«RXB8 11«ТХВ8)

Напомним, что при указании функции "побитового ИЛИ" скобки ставить необязательно (ее приоритет выше, чем у операции сдвига). Смысл этого выражения в том, что мы устанавливаем в единицы для регистра temp только биты с указанными именами (естественно, последние должны быть где-то определены — в данном случае это сделано в inc-файлах). В рассмотренном примере мы хотим инициализировать последовательный порт UART, и приведенная форма записи означает, что устанавливается разрешение приема (RXEN) и передачи (TXEN), причем и для того и для другого задается 8-битовый режим
(RXB8 и ТХВ8).

Обратите внимание, что, в отличие команды sbi, неуказанные биты будут в этой операции обнулены, а не останутся при своих значениях. Такая форма очень удобна для задания поименованных битов в процессе инициализации служебных регистров. Вместо имен могут быть указаны непосредственно номера битов, но записывать их в такой форме нецелесообразно — здесь как раз удобнее указывать имена. Непосредственная установка через константу заставляет рыться в справочнике или в inc-файлах в поиске номеров поименованных битов:
ldi temp,ObOOOllOll ;TXEN=1,RXEN=1,RXB8=1,TXB8=1

А при использовании "законной" команды sbi пришлось бы делать то же самое, но еще и предварительно обнулять регистр.
Понятно, что установить биты в рабочем регистре temp для инициализации UART недостаточно. Потому следующей по тексту программы командой мы обязаны перенести установленное значение в соответствующий РВВ, называющийся в данном случае UCR (для семейства Classic, в Mega регистр установок последовательного порта называется иначе, см. главу 13). Это делается традиционной для всех ассемблеров командой out: out UCR, temp
В паре к out идет симметричная команда in— чтение данных из РВВ. Эти две команды также относят к командам переноса данных.

Следующими по важности командами пересылки данных будут команды загрузки и чтения SRAM — id и st. С этими командами связаны такие "жуткие" понятия, как "прямая" и "косвенная" адресации, а также "относительная косвенная адресация" и т. п. (по моему убеждению, этот раздел в описаниях МК AVR спокойно можно пропускать при чтении— вот для х5\ способы адресации действительно имеют большое значение). Мы постараемся термин "адресация" вообще не употреблять, и разберем здесь три основных режима чтения/записи SRAM: простой, а также с преддекрементом и постинкрементом. Все три встречаются очень часто, хотя два последних режима работают не во всех типах AVR.

Во всех случаях при чтении и записи SRAM потребуются регистры х, Y и z — т. е. пары r27:r26, г29:г28 и г31:г30 соответственно, которые по отдельности еще именуют XH:XL, YH: YL, ZH: ZL— в том же порядке (т. е. старшим в каждой паре служит регистр с большим номером). Если обмен данными производится между памятью и другим регистром общего назначения, то достаточно одной из этих пар (любой), если же между областями памяти — целесообразно задействовать две. Независимо от того, какую из пар мы используем, чтение и запись происходят по идентичным схемам, меняются только имена регистров.

Покажем основной порядок действий при чтении из памяти для регистра z (гЗКгЗО). Чтение одной ячейки с заданным адресом Address, коррекция ее значения и последующая запись выполняются так, как показано в листинге 6.8.

Листинг 6.8
ldi ZH,High(Address) /старший байт адреса RAM ldi ZL,Low(Address) /младший байт адреса RAM Id temp,Z ;читаем ячейку в temp inc temp /например, увеличиваем значение на 1 st Z,temp ;и снова записываем

Заметки на полях
При всех подобных манипуляциях нужно внимательно следить за двумя вещами: во-первых, за тем, чтобы не залезть в несуществующую область памяти (если объем SRAM составляет 512 байт, как в большинстве моделей, которые мы будем использовать, то ZH в данном примере может иметь значения только О или 1). Но еще важнее не забыть, как мы уже говорили, что младшие адреса SRAM заняты регистрами (в большинстве моделей под это зарезервированы первые 96 адресов, от $00 до $5F). И запись, например, по адресу $0000 (ZH=0, ZL=0) равносильна записи в регистр гО. Во избежание коллизий я по возможности поступаю следующим образом: резервирую пару ZH, ZL только под запись/чтение в память и устанавливаю с самого начала регистр ZH в единицу. Тогда при любом значении ZL мы будем просматривать только старшие 256 байтов из 512, чего для практических нужд обычно достаточно. Обязательно нужно помнить, что если в программе имеются вызовы процедур и прерываний, то последние адреса SRAM использовать нельзя — мы сами дали в начале программы команду выделить их под стек.



     
 

Библиотека программиста. 2009.
Администратор: admin@programmer-lib.ru