4.1. Ассемблер

Как известно, наиболее эффективные программы получаются при использовании языка Ассемблер. Стоит, правда, отметить, что при этом также увеличивается сложность и время разработки программы. Для микроконтроллеров семейства AVR имеется свободно распространяемый транслятор ассемблера — wavrasm. Также одновременно с транслятором ассемблера устанавливается программа для отладки программ на языке ассемблера для микроконтроллеров семейства AVR. Однако она заметно уступает свободно распространяемому фирмой Atmel отладчику AVR Studio, поэтому ее мы рассматривать не будем.

В этой главе читатели познакомятся с описанием транслятора ассемблера wavrasm. Этот транслятор преобразует команды в виде текстовых мнемоник (специальных сокращений) в закодированные в виде чисел-кодов команды микроконтроллеров. Полученный код можно использовать для работы совместно с отладчиком для проверки правильности работы программы. Также в результате работы транслятора можно получить так называемый файл прошивки, который используется программатором для занесения программы в память программ микроконтроллера.

Транслятор ассемблера работает в среде Microsoft Windows 3.11. Microsoft Windows 95/98 и NT. Кроме того, имеется версия ассемблера, работающая из командной строки MS-DOS. Она устанавливается одновременно с версией для Windows. Версия для Windows имеет встроенный полноэкранный текстовый редактор и справочную систему на английском языке.

В этом описании отсутствует описание системы команд микроконтроллеров, так как в главе 2 имеется таблица команд, и описаны способы адресации.

Это описание предполагает, что транслятор wavrasm правильно установлен на компьютер, на котором происходит работа.

Начало работы

Запустите транслятор ассемблера. С помощью команды меню File» Open откройте файл tutor.asm. В результате выполнения этой команды исходный текст программы на ассемблере будет загружен в программу и показан на экране. На рис. 4.1 показан примерный вид экрана.

Рис. 4.1. Окно транслятора с загруженной программой

Ассемблирование первой программы

После того как вы просмотрели текст, выберите команду меню Assemble. После этого появится второе окно (окно сообщений), которое содержит сообщения об ошибках. Окно сообщений будет располагаться поверх окна с исходным текстом программы на ассемблере, поэтому удобно предпринять некоторые действия по настройке расположения окон. Перейдите в окно с исходным текстом программы (просто щелкнув левой кнопкой мышки в любом месте текста программы) и выберите команду меню Windows» Tile Horizontal. Кроме того, полезно увеличить размер окна с исходным текстом программы и уменьшить окно сообщений. Для этого следует переместить верх окна сообщений с помощью мышки ниже. В результате на экране должна получиться картинка, похожая на изображенную на рис. 4.2.

Рис. 4.2. Вид экрана транслятора ассемблера с двумя окнами

Поиск и исправление ошибок

Глядя на окно сообщений, можно сделать вывод, что в процессе трансляции программы были обнаружены ошибки. В окне сообщений ошибки показываются следующим образом: в строке подряд идут название файла, в скобках номер строки, в которой обнаружена ошибка, и, наконец, краткое текстовое сообщение о характере ошибки. Естественно, ошибку следует найти и исправить. Щелкните левой кнопкой мышки на первом сообщении об ошибке в окне сообщений (которая находится на 7-й строке). Обратите внимание, что в окне с исходным текстом на строке 7 появится вертикальная красная линия. Сообщение об ошибке говорит о том, что как имена регистров можно использовать только имена r0…r31. Это верно, так как микроконтроллеры семейства AVR имеют 32 регистра общего назначения, а в строке 7 программы указано имя регистра r39, которого не существует. Фотография окна программы с описанной ситуацией показана на рис. 4.3.

Рис. 4.3. Окно программы с выделенной строкой с ошибкой

Двойной щелчок на сообщении ошибки в окне сообщений приводит к тому, что окно текстового редактора исходного текста становится активным, а курсор устанавливается в начало строки с ошибкой. Исправьте r39 на r19.

Ниже в окне сообщений показано еще сообщение об ошибке. Щелкните левой кнопкой мышки по следующему сообщению об ошибке.

Сообщение Illegal argument type or count говорит о том, что что-то неправильно в аргументах команды. Обратите внимание, что один из аргументов — тот самый, который мы только что исправили. Просмотрев все сообщения об ошибках, можно прийти к выводу, что все остальные ошибки были связаны с первой.

