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

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

 

 

Конкретному устройству соответствует конкретный регистр, как правило 8-битный (1 байтный), состоящий из 8 ячеек памяти.

В любую ячейку можно записать 0 или 1.
Создадим произвольную таблицу, где каждая строка состоит из 8 ячеек и имеет свой порядковый номер, соответствующий одному регистру. Пусть наша таблица состоит из 128 ячеек или из 16 восьмибитных регистров.

 

 

alt

В микроконтроллере есть разные функциональные устройства – это порты, таймеры, АЦП, устройства ШИМ, устройства последовательного приема и передачи данных, и много еще чего. Кроме этого функции конкретного устройства могут меняться, например, сначала принять информацию, а затем переключиться на передачу. Как же они работают? Все проще, чем кажется! Функции определенного устройства жестко привязывается к конкретным ячейкам памяти. Например, если нам нужно на какую-то ножку подать напряжение, мы устанавливаем конкретную ячейку в 1. Пусть, к примеру, за вывод положительного напряжения на 4 ножку отвечает ячейка 9h:3h. Значит, если мы пропишем в ячейку 9h:3h единицу, то на 4- ой ножке получим положительное напряжение. А как мы узнаем, что эта ячейка отвечает за эту функцию? Ячеек много и запомнить номер каждой ячейки очень сложно.
Чтобы было легко работать, производители присвоили каждой строке с определенным порядковым номером, называемым адресом, свое имя, соответствующее устройству. Пусть у нас строка 9h, будет называться регистром PortB, строка 8h регистром PinB, а строка 7h регистром DdrB. Таким образом 7h, 8h, 9h – это адреса регистров с названиями PortB, PinB, DdrB.
Соответствующие регистры указываются в специальном файле с расширением .inc, в самом начале программы. Этот файл становится доступным с помощью директивы .include
Например для attiny2313:
.include "at2313def.inc"
Напомню, что в настоящем контроллере регистр DdrB отвечает за направление ввод-вывод, если в ячейку регистра пропишем 1, то соответствующая ножка будет работать на вывод, подключаясь к регистру PortA , если пропишем 0, то перейдет в режим чтения из регистра PinB. Если в режиме ввода прописать 1 в ячейку регистра PortB, то к соответствующей ножке подключиться подтягивающий резистор.
Таким образом, создается таблица, где указываются все регистры, управляющие внутренними устройствами микроконтроллера, и называются регистрами ввода-вывода оперативной памяти.
Реальная таблица регистров ввода-вывода для attiny2313 выглядит следующим образом:

 

alt

Обратите внимание, что таблица для attiny2313 начинается с адреса 0х20 и заканчивается 0х5F (соответствуют регистрам SFR в PIC-ах). Это значит, что регистры, начиная с адреса 0х60 и до 0хDF (0хDF- последний адрес оперативной памяти для tiny2313) могут использоваться для временного хранения данных, создания промежуточных регистров определяемых программистом (как регистры GRP в PIC-ах). В более современных микроконтроллерах адресное пространство регистров специального назначения может быть больше, и это надо учитывать при создании программ. Для упрощения жизни программиста существует определение SRAM_START прописанное в файле ***.inc, которое определяет начало свободной оперативной памяти.
Напомню, что первые 32 регистра называются регистрами общего назначения (РОН), “полноценные” из них регистры старшей группы от 16 до 32. (каждый регистр r16-r32 соответствует W в PIC-ах)
Младшие РОН, от 0 до 15, не дают записать в себя число напрямую. Только через регистры старшей группы. (Почему? Ответ знают только производители!)
Адресация в микроконтроллерах AVR линейная (в PIC оперативная память разделена на несколько страниц – так называемые банки), начинается с 0x0000 и может заканчиваться 0хFFFF
Общая структура оперативной памяти представлена на рисунке:

 

alt

