|
Система
команд микроконтроллеров AVR
Перед
тем, как приступить к рассмотрению
системы команд, давайте вспомним некоторые
основные архитектурные особенности
микроконтроллера.
Итак,
микроконтроллер имеет своем составе 32
регистра. Первая их половина (R0-R15) не
может быть использована в операциях с
непосредственным операндом. Во второй
половине есть специфические регистровые
пары, которые могут использоваться в
операциях пересылки данных между
регистрами и памятью и некоторых других
действий (X,Y и Z). Заметим к тому
же, что "возможности" этих регистровых
пар различны!
Кроме
регистров, микроконтроллер может иметь
память данных (ОЗУ), обращение к которой
производится при помощи регистровых пар (индексная
адресация) или указанием 16-ти разрядного
адреса. Микроконтроллер может только
прочесть память данных в регистр или
записать туда из регистра, никакие
арифметические или логические операции с
памятью данных невозможны.
Ну
и последнее - периферия, или регистры ввода-вывода
(I/O). Можно прочитать данные из I/O в
регистр общего назначения и записать из
регистра общего назначения в I/O. Кроме
этого, у части регистров ввода-вывода, а
точнее - у тех, чей адрес не превышает 0x1F,
возможна установка отдельных бит в
состояние 0 или 1.
Операнды
команд будем обозначать следующим (стандартным)
способом:
| Rd |
регистр - приемник,
место, куда сохраняется результат
выполнения команды |
| Rs |
регистр - источник в
двухоперандных командах. Его значение
после выполнения команды не изменяется. |
| I/O |
регистр ввода-вывода,
или периферия. Это порты, таймеры и т.д. |
| K |
8-ми разрядная
константа в операциях со "старшими"
регистрами общего назначения (R16-R31) |
| b |
Номер бита в
операциях с регистрами ввода-вывода |
| A |
16-ти разрядный
адрес при работе с памятью данных |
| q |
6-ти разрядное
смещение при работе с памятью данных |
| X |
Регистровая
пара X. Состоит их регистров XL (R26) и XH
(R27) |
| Y |
Регистровая
пара Y. Состоит их регистров YL (R28) и YH
(R29) |
| Z |
Регистровая
пара Z. Состоит их регистров ZL (R30) и ZH
(R31) |
Итак,
приступим. Для начала рассмотрим команды
передачи данных.
| MOV Rd,Rs |
Эта команда копирует содержимое
регистра Rs в регистр Rd. Содержимое Rs не
изменяется, предыдущее содержимое Rd
теряется. Пример:
mov R3,R19 ; содержимое R19
копируется в R3
Работает со всеми регистрами. Биты
признаков не изменяет. |
| LDI Rd,K |
Загружает в регистр Rd 8-ми разрядную
константу. Работает со старшими
регистрами (R16-R31). Пример:
ldi R16,1 ; загружает в R16
значение 1
Биты признаков не изменяет. Если
необходимо загрузить константу в
младший регистр, то это делается двумя
командами:
ldi R16,1 ; загружает в R16
значение 1
mov R4,R16; и копирует в R4
|
| LD Rd,X |
Загружает в регистр Rd байт из памяти
данных, адрес ячейки памяти в
регистровой паре X. Содержимое
регистровой пары X не изменяется.
Например:
ldi XL,0 ; загружает младший
байт регистровой пары Х
ldi XH,2 ; -//- старший байт регистровой пары
Х
ld R5,X ; байт из ОЗУ с адресом 0x200
загружается в R5
Биты признаков не изменяет.
|
| LD Rd,X+ |
Аналогично предыдущей команде, но
содержимое регистровой пары X после
выполнения пересылки данных
увеличивается на 1. Например:
ldi XL,0 ; загружает младший
байт регистровой пары Х
ldi XH,2 ; -//- старший байт регистровой пары
Х
ld R5,X+ ; байт из ОЗУ с адресом 0x200
загружается в R5
ld R6,X+ ; байт из ОЗУ с адресом 0x201
загружается в R6
Биты признаков не изменяет. |
| LD Rd,-X |
Аналогично предыдущей команде, но
содержимое регистровой пары X перед
выполнением пересылки данных
уменьшается на 1. Например:
ldi XL,0 ; загружает младший
байт регистровой пары Х
ldi XH,2 ; -//- старший байт регистровой пары
Х
ld R5,-X ; байт из ОЗУ с адресом ox1FF
загружается в R5
ld R6,-X ; байт из ОЗУ с адресом 0x1FE
загружается в R6
Биты признаков не изменяет. |
| LD Rd,Y
LD Rd,Y+
LD Rd,-Y
LD Rd,Z
LD Rd,Z+
LD Rd,-Z
|
Эти команды работают абсолютно
идентично трем ранее описанным, за
исключением того, что индексным
регистром является не X, а Y и Z. Наличие
трех пар регистров дает возможность
эффективной работы с блоками памяти,
например:
ldi XL,0x00 ;\первый блок
памяти
ldi XH,0x02 ; регистровая пара X указывает на
адрес 0x200
ldi YL,0x80 ;\второй блок памяти
ldi YH,0x01 ; регистровая
пара Y указывает на адрес 0x180
ldi R16,10 ; счетчик на 10
LOOP:
ld R5,X+ ; в R5 из первого
блока, X указывает на следующий!
st Y+,R5 ; из R5 во второй блок, Y также - на
следующий
dec R16 ; и так - 10 раз!
brne LOOP
В результате выполнения этого цикла 10
байт памяти, начиная с адреса 0x200 будут
скопированы в область памяти с адресом
0x180
|
| LDD Rd,Y+q
LDD Rd,Z+q
|
Регистровые пары Y и Z, кроме
вышеописанных методов обращения к
памяти данных, имеют еще один. В этом
случае в регистр Rd загружается байт из
ячейки памяти, чей адрес вычисляется как
содержимое регистровой пары плюс 6-ти
разрядное смещение. Содержимое
регистровой пары не изменяется!
Например:
ldi YL,0 ; \
ldi YH,2 ;
регистровая пара Y указывает на адрес
0x200
ldd R5,Y+5 ; байт из ОЗУ с адресом
0x205
загружается в R5
ldd R6,Y+10 ; байт из ОЗУ с адресом 0x210
загружается в R6
Такой режим адресации невозможен для
регистровой пары X. Значение смещения q -
от 0 до 63.
|
|
Мы рассмотрели команды LD и LDD,
которые обеспечивают пересылку данных
из памяти данных в регистр общего
назначения. Естественно, что для каждой
команды LD и LDD имеется "обратная" ей
команда - записи в память данных из
регистра. Эти команды имеют мнемоники
соотвественно ST и STD (store). Например:
ldd R5,Y+5 ; байт из ОЗУ с адресом
0x205
загружается в R5
std Y+6,R5 ; байт из R5
записывается в ОЗУ с адресом 0x206
Думаю, что совершенно нет
необходимости расписывать каждую из них
в отдельности... |
| LDS Rd,A
STS A,Rs |
Команда LDS загрузит в регистр Rd
содержимое ячейки памяти данных с
адресом A, где A - шестнадцатиразрядная
константа. В этом случае нет
необходимости предварительно загружать
регистровую пару, но сама команда займет
два слова программной памяти, а не одно,
как предыдущие. Например:
lds R5,0x240 ; байт из ОЗУ с адресом 0x240
загружается в R5
sts 0x060,R5 ; байт R5 в ОЗУ с адресом 0x060
Парой для команды LDS является команда
STS - записывающая содержимое регистра в
память.
|
| LPM |
К командам пересылки данных надо
отнести и очень специфичную команду LPM,
которая пересылает в R0 байт памяти
программ, на который указывает региcтровая
пара Z. Напомню, что память программ и
память данных между собой никак не
пересекаются. Данная команда
используется в основном для чтения
таблиц констант, располагаемых в памяти
программ. Например:
TABLE: db 4,6,8,2,3,5,0
;......
ldi ZL,low(TABLE*2)
ldi ZH,hi(TABLE*2)
LPM ; в R0 будет занесено число 4
Содержимое регистровой пары Z не
изменяется, биты признаков - тоже. Вообще,
ни одна команда пересылки данных не
изменяет признаков.
Важно! Поскольку для команды LPM
адресация побайтная, а память программ
адресуется словами (слово = 2 байта), то
необходимо при загрузке адреса таблицы
адрес умножить на 2!
|
| IN Rd, I/O |
Команда IN прочтет байт из регистра
ввода-вывода в регистр общего
назначения, например:
in R18,PINA ; прочитать
состояние входных линий порта A в R18
in R1,TCCR0 ; прочитать в R1 счетчик таймера 0
Работает со всеми регистрами, биты
признаков не изменяет. |
| OUT I/O, Rs |
А эта - из регистра выведет в порт. |
| PUSH Rs
POP Rd
|
Эти команды предназначены для
работы со стеком. Команда
PUSH поместит Rs в стек, после выполнения
команды указатель стека уменьшается на
единицу. Команда POP извлечет байт из
стека и поместит его в Rd. Соответственно,
указатель стека увеличится на единицу.
Указатель стека должен быть
установлен (как правило - на последний
байт ОЗУ) при старте программы!
|
Теперь
рассмотрим арифметические и логические
команды. Но перед этим освежим в памяти
регистр состояния SREG - поскольку все
команды будут изменять какие-либо биты в SREG.
Регистр
SREG находится в области регистров ввода-вывода,
по адресу 0x3F (0x5F). Чтение и запись
производится командами IN / OUT, кроме того,
есть специальные команды установки и
очистки конкретного бита в SREG. Ну и,
естественно, команды условного перехода (ветвления)
выполняются в зависимости от соcтояния
битов SREG, но о ветвлениях - в следующем
подразделе...
Итак, в SREG имеются следующие биты:
| I |
SREG.7 |
Бит разрешения прерывания. Если он = 0,
то все прерывания в МК запрещены. Если он
=1, то разрешением прерываний будут
управлять соответствующие биты
периферии.
|
| T |
SREG.6 |
Битовый аккумулятор.
С этим битом работают команды BST и BLD
|
| H |
SREG.5 |
Флаг переноса из младшей тетрады
|
| S |
SREG.4 |
Sign -
ислючающее ИЛИ битов N и V
|
| V |
SREG.3 |
oVerflow - переполнение
|
| N |
SREG.2 |
Negative - Результат операции < 0
|
| Z |
SREG.1 |
Zero - Результат операции равен нулю
|
| C |
SREG.0 |
Carry - Флаг переноса
|
| ADD Rd,Rs |
Сложение Rd
и Rs, результат помещается в Rd. Изменяемые
признаки: H V N Z C |
| ADC Rd,Rs |
То же, что
и ADD, но еще прибавляется C-разряд.
Используется при работе с числами
разрядностью более байта:
add R18,R20 ; сложили мл байты -
может быть перенос!
adc R19,R21 ; сложили старшие с учетом этого
переноса
Изменяемые
признаки: H V N Z C |
| ADIW Rdl,q |
Сложение
пары регистров с константой (q - от 0 до 63).
Работает с четырьмя старшими парами
регистров, то есть Z,Y,X и R25:R24 и
используется в основном для операций с
указателями.
Изменяемые
признаки: V N Z C |
| SUB Rd,Rs |
Вычитание
Rs из Rd, результат помещается в Rd.
Изменяемые признаки: H V N Z C |
| SUBI Rd,K |
Вычитание
из Rd константы K. Изменяемые признаки: H
V N Z C. Отметим, что команды сложения
с константой в системе команд почему-то
нет! Что, конечно, очень неудобно. Если
нужно прибавить к регистру, например,
число 10 - следует написать
subi R16, -10
Но тут
надо помнить, что признаки будут
установлены "неправильно"!
Работает со старшими регистрами |
| SBC Rd,Rs |
Вычитание
Rs из Rd с учетом переноса. Результат в Rd.
Изменяемые признаки: H V N Z C |
| SBCI Rd,K |
Вычитание
константы K из Rd с учетом переноса.
Результат в Rd. Работает со старшими
регистрами. Изменяемые признаки: H V N Z C |
| SBIW Rdl,q |
Вычитание
из пары регистров константы. См.
описание ADIW |
| AND Rd,Rs |
Логическое
"И" Rd и Rs, результат помещается в Rd.
Изменяемые признаки: V N Z
Суть логического "И" - в Rd
будут установлены в состояние лог. 1 те
биты, которые были равны 1 и в Rd и в Rs,
остальные сбрасываются в 0 |
| ANDI Rd,K |
То же,
только вместо Rs - константа K.
Работает со старшими регистрами |
| OR Rd,Rs |
Логическое
"ИЛИ" Rd и Rs, результат помещается в Rd.
Изменяемые признаки: V N Z
Суть логического "ИЛИ" - в Rd
будут установлены в состояние лог. 1 те
биты, которые были равны 1 или в Rd, или в Rs,
остальные сбрасываются в 0 |
| ORI Rd,K |
Логическое
"ИЛИ" Rd и константы K.
Работает со старшими регистрами |
| EOR Rd,Rs |
Исключающее
"ИЛИ" Rd и Rs, результат помещается в Rd.
Изменяемые признаки: V N Z
Суть исключающего "ИЛИ" - в Rd
будут установлены в состояние лог. 1 те
биты, которые были не равны в Rd, и в Rs,
Следует заметить, что нет команды "исключающее
ИЛИ" с константой! |
| COM Rd |
Изменит
все биты Rd на противоположные.
Внимание! На самом деле эта команда
выполняется как 0xFF-Rd ! Результат -
то один, но в результате выполнения
команды будет установлен C-разряд!
Изменяемые признаки: V N Z С |
| NEG Rd |
Изменение
знака Rd. Вычисляется как 0x00 - Rd
Изменяемые признаки: H V N Z
С |
| SBR Rd,K |
Совершенно
непонятно, зачем в систему команд
введена эта мнемоника. Set Bit(s) in Register -
это та же операция "логическое ИЛИ".
Наверное, для того, чтобы в даташите
гордо заявить - 118 Powerful Instructions!,
хотя на самом деле добрая пятая часть
дублируется. Короче, см. описание ORI Rd,K |
|
CBR Rd,K |
По сути то же
самое. На самом деле - ANDI Rd,Not(K) |
INC Rd
DEC Rd |
Инкремент
/ декремент Rd. Думаю, тут все ясно...
Изменяемые признаки: N Z V |
| TST Rs |
Установка
признаков по содержимому Rs. На самом
деле вычисляется как AND Rs, Rs.
Изменяемые признаки: N Z V |
| CLR Rd |
Очистка Rd (занесение
в Rd нуля). Выполняется как EOR Rd,Rd ,
поэтому изменяет признаки: N Z
V |
| SER Rd |
Занесение
константы 0xFF в Rd. Именно так и
выполняется - LDI Rd, 0xFF
Соответственно признаков не меняет,
смысла в этой мнемонике также не
наблюдается. |
Уффф... Что-то
длинная страничка получается.
Наверное, остальные
команды опишу в >>>
следующем уроке >>>
|