Чтобы определить, все ли ошибки исправлены, имеет смысл снова запустить трансляцию программы. Если ошибки остались, следует их исправить. Если ошибок больше нет, в окне сообщений появится сообщение об успешном завершении трансляции.

Формат программы на ассемблере

Программа на ассемблере представляет собой текстовый файл, который состоит из мнемоник — символьных обозначений команд микроконтроллера, меток и директив.

Любая строка может начинаться с метки — строки из символов и (или) цифр, заканчивающейся двоеточием.

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

Строка исходного текста может иметь один из следующих видов:

1. [метка: ] директива [аргументы директивы] [комментарий]

2. [метка: ] мнемоника команды [аргументы команды] [комментарий]

3. Комментарий

4. Пустая строка

Комментарии всегда начинаются с символа «;».

Элементы, заключенные в квадратные скобки, могут отсутствовать. Текст, расположенный после символа «точка с запятой» до конца строки, полностью игнорируется ассемблером. Использование меток, мнемоник команд микроконтроллера и директив ассемблера подробнее будет рассмотрено чуть позднее.

Примеры записи строк:

label1:.EQU var1=100; Директива определения символьного

                                ; имени var1, эквивалентного записи ”100"

          .EQU var2=200; Определение имени var2, соответствующего "200"

test: rjmp test; Бесконечный цикл (мнемоника команды микроконтроллера)

; Пустая строка

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

Команды микроконтроллера

Транслятор ассемблера позволяет использовать в тексте программы мнемоники (обозначения команд микроконтроллера), полностью совпадающие с их названием в системе команд микроконтроллера.

Команды микроконтроллеров семейства AVR делятся на несколько групп:

• арифметические и логические;

• команды условных и безусловных переходов;

• команды передачи данных;

• команды для работы с битами.

Краткое описание команд микроконтроллера можно найти в главе 2.

Для транслятора ассемблера нет разницы, какими буквами написаны слова, т. е. rjmp и RJMP совершенно равнозначны. Однако для удобства понимания программы рекомендуется все мнемоники и метки записывать строчными (маленькими) буквами, а директивы прописными (большими).

Директивы транслятора ассемблера

Транслятор ассемблера поддерживает достаточно много директив. Директивы не транслируются в программу для микроконтроллера. Они используются для указания транслятору ассемблера данных о расположении программы в памяти микроконтроллера, определения макросов и т. д.

Ниже приведен перечень директив транслятора ассемблера:

.BYTE — резервирует 1 байт для использования в качестве переменной;

.CSEG — сегмент программ;

.DB — определяет байт-константу;

.DEF — определяет символическое имя для регистра;

.DEVICE — задает тип целевого микроконтроллера;

.DSEG — сегмент данных;

.DW — определяет слово-константу;

.ENDMACRO — конец определения макроса;

.EQU — сопоставляет символьному имени арифметическое выражение;

.ESEG — сегмент EEPROM;

.EXIT — выйти из файла (конец текста программы);

.INCLUDE — загрузить исходный текст из другого файла;

.LIST — включить генерацию листинга;

.LISTMAC — включить печать содержимого макросов в листинге;

.MACRO — начать определение макроса;

.NOLIST — выключить генерацию листинга;

.ORG — установить расположение;

.SET — сопоставить символу выражение.

Обратите внимание, что все директивы должны начинаться с точки.

.BYTEрезервирует место (или несколько мест) размером 1 байт для переменной.

Директива BYTE резервирует один байт в памяти SRAM для реализации переменной. Для того чтобы иметь возможность обращаться к этой переменной, перед директивой BYTE должна стоять метка. Директива имеет один параметр — количество байтов для резервирования. Директива может использоваться только для резервирования места в памяти данных (смотри директивы CSEG, DSEG и ESEG).

Синтаксис:

Метка:.BYTE числовое выражение

Примеры:

.DSEG

var1:.BYTE 1; Резервируем 1 байт для переменной var1

able:.BYTE tab_size; Резервируем tab_size байт

.CSEG

    ldi r30,low(var1); Загружаем младший байт Z-регистра

    ldi r31,high(var1); Загружаем старший байт Z-регистра

    Id r1,Z; Загрузить содержимое переменной var1 в r1