Теперь посмотрим, как устроен сам микроконтроллер.
Любой контроллер начинается с тактового генератора (oscillator), который может работать как с внутренней RC- времязадающей цепочкой (internal oscillator), так и с внешним кварцевым резонатором, или же может работать от внешних тактовых импульсов. С тактового генератора импульсы через предделитель и таймер(timing and control),(timer/ counter) приходят на счетчик программ – PC (Programm counter), который последовательно начинает обращаться к 16 разрядным инструкциям во флешь - памяти (программе написанную и прошитую программистом), начиная с адреса указанного директивой .org. Инструкция (команда) определяет следующее действие, создавая приращение счетчику команд (если программа без относительных переходов, то после каждой инструкции значение PC увеличивается на единицу, а если есть относительные переходы, то автоматически выполняется расчет приращения).

 

alt

Если возникает событие, связанное с прерыванием, то существующее значение PC записывается в стековую память (Stack pointer), организованную из последних адресных регистров ОЗУ, и которую можно вызвать в виде определения Ramend. По окончании прерывания, значение PC извлекается из стековой памяти, и дальше, с этого адреса продолжает выполнять инструкции. Инструкции в процессе выполнения могут обращаться непосредственно по указанному адресу, или косвенно через сдвоенные регистры общего назначения X, Y,Z. (r27:r26; r29:r28; r31:r30). Кроме этого происходит постоянное обращение к регистру статуса (Status register), где прописываются и считываются флаги. Регистры ввода-вывода (General purpose register)позволяют управлять встроенными устройствами, принимать и выдавать данные. Область памяти данных (Sram) отведена для временного хранения промежуточных результатов, констант, которые необходимы в процессе выполнения программы, но при отключении питания эти данные не сохраняются. Встроенная флешь предназначена для сохранения текущей информации в случаях отключения питания, для хранения кодов доступа, различных настроек и т.п.
Вся эта канитель крутиться вокруг арифметико-логического устройства (ALU), по сути – сердца процессора, где и происходят все логические операции.
На следующем рисунке показана вся память микроконтроллера attiny2313:

 

alt

Ну, вроде как с общей схемой работы микроконтроллера мы разобрались в том понимании, которое нам необходимо для успешного создания рабочей программы. Дальнейший акцент будет смещен в сторону устройств ввода-вывода, т.к. именно их мы включаем и выключаем программно для создания какого либо функционального устройства. Самым сложным для начинающего программиста считается именно детальное изучение регистров ввода-вывода. У каждого свой путь, кто-то читает даташиты (курит даташит) – инструкции от производителя, кто-то разбирает готовые исходники, а некоторые пытаются писать свои коды, доводя “мозг до кипения”. Скажу сразу – нужно делать все вместе – разбирать исходники, заглядывая в даташиты, и дописывать под себя. Если возникает дефицит информации, то прямиком на форум, задавать вопросы. Но, не просите написать вам готовые коды, и не задавайте абстрактных вопросов на отвлеченные темы, потому, что это не поможет!
Итак! С чего начинается любая программа? Если вы ответите – с инициализации, то я соглашусь с вами, но скажу, что есть некоторое но…
Любая программа начинается с инструкций компилятора, а именно с директив. Дело в том, что сами директивы позволяют создавать структурные звенья программы, формировать универсальные блоки, задавать условия. Очень часто бывает так, что начинающий программист выпрашивает исходник у более опытного товарища, и потирая руки открывает текст, и … не видит знакомых ему команд, а только, что то в виде непонятных меток. А где же программа? В сомнениях компилирует программу и… как ни странно, получает нормальный файл прошивки. В чем же дело? А хитрость в том, что вся программа организована в виде готовых библиотек.
А что это за библиотеки? А вы представьте – стеллажи на которых множество книг, у каждой книги свое название и, конечно же разное содержание. Так вот содержание – это и есть исходный код небольшой программы, имеющий свое имя – как название книги, и все они расположены в одном файле – как на стеллаже. Чтобы создать программу нужно всего лишь составить последовательность имен. Самое интересное в том, что имена этим программам присваиваются совершенно произвольно (все зависит от фантазии программиста). Вот и приходиться иногда “гадать” на каком же языке написана программа (а принцип по сути тот же, что на языках высокого уровня).
Запутал окончательно? Тогда все по порядку!
Любая программа-компилятор подчиняется собственным инструкциям, которые называются директивами. Как правило, директивы разных программных компиляторов имеют одинаковые или схожие названия выполняющие похожие функции. В предыдущих статьях функции некоторых директив уже рассматривались и многие уже нам знакомы. И все таки давайте рассмотрим их детально. А если немного подзабыли, то повторим!

