Программирование c нуля в AVRStudio 5 (ч.7)

Автор: Радик Просмотров: 2877


- Составные инструкции в строке.

 

 

Ключевые слова. В отличие от AVRASM встроенные идентификаторы (ключевые слова) зарезервированы и не могут быть переопределены. Ключевые слова включают все инструкции (команды), регистры R0-R31 и X, Y, Z и все функции. Ключевые слова Ассемблер распознаёт независимо от регистра, в котором они набраны, за исключением чувствительных к регистру опций, в которых ключевые слова набираются в нижнем регистре (т.е. "add" зарезервирован, а "ADD" – нет).
Директивы препроцессора. AVRASM2 считает директивами препроцессора все строки, начинающиеся с '#' (или первый непустой символ в строке, так как пробелы и символы табуляции игнорируются).

Комментарии. Дополнительно к классическим комментариям Ассемблера, начинающимся с ';', AVRASM2 признает комментарии в Cи-стиле:
. . . . . . . . . . ; Остальная часть строки является комментарием.
// Подобно ';' остальная часть строки является комментарием.
/* Блок комментариев может располагаться в нескольких строках.
Этот стиль комментариев не может быть вложенным */
Ассемблер распознает разделители комментария (';') в стиле AVRASM, а также комментарии Cи-стиля. Однако ';' используется в синтаксисе языка Cи, что может привести к конфликту при использовании ';' в качестве разделителя комментария, поэтому не рекомендуется использовать комментарии в стиле Ассемблера вместе с директивами препроцессора AVRASM2.
Продолжение строки. Подобно Cи, строки исходных кодов могут быть продолжены посредством '\ '– обратной косой черты в конце строки. Это особенно полезно для длинных макроопределений препроцессора и для длинных директив .db.
Пример:
.db 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 11,12, 21, 214,235,634, \n', 0, 2, \
12, 3,"’это продолжение верхней строки", '\n', 0, 3, 0
Строки и символьные константы. AVRASM2 понимает строки и символы так же, как AVRASM, кроме того, служебные символы, которые не поддерживаются AVRASM. Строка, заключенная в двойные кавычки ("), может быть использована только вместе с директивой .db. Строка передается буквально, никакие служебные символы и NUL-окончания не распознаются. Символьные константы, заключенные в одиночные кавычки ('), могут использоваться везде, где допустимо целое выражение. Служебные символы в Cи-стиле распознаются с тем же значением, как в Cи

 

alt

Ассемблером также распознаются \ooo (ooo = восьмеричное число) и \xhh (hh = шестнадцатеричное число).
Примеры:
.db "Hello\n"
// - эквивалент:
.db 'H', 'e', 'l', 'l', 'o', '\\', 'n,
Для того чтобы создать эквивалент Cи-строки "Привет, мир \n", делают следующим образом:
.db " Hello, world", '\n', 0
Составные инструкции в строке. AVRASM2 допускает составные инструкции (команды) и директивы в строке, но их использование не рекомендовано. Это нужно для того, чтобы поддерживать распаковку (расширение) многострочных макроопределений препроцессора.
Операнды. Дополнительно к операндам AVRASM AVRASM2 поддерживает выражения с плавающей точкой.
Ассемблер поддерживает ряд операторов, которые перечислены в таблице (чем выше положение в таблице, тем выше приоритет оператора). Выражения могут заключаться в круглые скобки, такие выражения вычисляются перед выражениями за скобками.

 

alt

alt

Функции
В Ассемблере определены следующие функции:
LOW(выражение) – возвращает младший байт выражения;
HIGH(выражение) – возвращает второй байт выражения;
BYTE2(выражение) – то же, что и функция HIGH;
BYTE3(выражение) – возвращает третий байт выражения;
BYTE4(выражение) – возвращает четвёртый байт выражения;
LWRD(выражение) – возвращает биты 0-15 выражения;
HWRD(выражение) – возвращает биты 16-31 выражения;
PAGE(выражение) – возвращает биты 16-21 выражения;
EXP2(выражение) – возвращает 2 в степени (выражение);
LOG2(выражение) – возвращает целую часть log2(выражение).
Следующие функции определены только в AVRASM2:
INT (выражение) – преобразовывает выражение с плавающей точкой в целое (т.е. отбрасывает дробную часть);
FRAC(выражение) – выделяет дробную часть выражения с плавающей точкой (т.е. отбрасывает целую часть);
Q7(выражение) – преобразовывает выражение с плавающей точкой в форму пригодную для инструкций FMUL/ FMULS/FMULSU (знак + 7-битовая дробная часть);
Q15(выражение) – преобразовывает выражение с плавающей точкой в форму пригодную для инструкций FMUL/ FMULS/FMULSU (знак + 15-битовая дробная часть);
ABS( ) – возвращает абсолютную величину постоянного выражения;
DEFINED(символ) – возвращает «истина», если символ прежде определен директивами .equ, .set или .def. Обычно используется вместе с директивами if (.if defined(foo)), но может быть использовано в любом контексте. В отличие от других функций DEFINED(символ) требует наличия круглых скобок вокруг своего аргумента.
Ассемблер AVRASM2 различает регистр символов (AVRASM не различает).
Ну, вот выложил минимум теории необходимой для программирования современных контроллеров. (из учебного пособия по ассемблеру, автор Зубарев Александр Александрович).
Если вглядываться в последние тенденции, то видно, что ассемблер унифицируется и разные производители вынуждены “приходить к общему знаменателю”, а именно аналогии языка Си.
Чтобы быстро писать программы, программист создает свои библиотеки – небольшие микропрограммы в виде сборок - макроопределений, например микропрограммы задержки, или модули инициализации ЖКИ. Удержать в голове множество таких микропрограмм физически невозможно, тем более, что многие программисты даже не помнят все команды, от силы 40-60, а остальные берут из справочника по мере необходимости. Проще один раз написать микропрограмму и использовать в виде макроопределения при создании других программ. Макроопределению можно дать любое произвольное название так, как вам нравиться. Чтобы пользоваться готовыми макроопределениями достаточно нескольких директив. Вспомним их.

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

Синтаксис:
.INCLUDE "имя_файла"
Пример:
; файл iodefs.asm:
.EQU sreg = 0x3f ; Регистр статуса.
.EQU sphigh = 0x3e ; Старший байт указателя стека.
.EQU splow = 0x3d ; Младший байт указателя стека.
; файл incdemo.asm
.INCLUDE iodefs.asm ; Вложить файл.
in r0,sreg ; Прочитать регистр статуса.


.MACRO - начало макроса
С директивы MACRO начинается определение макроса. Макрос (макроопределение) – это микропрограмма, состоящая из последовательности операторов, которые несколько раз встречаются в тексте программы. Эта последовательность операторов включается в тело макроса. Кроме этого, макрос имеет заголовок, состоящий из имени и списка параметров, и окончание. После того как макрос определен, повторяющиеся участки кода в тексте программы заменяются на его имя. Это сокращает текст программы. При встрече имени макроса позднее в тексте программы компилятор заменит его имя на операторы из тела макроса. Таким образом, исполнение макроса заключается в его «расширении».
Макрос в AVRASM может иметь до 10 параметров, к которым в его теле обращаются через @0 – @9. Макрос в AVRASM2 может иметь неограниченное число параметров.
При вызове параметры перечисляются через запятые. Определение макроса заканчивается директивой ENDMACRO.
По умолчанию в листинг включается только вызов макроса, для разворачивания макроса необходимо использовать директиву LISTMAC. Макрос в листинге показывается знаком +.
Синтаксис:
.MACRO имя_макроса
Пример:
.MACRO SUBI16 ; Начало макроопределения.
subi @1,low(@0) ; Вычесть младший байт параметра 0 из параметра 1.
sbci @2,high(@0) ; Вычесть старший байт параметра 0 из параметра 2.
.ENDMACRO ; Конец макроопределения.
.CSEG ; Начало программного сегмента.
SUBI16 0x1234,r16,r17 ; Вычесть 0x1234 из r17:r16.

Пример:
Создадим макрос под именем write

.macro write
ldi @0,@5
ldi @2,@3
ldi @4,@1
.endm

Вызываем макрос и прописываем параметры
;
write r16,0x1,r17,0x2,r18,0x3
;
После выполнения макроса в регистры записываются числа
R16=3
R17=2
R18-1


.ENDM
.ENDMACRO - конец макроса
Директива определяет конец макроопределения и не принимает никаких параметров. Для информации по определению макросов смотрите директиву MACRO.
Синтаксис:
.ENDMACRO
.ENDM
Пример:
.MACRO SUBI16   ; Начало определения макроса.
subi r16,low(@0) ; Вычесть младший байт первого параметра.
sbci r17,high(@0) ; Вычесть старший байт первого параметра.
.ENDMACRO


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

.MACRO MACX ; Определение макроса.
add r0,@0  ; Тело макроса.
eor r1,@1
.ENDMACRO 
; Конец макроопределения.
.LISTMAC   ; Включить разворачивание макросов.
MACX r2,r1 ; Вызов макроса (в листинге будет показано тело макроса).


Рассмотрим практический пример в нашей последней программе (бегущие огни).
Если мы зададим программе задержки макроопределение PAUSE в виде

MACRO PAUSE
dec @0
brne PC-1
dec @1
brne PC-3
dec @2
brne PC-5
.ENDMACRO

То сама программа задержки примет вид

delay:
PAUSE temp1, temp2, temp3
ret

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

Ну вот, вроде как пора и к программированию возвращаться!
Директивы, операторы и функции посмотрели и запомнили.
Теперь нужно инициализировать микроконтроллер. Под инициализацией понимается активация встроенных устройств, установка векторов прерываний, подключение портов, полная очистка оперативной памяти от возможного “мусора”. Конечно - же при корректно составленной программе вроде–бы и никакой очистки не нужно, но почему-то в силу неясных причин, нередко без начальной очистки ОЗУ, контроллер виснет или начинает вести себя непредсказуемо...
Чтобы избежать этого, нам нужно очистить область стека(RAMEND), область данных ОЗУ (SRAM_START-RAMEND), область регистров общего назначения(r0–r31).
Универсальные процедуры очистки (для всех микрконтроллеров AVR) выглядят следующим образом:

Очистка Стековой памяти

 ldi r16,low(RAMEND);
 out SPL,r16;
 .if (RAMEND)>=0x0100;
 ldi r16,high(RAMEND);
 out SPH,r16;
 .endif;
 .ENDM;

Очистка области данных ОЗУ

LDI     ZL,Low(SRAM_START)      ; Адрес начала ОЗУ в индекс
LDI     ZH,High(SRAM_START)
CLR     R16  
                                 ; Очищаем R16
Flush:           
ST      Z+,R16  
                           ; Сохраняем 0 в ячейку памяти
CPI     ZH,High(RAMEND+1)       ; Достигли конца оперативки?
BRNE    Flush                               ; Нет? Крутимся дальше!
 

CPI     ZL,Low(RAMEND+1)          ; А младший байт достиг конца?
BRNE    Flush

CLR     ZL                                      ; Очищаем индекс
CLR     ZH

Очистка регистров общего назначения

LDI     ZL, 30                               ; Адрес самого старшего регистра         
CLR     ZH                                      ; Обнуляем
DEC     ZL                                     ; Уменьшаем адрес на единицу
ST      Z, ZH                               ; Записываем в регистр 0
BRNE    PC-2                                  ; Зацикливаемся до полного обнуления

Все три микропрограммы можно записать как макроопределения, каждый под своим названием и поместить в один отдельный файл. Сам файл можно вызвать с помощью директивы .INCLUDE в начале программы.
В процессе инициализации, можно задать режим полноценного использования регистров r0-r15, так же как r16-r31. Макроопределение будет выглядеть следующим образом:

.MACRO LDIL
PUSH    R17                                    ; Сохраним значение одного из старших регистров в стек.
LDI     R17,@1                ; Загрузим в него наше непосредственное значение
MOV     @0,R17                               ; Перебросим значение в регистр младшей группы.  
POP     R17                                   ; Восстановим из стека значение старшего регистра.
.ENDM

Теперь с помощью одной команды LDIL rX,Y
можно легко записать в регистр rX, любое 1байтное число Y,
где rX может быть любым из r0-r15
(Не забываем, что созданная нами команда LDIL rX,Y в пять раз медленнее настоящей команды LDI и занимает объем в пять строк…)
Таким образом. С помощью макросов (макроопределений) можно разрешить множество неоднозначных ситуаций, связанных с адресацией, управлением устройств ввода вывода, и.т.п. создавая свою библиотеку…

Далее рассмотрим прерывания, работу встроенных таймеров, использование ШИМ.

                                                         (Продолжение следует)


Все права принадлежат ChipMK.ru. При копировании материала ссылка обязательна. 2011-2017 © ChipMK.ru

ChipMk.ru Яндекс.Метрика
PRCY.ru