.CSEG — сегмент кода.

Директива CSEG определяет начало сегмента кода (программ). В исходном тексте программы может быть несколько сегментов кода. Транслятор ассемблера в процессе компиляции программы объединяет все сегменты кода в один. Директива BYTE не может быть использована в сегменте кода. Если в программе нет явного указания названия сегмента, по умолчанию считается, что это сегмент кода. Директива CSEG не имеет никаких параметров. Сегмент кода имеет свой счетчик слов. Директива-ORG может быть использована для размещения кода или констант в определенном программистом месте памяти программ.

Синтаксис:

.CSEG

Пример:

.DSEG; Начало сегмента данных

     vartab: BYTE 4; Резервируем 4 байта в SRAM

.CSEG; Начало сегмента кода

     const:.DW 2; Запишем число 0x0002 в память программ

     mov r1,r0; Что-нибудь сделаем

. DB — определить байты-константы в памяти программ или EEPROM.

Директива DB резервирует место в памяти программ или EEPROM. Для того чтобы иметь возможность обращаться к зарезервированному пространству, перед этой директивой следует ставить метку. Директива DB может быть расположена только в сегменте кода или EEPROM. Параметрами директивы DB является список выражений.

Список выражений представляет собой одно или несколько выражений, разделенных запятыми. Каждое выражение может быть равно числу от -128 до 255. Если выражение представляет собой отрицательное число, оно будет помещено в намять программ или EEPROM в дополнительном коде.

Если директива DB расположена в сегменте кода и имеет больше, чем одно выражение в списке параметров, выражения упаковываются таким образом, что два байта располагаются в одном слове памяти программ. Если число выражений нечетное, последнее выражение будет помещено в отдельное слово памяти программ, даже если после директивы DB следом расположена еще одна директива DB.

Синтаксис:

Метка:.DB список выражений

Пример:

.CSEG

     const:.DB 0, 255, 0Ь01011100, — 128,0хаа

.ESEG

      eeconst:.DB 0xff

.DEF — назначить регистру символьное имя.

Директива DEF позволяет назначить регистру символьное имя, что позволяет сделать программу гораздо понятнее и нагляднее. Можно назначить одному регистру несколько символьных имен. Символьное имя регистра может быть переопределено в последующем тексте программы.

Синтаксис:

.DEF символьное имя = регистр

Пример:

.DEF temp=r16.

.DEF for=r0

.CSEG

     ldi temp, 0xf0; Загрузить в регистр temp число 0xf0

     in ior, 0x3f; Прочитать содержимое SREG и записать в регистр ior

     еог temp, ior; Исключающее ИЛИ между регистрами temp и ior

.DEVICE — определяет тип целевого микроконтроллера.

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

Синтаксис:

DEVICE AT9DS1200 | AT90S2313 | AT9DS2323 | AT90S2343 | AT90S4414 | AT90S8515 | ATMEGA103

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

Пример:

.DEVICE AT90S1200; Используется микроконтроллер AT90S1200

.CSEG

     push r30; Эта запись вызовет сообщение о том, что выбранное устройство не поддерживает эту инструкцию

.DSEG — сегмент данных.

Директива DSEG определяет начало сегмента данных. В исходном тексте программы на ассемблере может быть несколько сегментов данных. В процессе трансляции все они будут объединены в один. Обычно сегмент данных содержит только директивы BYTE с метками. Сегмент данных имеет свой счетчик байтов. Директива ORG может быть использована для расположения переменных в конкретных местах SRAM. Директива DSEG не имеет параметров.

Синтаксис:

.DSEG

Пример:

.DSEG;Начало сегмента данных

     var1:.BYTE 1; Резервируем 1 байт для переменной var1

     table:.BYTE tab_size; Резервируем tab_size байт

.CSEG

     ldi r30,low(var1);Загружаем младший байт Z-регистра

     ldi r31.high(var1);Загружаем старший байт Z-регистра

     Id r1,Z ;Загрузить содержимое переменной var1 в r1

.DW — определение слов-констант в памяти программ или EEPROM.

Директива DW резервирует место в памяти программ или EEPROM. Для того чтобы иметь возможность обращаться к зарезервированному пространству, перед этой директивой следует ставить метку. Директива DW должна быть расположена в сегменте кода или EEPROM. Параметрами директивы DW является список выражений.