Полный список директив контроллеров AVR расположен в виде таблицы:

alt

Если вам приходилось сталкиваться с языком Cи, то наверно “броситься в глаза” сходство с директивами препроцессора этого языка. Тем самым производители решили частично “унифицировать” ассемблер. Хитрость заключается в том, что можно взять готовые библиотеки программ Си и легко адаптировать в ассемблере, и так же создавая программу в Си легко адаптировать ассемблерные библиотеки. Имея такую универсальность, можно без значительных затрат написать свою RTOS (Real-Time Operating System) – операционную систему реального времени. Но об этом несколько позже. Последняя верся ассемблера (версия 2.1.9) стала более функиональной, и состоит из 29 директив. Рассмотим новые директивы, которые не вошли в описания ассемблера AVRASM: http://dfe.karelia.r.../avrasm-rus.htm

Директивы ассемблера AVRASM2 версии 2.1.9
В Ассемблере до версии 2.1.9 директивы AVRASM2 начинаются с #:
#define
#elif
#else
#endif
#error #if
#ifdef
#ifndef
#include
#message #pragma
#undef
#warning
# (пустая директива)

В Ассемблере версии 2.1.9 директивы начинаются с точки, также как и директивы AVRASM.

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

.CSEGSIZE – размер памяти программ
Устройства AT94K имеют раздел памяти, которую пользователь может присоединить к памяти программ AVR или памяти данных. Программа и данные SRAM подразделены на три блока: 10K x 16 память программ, 4K x 8 память данных и 6K x 16 или 12K x 8 перестраиваемой SRAM, которые могут быть распределены между программной памятью (до 4-х разделов по 2K x 16) и памятью данных (до 8-ми разделов по 4Kx8).
Эта директива используется, чтобы определять размер программного блока памяти.
Синтаксис:
.CSEGSIZE = 10 | 12 | 14 | 16
Пример:
.CSEGSIZE = 12 ; Определить размер памяти программ как 12K x 16.

.DD – определяет двойное слово(а) в памяти программ и EEPROM.
.DQ – определяет четверное слово(а) в памяти программ и EEPROM.
Эти директивы подобно директиве .DW определяют нужное количест-во слов 32-битных (двойные слова) и 64-битных (четверные слова) соот-ветственно.
Синтаксис:
МЕТКА: .DD список выражений
МЕТКА: .DQ список выражений
Пример:
.CSEG
varlist: .DD 0, 0xfadebabe, -2147483648, 1 << 30
.ESEG
eevarlst: .DQ 0,0xfadebabedeadbeef, 1 << 62

#define – определить макрос препроцессора
Синтаксис:
1) #define имя [value]
2) #define имя(arg.,...) [value]
Описание:
Определяет макрос препроцессора. Есть две формы макроса: (1) – объект, который в основном определяет константу, и (2) – функция, в которую делают подстановку параметра.
Value – величина (значение) может быть любой строкой, она не определена, пока макрос не будет распакован (расширен). Если величина не определена, она = 1.
Форма (1) макроса может быть определена из командной строки использованием опции -D.
Когда использована форма (2), макрос должен вызываться с тем же количеством аргументов, с которыми он определен. Любые arg. и value будут заменены соответствующими аргументами и значениями, когда макрос расширяется. Отметьте, что левые скобки должны идти сразу после имени (никаких пробелов между ними), в противном случае это будет интерпретировано как часть величины макроса формы (1).
Примеры:
Обратите внимание на размещение первой скобки '(' в примерах, приведенных ниже.
#define EIGHT (1 << 3)
#define SQR(X) ((X)*(X))

.UNDEF – отменить определение символьного имени регистра
Описание:
Отмена определения имени, которое прежде определялось директивой .DEF или #define. Это позволит избежать сообщений об ошибке при многократном использовании регистра. Если имя прежде не определено, директива .undef будет проигнорирована, это в соответствии со стандартом ANSI C. То же можно сделать из командной строки, используя опцию -U.
Синтаксис:
.UNDEF символ
Пример:
.DEF var1 = R16
ldi var1, 0x20
... ; сделает что-то с использованием var1.
.UNDEF var1
.DEF var2 = R16 ; теперь использование R16 не будет вызывать предупреж-дения.

#ifdef или .IFDEF – директива условной компиляции
Синтаксис:
#ifdef имя
Описание:
Сокращение от #if defined. Все следующие строки до соответствующего #endif, #else или #elif условно ассемблируются, если имя определено прежде.
Пример:
#ifdef FOO
……….. // делает что-то.
#endif

#ifndef – директива условной компиляции
Синтаксис:
#ifndef имя
Описание:
Сокращенная запись от #if not defined. Противоположность #ifdef. Все следующее строки до соответствующих #endif, #else или #elif условно ассемблируются, если имя не определено.

#if
#elif – директивы условной компиляции
Синтаксис:
#if условие
#elif
Описание:
Все следующие строки до соответствующего #endif, #else или #elif условно ассемблируются, если условие является истиной (не равно 0). Условие – любое целое выражение, включая макросы препроцессора, которые расширены (распакованы). Препроцессор распознает оператор defined(name), который возвращает 1, если имя определено, и 0 – в противном случае. Любые не определенные символы, использованные в условии по умолчанию, = 0.
Условие может быть вложенным на произвольную глубину.
#elif оценивает условие так же, как #if, за исключением того, что только что оценено, и если никакой предшествующей ветвлению командой #if … #elif данное условие не было оценено как истина.
Примеры:
#if 0
……….. // Здесь код никогда не компилируется.
#endif
#if defined(__ATmega48__) || defined(__ATmega88__)
…………. // код специфичный для этих устройств.
#elif defined (__ATmega169__)
………… // код специфичный для ATmega169.
#endif
Препроцессор AVRASM2 не делает отдельный проход до вызова Ассемблера, он встроенная часть Ассемблера. Это может вызвать некоторую неразбериху, если препроцессор и Ассемблер создают аналогичные разнотипные объекты (например, #if и .if условия). Это также вызывает сбои препроцессора при использовании условий в макросах Ассемблера, которые нужно оценивать, когда макрос распакован, а не когда он определен. Условные выражения не могут распределять начало или конец макроопределения (но могут распределить целое макроопределение, включая начало и окончание).

.ENDIF – директива условного ассемблирования
Завершает условный блок кода после директив .IF, .IFDEF или .IFNDEF. Условные блоки (.IF...ELIF... .ELSE...ENDIF) могут быть вложенными, но все они должны быть выполнены до конца файла (условные блоки не могут работать в нескольких файлах).
Синтаксис:
.ENDIF
.IFDEF |.IFNDEF

.ELIF, .ELSE– директивы условного ассемблирования
.ELIF включит в процесс ассемблирования код, следующий за ELIF, до соответствующего ENDIF или следующего ELIF, если expression явля-ется истиной. В противном случае этот код будет пропущен.
.ELSE включит код до .ENDIF, если условия в директиве .IF и условия во всех .ELIF были ложными.
Синтаксис:
.ELIF
.ELSE
.IFDEF |.IFNDEF
...
.ELSE | .ELIF
...
.ENDIF
Пример:
.IFDEF DEBUG
.MESSAGE "Debugging.."
.ELSE
.MESSAGE "Release.."
.ENDIF

#else – директива условной компиляции
Синтаксис:
#else
Описание:
Все следующие строки до соответствующего #endif условно ассемблируются, если никакая предшествующая ветка в составе последовательности #if... #elif... не оценена как истина.
Пример:
#if defined(__ATmega48__) || defined(__ATmega88__)
…………. // код специфичный для этих МК
#elif defined (__ATmega169__)
………….. // код специфичный для ATmega169
#else
#error "Unsupported part:" __PART_NAME__ // сообщение об ошибке.
#endif

.IF, .IFDEF, .IFNDEF – директивы условного ассемблирования
Условное ассемблирование включает команды из исходного кода в процесс ассемблирования выборочно. Директива IFDEF включит код до соответствующей директивы ELSE, если определен. Символ должен быть определен директивами EQU или SET (не будет работать с директивой DEF). Директива IF, если отлично от 0, включит код до соответствующей директивы ELSE или ENDIF. Возможны до пяти уровней вложенности.
Синтаксис:
.IFDEF
.IFNDEF
.IF
.IFDEF |.IFNDEF
...
.ELSE | .ELIF
...
.ENDIF
Пример:
.MACRO SET_BAT
.IF @0>0x3F
.MESSAGE "Адрес больше, чем 0x3f"
lds @2, @0
sbr @2, (1<<@1)
sts @0, @2
.ELSE
.MESSAGE " Адрес меньше или равен 0x3f"
.ENDIF
.ENDMACRO

.ERROR – вывод строки с сообщением об ошибке.
.WARNING – вывод строки с предупреждением.
.MESSAGE – вывод строки с сообщением.
Синтаксис:
.ERROR “строка”
.WARNING “строка”
.MESSAGE “строка”
Описание:
.ERROR – (ошибка) выдает сообщение об ошибке, останавливает компиляцию и увеличивает счетчик ошибок Ассемблера, тем самым помогает успешному ассемблированию программы. #error определена в стандарте ANSI C.
Пример:
.IFDEF TOBEDONE
.ERROR "Still stuff to be done.."
.ENDIF
.WARNING – (предупреждение) выдает предупреждающее сообщение и увеличивает счетчик предупреждений Ассемблера. В отличие от error не останавливает компиляцию. Директива .warning не определена в стандарте ANSI C, но обычно реализована в препроцессорах, как, например, в препроцессоре GNU C.
Пример:
.IFDEF EXPERIMENTAL_FEATURE
.WARNING "This is not properly tested, use at own risk."
.ENDIF
.MESSAGE – (сообщение) выдает сообщение и не влияет на счетчики ошибок и предупреждений Ассемблера. .message не определено в стандарте ANSI C.
Пример:
.IFDEF DEBUG
.MESSAGE "Debug mode"
.ENDIF
Для всех директив сообщения включают файловое имя и номер строки, подобно нормальным сообщениям об ошибках и предупреждениях.
Макросы препроцессора распаковываются, кроме заключенного внутри двойных кавычек (").
Пример:
.error "Неподдерживаемый МК:" __PART_NAME__

#include или .INCLUDE – включение другого файла
Синтаксис:
1) " file "
2) #include
Описание:
Включение файла. Две формы отличаются тем, что (1) ищет сначала текущий рабочий директорий и функционально эквивалентна директиве .include Ассемблера. (2) ищет в установленном месте – обычно в директории C:\Program Files\Atmel\AVR Tools\AvrAssembler2\Appnotes. Обе формы ищут включаемые файлы в известном месте установленным Ассемблером.
Лучше использовать абсолютные имена пути к файлу в директивах #include, так как поиск файлов затрудняется при перемещении проектов между другими директориями/компьютерами. Используйте опцию -I командной строки, чтобы определять путь, или установите его в AVR Studio - Project - Assembler Options, в окошке Additional include path.
Примеры:
#include ; Ищет в каталоге Appnotes.
#include "mydefs.inc" ; Ищет в рабочем каталоге.
; iodefs.asm:
.EQU sreg = 0x3f ; Status register.
.EQU sphigh = 0x3e ; Stack pointer high.
.EQU splow = 0x3d ; Stack pointer low.
; incdemo.asm
.INCLUDE iodefs.asm ; Include I/O definitions.
in r0,sreg ; Read status register.