Список выражений представляет собой одно или несколько выражений, разделенных запятыми. Каждое выражение может быть равно числу от -32768 до 65535. Если выражение представляет собой отрицательное число, оно будет помещено в память программ или EEPROM в дополнительном коде.

Синтаксис:

Метка:.DW список выражений

Пример:

.CSEG

     varlist:.DW 0,56255, 0b0101110011101011, -12128, 0xaaff

.ESEG

     eevar:.DW 0xff17

.ENDMACRO — конец описания макрокоманды.

Директива ENDMACRO определяет конец описания макрокоманды. Директива не имеет параметров. Для получения информации о макрокомандах смотри директиву MACRO.

Синтаксис:

.ENDMACRD

Пример:

MACRO SUBI16; Начало определения макрокоманды

      subi r16,low(@0); Вычитаем младший байт

      sbci r17, high(@0); Вычитаем старший байт

.ENDMACRO; Конец определения макрокоманды

.SET — присвоить символьному обозначению выражение.

Директива SET присваивает символьному обозначению значение выражения. В дальнейшем это символьное обозначение может быть использовано в выражениях. Присвоенное значение — константа. В дальнейшем тексте программы это символьное выражение не может быть переопределено или изменено.

Синтаксис:

.EQU <символьное обозначение> = <выражение>

Пример:

.EQU io_offset = 0x23

.EQU porta = io_offset + 2

.CSEG; Начало сегмента кода

      clr r2; Очистить регистр r2

      out porta,r2; Записать в порт А

.ESEG — EEPROM сегмент.

Директива ESEG определяет начало EEPROM сегмента. В исходном тексте программы может быть несколько EEPROM сегментов. Транслятор ассемблера в процессе компиляции программы объединяет все EEPROM сегменты в один. Директива BYTE не может быть использована в EEPROM сегменте. Директива ESEG не имеет никаких параметров. Сегмент EEPROM имеет свой счетчик байтов. Директива. ORG может быть использована для размещения кода или констант в определенном программистом месте памяти EEPROM.

Синтаксис:

.ESEG

Пример:

.DSEG; Начало сегмента данных

     vartab:.BYTE 4; Резервируем 4 байта в SRAM

.ESEG

     eevar:.DW 0xff67; Инициализируем одно слово в EEPROM

.CSEG;Начало сегмента кода

     const:.DW 2;Запишем число 0x0002 в память программ

     mov r1,r0;Что-нибудь сделаем

.EXIT — конец текста программы.

Директива EXIT указывает транслятору ассемблера, что следует завершить трансляцию программы. При отсутствии этой директивы транслятор ассемблера работает до тех пор, пока исходный файл не закончится (EOF). Если директив EXIT встречается в файле, включаемом в текст директивой INCLUDE, транслятор ассемблера продолжит работу со строки, следующей после соответствующей директивы INCLUDE.

Синтаксис:

.EXIT

Пример:

.EXIT; Завершить обработку этого файла

.INCLUDE — вставить файл.

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

Синтаксис:

.INCLUDE "имя файла"

Пример:

; Файл iodefs.asm

.E0U sreg=0x3f; Регистр статуса

.EQU sphigh=0x3e; Старший байт стека

.EOU splow=0x3d; Младший байт стека

;Файл incdemo.asm

.INCLUDE "iodefs.asm"; Включить в текст программы файл incdemo.asm

     in r0.sreg; Прочитать содержимое регистра статуса

.LIST — включить генерацию листинга.

Директива LIST включает генерацию листинга. Ассемблер генерирует листинг, содержащий исходный текст на ассемблере, адреса и коды операций. По умолчанию генерация листинга включена. В комбинации с директивой NOLIST можно организовать печать только нужных фрагментов программы.

Синтаксис:

.LIST

Пример:

.N0LIST; Отключить генерацию листинга

.INCLUDE "macro.inc"; Включаемые файлы не будут

.INCLUDE “const.def"; показаны в листинге

.LIST; Включить генерацию листинга

.LISTMAC — включить раскрытие макрокоманд.

Директива LISTMAC указывает транслятору ассемблера на необходимость показа в листинге содержимого макрокоманд. По умолчанию в листинге показывается только название макрокоманды.