.OVERLAP – перекрытие
.NOOVERLAP – неперекрытие
Эти директивы нужны для проектов со специфическими особенностями и не должны использоваться в обычных случаях. Они к настоящему времени влияют только на активный сегмент (cseg/dseg/eseg).
Директивы .overlap/nooverlap выделяют секцию кода/данных, которой будет позволено перекрываться с кодом/данными, определенными где-нибудь еще, без генерации сообщения об ошибке или предупреждения. Это полностью независимо от того, что установлено с использованием директивы перекрытия #pragma. Атрибут допустимого перекрытия останется эффективным по директиве .org, но не последует по директивам .cseg/.eseg/.dseg (каждый сегмент выделяется отдельно).
Синтаксис:
.OVERLAP
.NOOVERLAP
Пример:
.overlap
.org 0 ; Секция #1.
rjmp default
.nooverlap.org 0 ; Секция #2.
rjmp RESET ; Здесь нет ошибки.
.org 0 ; Секция #3.
rjmp RESET ; Ошибка, так как есть перекрытие с секцией #2.
Типичное использование этого – устанавливать некоторую форму кода или данных по умолчанию, которые позже могут модифицироваться перекрытием с другими кодом или данными без необходимости вывода сообщения о перекрытии.

#pragma общего назначения
Синтаксис:
1) #pragma warning range byte option – предупреждение о байтовом диапазоне;
2) #pragma overlap option – перекрытие;
3) #pragma error instruction – ошибки инструкций;
4) #pragma warning instruction – предупреждения по поводу инструкций.
Описание:
1. Ассемблер оценивает постоянные целые выражения как 64 - битные знаковые целые. Когда такие выражения использованы как непосредственные операнды, они должны быть включены в количество битов, требующихся команде. Для большинства операндов выход из диапазона вызовет сообщение ошибки "операнд из диапазона". Тем не менее непосредственные байтовые операнды для команд ldi, cpi, ori, andi, subi, sbci имеют несколько возможных интерпретаций, в зависимости от опции (option):
option = integer: операнд непосредственно оценен как целое, и если его значение за пределами диапазона (-128 ... 255), будет дано предупреждение. Ассемблер не знает, что предполагает пользователь: операнд целым, со знаком или без знака, следовательно, он допускает любое значение со знаком или без знака, которое умещается в байт.
option = overflow (умолчание): операнд оценивается как байт без знака, и любые биты знака будут проигнорированы. Эта опция пригодна при работе с битовыми масками, когда интерпретация целого должна вызывать массу предупреждений, подобно ldi r16, ~ ((1 << 7) | (1 << 3)).
option = none: не выводится никаких предупреждений о диапазоне для байтовых операндов. Не рекомендуется.
2. Если две секции кода, размещенные в памяти директивой .org, перекрываются, передается сообщение об ошибке. Опции модифицируют это поведение следующим образом:
option = ignore: игнорирует условия перекрытия и не выдаются никакие ошибки, никакие предупреждения. Не рекомендуется.
option = warning: при обнаружении перекрытия выдается предупреждение.
option = error: считает перекрытие как ошибку, это рекомендовано устанавливать по умолчанию.
3. Использование инструкций, которые не поддерживаются на выбранном устройстве, вызывает ошибку Ассемблера (поведение по умолчанию).
4. Использование инструкций, которые не поддерживаются на выбранном устройстве, вызывает предупреждение Ассемблера.