Синтаксис:

.LISTMAC

Пример:

MACRO МАСХ; Определить макрокоманду

     add r0,@0

     еог г1,@1

.ENDMACRO; Конец определения макрокоманды

.LISTMAC

      МАСХ r2,r1; Вызов макрокоманды. В листинге будет показан ее текст

.MACRO — начало определения макрокоманды.

Директива MACRO указывает транслятору ассемблера на начало определения макрокоманды. Параметром директивы MACRO является имя определяемой макрокоманды. В дальнейшем при обнаружении в тексте программы имени макрокоманды транслятор ассемблера будет фактически заменять это имя на содержание макрокоманды. Макрокоманда может иметь до 10 параметров. Эти параметры имеют фиксированные имена: @0…@9. При вызове макрокоманды параметры должны быть представлены в виде списка, разделенного запятыми. Определение макрокоманды завершается директивой ENDMACRO.

При определении новой макрокоманды нельзя использовать другие макрокоманды (т. е. нельзя использовать вложенные макрокоманды).

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

По умолчанию в листинге генерируется только вызов макрокоманды. Чтобы получить в листинге содержимое макрокоманд, следует использовать директиву LISTMAC. Текст макрокоманды в листинге помечен символом «+».

Синтаксис:

.MACRO

Пример:

MACRO SUBI16; Начало определения макрокоманды

      subi r16,low(@0); Вычитаем младший байт

      sbci r17,hlgh(@0); Вычитаем старший байт

ENDMACRO; Конец определения макрокоманды

CSEG; начало сегмента кода

    SUBI16 9x1234,r16,r17; Вычесть 0x1234 из r17:r16

Примечание: r17:r16 в данном случае — пара регистров, содержащая 16-разрядное число.

.NOLIST — включить генерацию листинга.

Директива NOLIST выключает генерацию листинга. Ассемблер генерирует листинг, содержащий исходный текст на ассемблере, адреса и коды операций. По умолчанию генерация листинга включена. В комбинации с директивой LIST можно организовать печать только нужных фрагментов программы.

Синтаксис:

.NOLIST

Пример:

.NOLIST; Отключить генерацию листинга

.INCLUDE "macro.inc" ; Включаемые файлы не будут

.INCLUDE "const.def"; показаны в листинге

.LIST; Включить генерацию листинга

.ORG — установка значения счетчика расположения.

Директива ORG присваивает абсолютное значение счетчику. Параметром директивы является значение, которое должно быть присвоено счетчику. При использовании директивы ORG в сегменте данных будет определено значение, указывающее расположение и оперативной памяти SRAM. При использовании директивы ORG в сегменте кода будет определено значение, указывающее расположение в памяти программ. При использовании директивы ORG в сегменте EEPROM будет определено значение, указывающее расположение в памяти EEPROM.

Если перед директивой расположена метка (на этой же строке), метка получит значение параметра директивы. Значение по умолчанию для сегмента кода и EEPROM равно 0, а для SRAM — 32 (так как регистры занимают пространство с 0 до 31). Обратите внимание, что для EEPROM и SRAM отсчитываются байты, в то время как в памяти программ — слова.

Синтаксис:

.ORG выражение

Пример:

.DSEG; Начало сегмента данных (SRAM)

.ORG 0x37; Установить адрес SRAM 37Н

     variable:.BYTE 1; Зарезервировать 1 байт по адресу 37Н SRAM

.ESEG;Начало сегмента EEPROM

.ORG 0x20; Установить значение счетчика расположения

      eevar:.DW 0xf77a;Инициализировать слово в памяти EEPROM

.CSEG

.ORG 0x10; Установить счетчик на значение 0x10

mov r0,r1; Эта команда будет расположена в памяти; программ по адресу 0x10

.SET — присвоить символьному обозначению выражение.

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

Синтаксис:

.SET символьное обозначение = выражение

Пример:

SET io_offset = 0x23

.SET porta = io_offset + 2

CSEG; Начало сегмента кода

    clr r2; Очистить регистр г2

    out porta,r2; Записать в порт А

Выражения

Ассемблер позволяет использовать в тексте программы выражения. Они могут содержать операнды, операции и функции. Все выражения имеют разрядность 32 бита.

Операнды

Могут быть использованы следующие операнды:

• определенные программистом метки, имеющие значение счетчика, в зависимости от места своего расположения;

• переменные, определенные с помощью директивы SET;

• константы, определенные с помощью директивы EQU;

• целые константы:

— десятичные (по умолчанию): 10,255,

— шестнадцатеричные (два вида записи): 0x0а, $0а, 0xff, $ff,

— двоичные: 0Ь00001010, 0b11111111;

• коды символов ASCII: 'А', 'а';

• строки ASCII (без нуля в конце строки): «String»;

• PC — текущее значение счетчика команд в памяти программ.

Функции

LOW(выражение) — возвращает младший байт выражения;

НIGH(выражение) — возвращает старший байт выражения;

ВУТЕ2(выражение) — возвращает 2 байта выражения;

ВУТЕ3(выражение) — возвращает 3 байта выражения;

ВУТЕ4(выражение) — возвращает 4 байта выражения;

LWRD(выражение) — возвращает биты 0—15 выражения;

HWRD(выражение) — возвращает биты 16–31 выражения;

РАGЕ(выражение) — возвращает биты 16–21 выражения;

ЕХР2(выражение) — возвращает 2^ выражения;

LOG2(выражение) — возвращает целую часть lоg 2(выражение).

Операции

Ассемблер поддерживает различные операторы, описанные ниже. При их использовании можно применять скобки.

Логическое НЕ

Обозначение: !

Описание: унарный оператор, возвращает 1, если выражение равно нулю, и 0, если выражение было не равно нулю.

Приоритет: 14.

Пример: ldi r16,!0xf0; Загрузить в г16 0x00

Побитовое НЕ

Обозначение: ~

Описание: унарный оператор, который возвращает исходное выражение со всеми инвертированными битами.

Приоритет: 14.

Пример: ldi r16.~0xf0; Загрузить в r16 0x0f

Унарный минус

Обозначение:

Описание: возвращает число с измененным на противоположный знаком.

Умножение

Обозначение: *

Описание: возвращает результат умножения двух чисел. Приоритет: 13.

Пример: ldi r30,label*2; Загрузить в регистр r30 label*2

Деление

Обозначение: /

Описание: возвращает целую часть от деления левого параметра на правый.

Приоритет: 13.

Пример: ldi r30, label/2; Загрузить в регистр r30 label/2

Сложение

Обозначение: +

Описание: возвращает сумму двух чисел.

Приоритет: 12.

Пример: ldi г30,с1+с2; Загрузить в регистр r30 с1+с2

Вычитание

Обозначение: -

Описание: возвращает результат вычитания правого числа из левого.

Приоритет: 12.

Пример: ldi г17,с1-с2; Загрузить в регистр r30 с1-с2

Сдвиг влево

Обозначение: <<

Описание: возвращает значение левого числа, сдвинутое влево на число раз, равное правому числу.

Приоритет: 11.

Пример: ldi r17,1<<3; Загружает в регистр г17 число 1, сдвинутое влево на 3 бита

Сдвиг вправо

Обозначение: >>

Описание: возвращает значение левого числа, сдвинутое вправо на число раз, равное правому числу.

Приоритет: 11.

Пример: ldi r17,1>>2; Загружает в регистр r17 число 1, сдвинутое вправо на 2 бита

Меньше

Обозначение: <

Описание: возвращает 1, если первое число меньше второго, иначе— 0.

Приоритет: 10.

Пример: ori r18,bitmask*(c1<c2)+1

Меньше или равно

Обозначение: <=

Описание: возвращает 1, если первое число меньше второго или равно ему, иначе — 0.

Приоритет: 10.

Пример: ori r18,bitmask*(c<=c2)+1

Больше

Обозначение: >

Описание: возвращает 1, если первое число больше второго, иначе— 0.

Приоритет: 10.

Пример: ori r18,bitmask*(c1>c2)+1

Больше или равно

Обозначение: >=

Описание: возвращает 1, если первое число больше второго или равно ему, иначе — 0.

Приоритет: 10.

Пример: ori r18,bitmask*(c1>=c2)+1

Равно

Обозначение: ==

Описание: возвращает 1, если первое число равно второму, иначе — 0.

Приоритет: 9

Пример: andi г19, bitmask*(c1==c2)+1

Не равно