#pragma, связанная с маркой МК AVR
Синтаксис:
1) #pragma AVRPART ADMIN PART_NAME string
2) #pragma AVRPART CORE CORE_VERSION version-string
3) #pragma AVRPART CORE INSTRUCTIONS_NOT_SUPPORTED mnemonic[ operand[,operand] ][:...]
4) #pragma AVRPART CORE NEW_INSTRUCTIONS mnemonic [operand[,operand]][:...]
5) #pragma AVRPART MEMORY PROG_FLASH size
6) #pragma AVRPART MEMORY EEPROM size
7) #pragma AVRPART MEMORY INT_SRAM SIZE size
8) #pragma AVRPART MEMORY INT_SRAM START_ADDR address
Описание:
Эти директивы предназначены для указания различных характеристик МК и могут быть использованы во включаемом файле (partdef.inc). Естественно, нет причины использовать эти pragma непосредственно в программах пользователя.
В pragma недопустимы макросы препроцессора. Числовые аргументы в выражениях должны быть целыми числами в десятичном, шестнадцатеричном, восьмеричном или двоичном формате. Строковые аргументы не должны быть заключены в кавычки. В рragma определяются следующие характеристики МК:
1. Имя МК, например, ATmega8.
2. Версия ядра AVR. Это определяет основные поддерживаемые инструкции. Версии ядра к настоящему времени: V0, V0E, V1, V2 и V2E.
3. Разделенный список инструкций (команд), не поддерживаемых этим МК, относительно версии ядра.
4. Разделенный список дополнительных инструкций (команд), поддерживаемых этим МК, относительно основной версии ядра.
5. Размер флэш-памяти программ в байтах.
6. Размер EEPROM-памяти в байтах.
7. Размер SRAM-памяти в байтах.
8. Стартовый адрес SRAM-памяти 0x60 для основных МК AVR, 0x100 или более для МК с расширенным В/В.
Примеры:
Имейте в виду, что комбинация параметров в этих примерах не описывает реальный МК AVR!
1) #pragma AVRPART ADMIN PART_NAME ATmega32
2) #pragma AVRPART CORE CORE_VERSION V2
3) #pragma AVRPART CORE INSTRUCTIONS_NOT_SUPPORTED movw:break:lpm rd,z
4) #pragma AVRPART CORE NEW_INSTRUCTIONS lpm rd,z+
5) #pragma AVRPART MEMORY PROG_FLASH 131072
6) #pragma AVRPART MEMORY EEPROM 4096
7) #pragma AVRPART MEMORY INT_SRAM START_ADDR 0x60
8) #pragma AVRPART MEMORY INT_SRAM SIZE 4096