Обозначение: !=

Описание: возвращает 1, если первое число не равно второму, иначе — 0.

Приоритет: 9.

Пример:.SET flag=(c1!=с2)

Побитовое И

Обозначение: &

Описание: возвращает результат побитной операции «И» между операндами.

Приоритет: 8.

Пример: ldi r18,High(c1&c2)

Побитовое исключающее ИЛИ

Обозначение: ^

Описание: возвращает результат побитной операции «исключающее ИЛИ» между операндами.

Приоритет: 7.

Пример: ldi r18,Low(c1^c2)

Побитовое ИЛИ

Обозначение: |

Описание: возвращает результат побитной операции «ИЛИ» между операндами.

Приоритет: 6.

Пример: ldi ri8,Low(c2|c2)

Логическое И

Обозначение: &&

Описание: возвращает 1, если оба выражения не равны нулю, иначе — 0.

Приоритет: 5.

Пример: ldi r8,Low(ci&&c2)

Логическое ИЛИ

Обозначение: ||

Описание: возвращает 0, если оба выражения равны нулю, иначе — 0.

Приоритет: 4.

Пример: ldi r18,Low(ci||с2)

Описание программы WAVRASM

Здесь опишем специфические особенности применения транслятора ассемблера WAVRASM.

Открытие файла программы

Теоретически нет ограничений на количество одновременно oткрытых файлов исходных текстов. Размер каждого файла не должен превышать примерно 28 Кб. Для работы с файлами большего размера следует использовать версию ассемблера, работающую из командной строки MS-DOS — avrasm. Также можно разбить всю программу на несколько файлов и объединить их с помощью директивы INCLUDE.

Для каждого открытого файла создается окно с его текстом.

Для создания нового файла следует выполнить команду меню File>>New (быстрая комбинация клавиш: Alt-F N). Для открытия существующего файла следует выполнить команду меню File>>Open (быстрая комбинация клавиш: Alt-F О).

Встроенный текстовый редактор

Перемещение по тексту программы

Для перемещения по тексту программы можно пользоваться следующими командами:

вправо — стрелка вправо;

влево — стрелка влево;

вверх — стрелка вверх;

вниз — стрелка вниз;

в начало строки — Ноmе;

в конец строки — End;

в начало файла — Ctrl+Home;

в конец файла — Ctrl+End.

Редактирование текста

Для редактирования текста следует пользоваться клавишами:

— вставить пробел — пробел;

— завершить строку — Enter;

— удалить символ слева от курсора — Backspace;

— удалить символ справа от курсора — Del.

Для разбиения строки на две следует установить курсор на место разбиения и нажать Enter.

Для объединения двух строк следует установить курсор в начало второй строки и нажать клавишу Backspace.

Выделение текста, операции копирования, перемещения и удаления осуществляются так же, как в любой программе для Windows.

Установка опций программы

Некоторые установки транслятора ассемблера могут быть изменены. Для этого следует выполнить команду меню Options. Появится окно, подобное изображенному на рис. 4.4.

Рис. 4.4. Окно установки опций программы

В этом окне можно установить расширение файла, содержащего листинг программы и файла с оттранслированным кодом. Менять их не рекомендуется.

Также здесь можно указать, какого типа должен генерироваться выходной файл. Имеется три типа файлов: Generic, Motorola S-record и Intel HEX.

Обратите внимание, что объектный файл (который используется отладчиком) всегда имеет расширение obj. Также, если в программе инициализируются значения в памяти EEPROM, генерируется файл с расширением еер, используемый программатором для прошивки в микроконтроллер в процессе программирования. Этот файл генерируется в формате Generic.

Опция Wrap relative jumps — разрешить относительную адресацию переходов. Эта опция полезна для использования с микроконтроллерами, имеющими 4 К слов памяти программ.

Опция Save before assemble — сохранять исходный текст программы каждый раз перед ее ассемблированием.

Версия ассемблера для командной строки

Одновременно с установкой транслятора ассемблера для Windows, устанавливается версия для работы из командной строки MS-DOS. Эта версия транслятора не имеет никаких ограничений по объему транслируемой программы (т. е., в отличие от версии для Windows, размер файла может быть больше 28 кбайтов).

Вызывается программа следующим образом:

avrasm [-m|-i|-g] input.asm output.lst output.hex