# (пустая директива)
Синтаксис:
#
Описание:
Неудивительно, что эта директива ничего не делает. Единственная причина, по которой она существует, - это удовлетворить стандарту ANSI C.
3.3. Операторы AVRASM2

(#) Stringification ( выстроить по порядку в строку)
Оператор stringification преобразует в текстовую строку параметр функции, вызывавшей макрос.
Пример:
#define MY_IDENT(X) .db #X, '\n', 0
Если параметр назван подобно этому
MY_IDENT(FooFirmwareRev1),
результатом действия #X будет
.db "FooFirmwareRev1", '\n', 0
Примечания:
1. Stringification может быть использован только с параметрами в макросе функционального типа.
2. Значение параметра используется буквально, то есть это не будет расширено перед stringification.

(##) Concatenation (конкатенация – взаимная связь, сцепление)
Оператор конкатенации объединяет (конкатенирует) два параметра препроцессора, формируя новый параметр. Это возможно, когда, по крайней мере, один из параметров является параметром в макросе функционального типа.
Пример:
#define FOOBAR subi
#define IMMED(X) X##i
#define SUBI(X,Y) X ## Y
Когда макросы IMMED и SUBI вызываются как здесь:
IMMED(ld) r16,1
SUBI(FOO,BAR) r16,1
они могут быть расширены как
ldi r16,0x1
subi r16,0x1
Примечание:
В функциональном типе макроса аргумент используется буквально, т.е., макрос не будет расширен перед конкатенацией.
Параметр, сформированный конкатенацией, подвергнется дальней-шему расширению. В приведенном примере параметры FOO и BAR сначала конкатенировались в FOOBAR, а затем FOOBAR был расширен в subi.

Новые характеристики в AVRASM2 по сравнению с AVRASM:
• препроцессор в Cи-стиле;
• усложнение синтаксиса;
• новые директивы Ассемблера;
• улучшенное вычисление выражений;
• не нужно задавать путь для включаемых файлов;
• улучшение макроопределений.

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

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


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

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