В результате выполнения программы будет прочитан файл input.asm, сгенерирован файл листинга listfile.lst, файл скомпилированного кода для загрузки в память программ микроконтроллера output.hex и объектный файл *.obj, используемый отладчиком.

Назначение ключей программы

m — генерировать файл кода в формате Motorola S-Record;

i — генерировать файл кода в формате Intel HEX;

g — генерировать файл кода в формате Generic.

По умолчанию генерируется файл кода в формате Generic.

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

Формат файлов, генерируемых транслятором ассемблера

Формат Generic

Рассматриваемый транслятор ассемблера может генерировать три различных типа файлов: Generic, Motorola S-Records и Intel HEX.

Рассмотрим один из этих форматов — Generic. Файлы этого формата — текстовые.

Структура файла очень проста. Каждая строка файла имеет вид: Адрес: код операции.

Здесь «Адрес» — 6 цифр (24 бита) шестнадцатеричного числа, и «код операции» — 4 цифры (16 битов) шестнадцатеричного числа. «Адрес» определяет адрес в памяти программ, а «код операции» — содержимое памяти по указанному адресу.

В качестве примера рассмотрим программу на ассемблере:

; Демонстрация формата Generic

         mov r0,r1

         inc r1

         call oursub

.org 0x50; Установить адрес в памяти программ на 0x50

oursub: add r1,r2

         ret

В результате трансляции этой программы будет получен файл gen_demo.rom следующего содержания:

000000:2с01

000001:9413

000002:940е

000003:0050

000050:0с12

000051:9508

Обратите внимание на то, что команды, состоящие из двух слов, размещаются в двух строках файла.

Если в программе был определен сегмент EEPROM, то генерируется файл для прошивки в EEPROM. Расширение этого файла еер. Этот файл всегда генерируется в формате Generic.

Формат объектного файла

Объектный файл содержит отладочную информацию и может быть использован отладчиком для проверки правильности работы программы.

Объектный файл имеет две части: record и trailer.

Заголовочная часть имеет следующий формат:

• смещение к исходным именам файлов (4 байга);

• смещение к объектным записям (4 байга);

• число байтов в каждой записи (1 байт);

• число имен файлов во второй части файла (1 байт);

• строку A VR Object File ( означает, что строка завершена 0).

Длительность записей составляет 9 байтов каждая. Формат записи:

• адрес памяти программ (3 байта);

• код операции (2 байта);

• номер инструкции в исходном файле (1 байт, счет начинается с 0);

• номер строки в исходном файле (2 байга, счет начинается с 1);

• индикатор макроса (1 байт, 1 — если макрос, иначе — 0).

И наконец, trailer часть имеет следующий формат:

• имена файлов (заканчивающиеся на 0, число файлов в заголовке);

• ASCII 0.

Для примера рассмотрим программу (файл obj demo.asm):

; Демонстрация объектного формата

.equ const1=0x15

.equ const2=0x40

macro SWIN

      swap @0

      inc @0

.endmacro

start: ldi r16.const1

      SWIN r16

      ldi r16.const2

      SWIN r16

      rjmp start

.include "delay.asm"; Включение другого файла на ассемблере

Включаемый файл (delay.asm):

delay: dec r16

      breq delay

      ret

После трансляции будет получен объектный файл. Файл — бинарный. Для удобства рассмотрения он был переведен в 16-ричный формат, а столбцы были раздвинуты.

Смещение: Содержимое файла (в 16-ричном формате):

00000000: 00000074 Смещение к именам файлов

00000004: 0000001А

00000008: 09

00000009: 02

0000000A: 415652204F626A6563742046696C6500 Cтрока A0F

0000001А: 000000Е10500000В00 Первая запись

00000023: 000001950200000C01

0000002С: 000002950300000C01

00000035: 000003E40000000D00

0000003Е: 000004950200000Е01

00000047: 000005950300000Е01

00000050: 000006CFF900000F00

00000059: 000007950А01000400

00000062: 000008F3F101000500

0000006В: 000009950801000600 Последняя запись

00000074: 4F424A5F44454D4F2E41534D00 "0BJ_DEM0.ASH"

00000081: 44454С41592Е41534D00 "DELAY.ASM"

0000008В: 00 Конец объектного файла