8-900-374-94-44
[email protected]
Slide Image
Меню

Машинные коды команд avr – AVR програмирование в кодах / AVR / Сообщество EasyElectronics.ru

Таблицы команд ассемблера AVR — (ЭЛЕКТРОНИКА

В этой статье я хочу представить еще один вариант таблиц команд ассемблера для микроконтроллеров AVR.

Из дополнительных материалов у приобретателей курса уже есть pdf документ с набором таблиц команд. Так в чем же основное отличие набора команд, который представлен ниже?

В первую очередь, тем что в колонке «Описание» дается описание команд на английском. И как не трудно заметить, многие мнемоники команд образованы как раз от этих сокращений. Поэтому, тем кто знает английский язык, тем будет проще запомнить написание команд. И так же присутствует колонка «Код операции», где можно посмотреть каким образом та или иная команда выглядит в двоичном виде. Это на тот случай, если вам вдруг захочется по-программировать в машинных кодах.

Сразу стоит отметить, что здесь представлены в основном только команды семейства tiny. Я намерено убрал команды семейства mega, что бы лишний раз не вносить путаницу.

Арифметические и логические команды

Команда Описание Действие Циклы Код операции Флаги
add Rd,Rr Add two Registers Rd←Rd+Rr 1 0000 11rd dddd rrrr Z,C,S,N,V,H
adc Rd,Rr Add with Carry two Registers Rd←Rd+Rr+C 1 0001 11rd dddd rrrr Z,C,S,N,V,H
adiw Rdl,K Add Immediate to Word Rdh:Rdl←Rdh:Rdl+K 2 1001 0110 KKdd KKKK Z,C,S,N,V
sub Rd,Rr Subtract two Registers Rd←Rd-Rr 1 0001 10rd dddd rrrr Z,C,S,N,V,H
sbc Rd,Rr Subtract with Carry two Registers Rd←Rd-Rr-C 1 0000 10rd dddd rrrr Z,C,S,N,V,H
subi Rd,K Subtract Constant from Register Rd←Rd-K 1 1010 KKKK dddd KKKK Z,C,S,N,V,H
sbci Rd,K Subtract with Carry Constant from Register Rd←Rd-K-C 1 0100 KKKK dddd KKKK Z,C,S,N,V,H
sbiw Rdl,K Subtract Immediate from Word Rdh:Rdl←Rdh:Rdl-K 2 1001 0111 KKdd KKKK Z,C,S,N,V
and Rd,Rr Logical AND Registers Rd←Rd AND Rr 1 0010 00rd dddd rrrr Z,S,N
andi Rd,K Logical AND Register and Constant Rd←Rd AND K 1 0111 KKKK dddd KKKK Z,S,N
or Rd,Rr Logical OR Registers Rd←Rd OR Rr 1 0010 10rd dddd rrrr Z,S,N
ori Rd,K Logical OR Register and Constant Rd←Rd OR K 1 0110 KKKK dddd KKKK Z,S,N
eor Rd,Rr Exclusive OR Registers Rd←Rd EOR Rr
1
0010 01rd dddd rrrr Z,S,N
com Rd One’s complement Rd←0xFF-Rd 1 1001 010d dddd 0000 Z,S,N
neg Rd Two’s complement Rd←0x00-Rd 1 1001 010d dddd 0001 Z,C,S,N,V,H
sbr Rd,K Set Bit (s) in Register Rd←Rd OR K 1 0110 KKKK dddd KKKK Z,S,N
cbr Rd,K Clear Bit (s) in Register Rd←Rd AND (0xFF- K) 1 0111 KKKK dddd KKKK Z,S,N
inc Rd Increment Rd←Rd+1 1 1001 010d dddd 0011 Z,S,N,V
dec Rd Decrement Rd←Rd-1 1 1001 010d dddd 1010 Z,S,N,V
tst Rd Test for Zero or Minus Rd←Rd AND Rd 1 0010 00dd dddd dddd Z,S,N
clr Rd
Clear Register Rd←Rd EOR Rd 1 0010 01dd dddd dddd Z,S,N
ser Rd Set Register Rd←0xFF 1 1110 1111 dddd 1111 None

Команды пересылки данных

Команда Описание Действие Циклы Код операции Флаги
mov Rd,Rr Move Between Registers Rd←Rr 1 0010 11rd dddd rrrr None
movw Rd,Rr Copy Register Word Rd+1:Rd←Rr+1:Rr 1 0000 0001 dddd rrrr None
ldi Rd,K Load Immediate Rd←K 1 1110 KKKK dddd KKKK None
ld Rd,X Load Indirect Rd← (X) 2 1001 000d dddd 1100 None
ld Rd,X+ Load Indirect and
Post-Inc.
Rd← (X), X←X+1 2 1001 000d dddd 1101 None
ld Rd, -X Load Indirect and
Pre-Dec.
X←X-1, Rd← (X) 2 1001 000d dddd 1110 None
ld Rd,Y Load Indirect Rd← (Y) 2 1000 000d dddd 1000 None
ld Rd,Y+ Load Indirect and
Post-Inc.
Rd← (Y), Y←Y+1 2 1001 000d dddd 1001 None
ld Rd, -Y Load Indirect and
Pre-Dec.
Y←Y-1, Rd← (Y) 2 1001 000d dddd 1010 None
ldd Rd,Y+q Load Indirect with Displacement Rd← (Y+q) 2 10q0 qq0d dddd 1qqq None
ld Rd,Z Load Indirect Rd← (Z) 2 1000 000d dddd 0000 None
ld Rd,Z+ Load Indirect and
Post-Inc.
Rd← (Z), Z←Z+1 2 1001 000d dddd 0001 None
ld Rd, -Z Load Indirect and
Pre-Dec.
Z←Z-1, Rd← (Z) 2 1001 000d dddd 0010 None
ldd Rd,Z+q Load Indirect with Displacement Rd← (Z+q) 2 10q0 qq0d dddd 0qqq None
lds Rd,k Load Direct from SRAM Rd← (k) 2 1001 000d dddd 0000kkkk kkkk kkkk kkkk None
st X,Rr Store Indirect (X) ←Rr 2 1001 001r rrrr 1100
None
st X+,Rr Store Indirect and
Post-Inc.
(X) ←Rr, X←X+1 2 1001 001r rrrr 1101 None
st -X,Rr Store Indirect and
Pre-Dec.
X←X-1, (X) ←Rr 2 1001 001r rrrr 1110 None
st Y,Rr Store Indirect (Y) ←Rr 2 1000 001r rrrr 1000 None
st Y+,Rr Store Indirect and
Post-Inc.
(Y) ←Rr, Y←Y+1 2 1001 001r rrrr 1001 None
st -Y,Rr Store Indirect and
Pre-Dec.
Y←Y-1, (Y) ←Rr 2 1001 001r rrrr 1010 None
std Y+q,Rr Store Indirect with Displacement (Y+q) ← Rr 2 10q0 qq1r rrrr 1qqq None
st Z,Rr Store Indirect (Z) ←Rr 2 1000 001r rrrr 0000 None
st Z+,Rr Store Indirect and
Post-Inc.
(Z) ←Rr, Z←Z+1 2 1001 001r rrrr 0001 None
st -Z,Rr Store Indirect and
Pre-Dec.
Z←Z-1, (Z) ←Rr 2 1001 001r rrrr 0010 None
std Z+q,Rr Store Indirect with Displacement (Z+q) ← Rr 2 10q0 qq1r rrrr 0qqq None
sts k,Rr Store Direct to SRAM (k) ←Rr 2 1001 001r rrrr 0000kkkk kkkk kkkk kkkk None
lpm Load Program Memory R0← (Z) 3 1001 0101 1100 1000 None
lpm Rd,Z Load Program Memory Rd← (Z) 3 1001 000d dddd 0100
None
lpm Rd,Z+ Load Program Memory
and Post-Inc.
Rd← (Z), Z←Z+1 3 1001 000d dddd 0101 None
spm Store Program Memory (Z) ←R1:R0 1001 0101 1110 1000 None
in Rd,P In Port Rd←P 1 1011 0PPd dddd PPPP None
out P,Rr Out Port P←Rr 1 1011 1PPr rrrr PPPP None
push Rr Push Register in Stack STACK←Rr, SP←SP-1 2 1001 001r rrrr 1111 None
pop Rd Pop Register from Stack SP←SP+1, Rd←STACK 2 1001 000d dddd 1111 None

Команды передачи управления

Команда Описание Действие Циклы Код операции Флаги
rjmp k Relative Jump PC←PC+k+1 2 1100 kkkk kkkk kkkk None
ijmp Indirect Jump to (Z) PC← (Z) 2 1001 0100 0000 1001 None
*jmp k Direct Jump PC←k 3 1001 010k kkkk 110kkkkk kkkk kkkk kkkk None
rcall k Relative Subroutine Call STACK←PC+1,PC←PC+k+1,SP←SP-2 or 3 ¾ 1101 kkkk kkkk kkkk None
icall Indirect Call to (Z) STACK←PC+1, PC← (Z),SP←SP-2 or 3 ¾ 1001 0101 0000 1001 None
*call k Direct Subroutine Call STACK←PC+1, PC←k,SP←SP-2 or 3 4/5 1001 010k kkkk 111kkkkk kkkk kkkk kkkk None
ret Subroutine Return PC←STACK,
SP←SP+2 or 3
4/5 1001 0101 0000 1000 None
reti Interrupt Return PC←STACK,
SP←SP+2 or 3
4/5 1001 0101 0001 1000 I
cpse Rd,Rr Compare, Skip if Equal if (Rd=Rr)
PC←PC+2 or 3
½/3 0001 00rd dddd rrrr None
cp Rd,Rr Compare Rd-Rr 1 0001 01rd dddd rrrr Z,C,S,
N,V,H
cpc Rd,Rr Compare with Carry Rd-Rr-C 1 0000 01rd dddd rrrr Z,C,S,
N,V,H
cpi Rd,K Compare Register with Immediate Rd-Rr-K 1 0011 KKKK dddd KKKK Z,C,S,
N,V,H
sbrc Rr,b Skip if Bit in
Register is Cleared
if (Rr (b)=0)
PC←PC+2 or 3
½/3 1111 110r rrrr obbb None
sbrs Rr,b Skip if Bit in
Register is Set
if (Rr (b)=1)
PC←PC+2 or 3
½/3 1111 111r rrrr obbb None
sbic P,b Skip if Bit in IO
Register is Cleared
if (P (b)=0)
PC←PC+2 or 3
½/3 1001 1001 PPPP Pbbb None
sbis P,b Skip if Bit in IO
Register is Set
if (P (b)=1)
PC←PC+2 or 3
½/3 1001 1011 PPPP Pbbb None
brbc s,k Branch if Status
Flag is Cleared
if (SREG (s)=0)
PC←PC+k+1
½ 1111 01kk kkkk ksss None
brbs s,k Branch if Status
Flag is Set
if (SREG (s)=1)
PC←PC+k+1
½ 1111 00kk kkkk ksss None
brcc k Branch if Carry
Flag is Clearsd
if (C=0) PC←PC+k+1 ½ 1111 01kk kkkk k000 None
brcs k Branch if Carry
Flag is Set
if (C=1) PC←PC+k+1 ½ 1111 00kk kkkk k000 None
brsh k Branch if Same
or Higher
if (C=0) PC←PC+k+1 ½ 1111 01kk kkkk k000 None
brlo k Branch if Lower if (C=1) PC←PC+k+1 ½ 1111 00kk kkkk k000 None
brne k Branch if Not Equal if (Z=0) PC←PC+k+1 ½ 1111 01kk kkkk k001 None
breq k Branch if Equal if (Z=1) PC←PC+k+1 ½ 1111 00kk kkkk k001 None
brpl k Branch if Plus if (N=0) PC←PC+k+1 ½ 1111 01kk kkkk k010 None
brmi k Branch if Minus if (N=1) PC←PC+k+1 ½ 1111 00kk kkkk k010 None
brvc k Bruach if Overflow
Flag is Cleared
if (V=0) PC←PC+k+1 ½ 1111 01kk kkkk k011 None
brvs k Branch if Overflow
Flag is Set
if (V=1) PC←PC+k+1 ½ 1111 00kk kkkk k011 None
brge k Branch if Greate or
Equal, Signed
if (S=0) PC←PC+k+1 ½ 1111 01kk kkkk k100 None
brlt k Branch if Less than
Zero, Signed
if (S=1) PC←PC+k+1 ½ 1111 00kk kkkk k100 None
brhc k Branch if Half Carry
Flag is Cleared
if (H=0) PC←PC+k+1 ½ 1111 01kk kkkk k101 None
brhs k Branch if Half Carry
Flag is Set
if (H=1) PC←PC+k+1 ½ 1111 00kk kkkk k101 None
brtc k Branch if Transfer
Flag is Cleared
if (T=0) PC←PC+k+1 ½ 1111 01kk kkkk k110 None
brts k Branch if Transfer
Flag is Set
if (T=1) PC←PC+k+1 ½ 1111 00kk kkkk k110 None
brid k Branch if Interrupt
Disable
if (T=0) PC←PC+k+1 ½ 1111 01kk kkkk k111 None
brie k Branch if Interrupt
Enable
if (T=1) PC←PC+k+1 ½ 1111 00kk kkkk k111 None

*Обратите внимание! Команды jmp и call не поддерживаются микроконтроллерами семейства tiny, но так как они часто используются при программировании семейства mega, то я решил их так же внести в таблицу, что бы вы не забывали о их существовании.

 

Команды условных переходов по состоянию флагов SREG

Проверкафлага Команда условногоперехода АльтернативнаяФорма написания Условие перехода
C brbc 0,k brcc k Переход если флаг переноса установлен
brsh k Переход если больше или равно
brbs 0,k brcs k Переход если флаг переноса сброшен
brlo k Переход если меньше
Z brbc 1,k breq k Переход если равно
brbs 1,k brne k Переход если не равно
N brbc 2,k brpl k Переход если плюс
brbs 2,k brmi k Переход если минус
V brbc 3,k brvc k Переход если флаг дополнительного кода сброшен
brbs 3,k brvs k Переход если флаг дополнительного кода установлен
S brbc 4,k brge k Переход если больше или равно нулю (знаковое)
brbs 4,k brlt k Переход если меньше нуля (знаковое)
H brbc 5,k brhc k Переход если флаг половинного переноса сброшен
brbs 5,k brhs k Переход если флаг половинного переноса установлен
T brbc 6,k brtc k Переход если флаг хранения бита сброшен
brbs 6,k brts k Переход если флаг хранения бита установлен
I brbc 7,k brid k Переход если прерывания запрещены
brbs 7,k brie k Переход если прерывания разрешены

Команд битовых операций

Команда Описание Действие Циклы Код операции Флаги
sbi P,b Set Bit in I/O Rerister I/O (P,b) ←1 2 1001 1010 PPPP Pbbb None
cbi P,b Clear Bit in I/ORerister I/O (P,b) ←0 2 1001 1000 PPPP Pbbb None
lsl Rd Logical Shift Left Rd (n+1) ←Rd (n), Rd (0) ←0 1 0000 11dd dddd dddd Z,C,N,V
lsr Rd Logical Shift Right Rd (n) ←Rd (n+1), Rd (7) ←0 1 1001 010d dddd 0110 Z,C,N,V
rol Rd Rotate Left through Carry Rd (0) ←C, Rd (n+1) ←Rd (n), C←Rd (7) 1 0001 11dd dddd dddd Z,C,N,V
ror Rd Rotate Right through Carry Rd (7) ←C, Rd (n) ←Rd (n+1), C←Rd (0) 1 1001 010d dddd 0111 Z,C,N,V
asr Rd Arithmetic Shift Right Rd (n) ←Rd (n+1),
n=0…6
1 1001 010d dddd 0101 Z,C,N,V
swap Rd Swap Nibbles Rd (3…0) ←Rd (7…4),Rd (7…4) ←Rd (3…0) 1 1001 010d dddd 0010 None
bst Rr,b Bit Store from
Rerister to T
T←Rr (b) 1 1111 101b bbbb 0bbb T
bld Rd,b Bit Load from T
to Rerister
Rd (b) ←T 1 1111 100b bbbb 0bbb None
bset s Flag Set SREG (s) ←1 1 1001 0100 0sss 1000 SREG (s)
bclr s Flag Clear SREG (s) ←0 1 1001 0100 1sss 1000 SREG (s)
sec Set Carry C←1 1 1001 0100 0000 1000 C
clc Clear Carry C←0 1 1001 0100 1000 1000 C
sez Set Zero Flag Z←1 1 1001 0100 0001 1000 Z
clz Clear Zero Flag Z←0 1 1001 0100 1001 1000 Z
sen Set Negative Flag N←1 1 1001 0100 0010 1000 N
cln Clear Negative Flag N←0 1 1001 0100 1010 1000 N
sev Set Twos Complement Overflow V←1 1 1001 0100 0011 1000 V
clv Clear Twos Complement Overflow V←0 1 1001 0100 1011 1000 V
ses Set Signed Test Flag S←1 1 1001 0100 0100 1000 S
cls Clear Signed Test Flag S←0 1 1001 0100 1100 1000 S
seh Set Half Carry Flag H←1 1 1001 0100 0101 1000 H
clh Clear Half Carry Flag H←0 1 1001 0100 1101 1000 H
set Set Transfer bit T←1 1 1001 0100 0110 1000 T
clt Clear Transfer bit T←0 1 1001 0100 1110 1000 T
sei Global Interrupt Enable I←1 1 1001 0100 0111 1000 I
cli Global Interrupt Disable I←0 1 1001 0100 1111 1000 I

Команды управления процессором

Команда Описание Действие Циклы Код операции Флаги
nop No operation 1 0000 0000 0000 0000 None
sleep Sleep 1 1001 0101 1000 1000 None
wdr Watchdog Reset 1 1001 0101 1010 1000 None

 

 

Раздел: Программирование микроконтроллеров для начинающих

www.mcu4you.ru

Справочник по командам ассемблера AVR

Все команды этой группы выполняют переход (PC ← PC + A + 1) при разных условиях.

Мнемоника Описание Операция Флаги
ADD Rd, Rr Сложение двух регистров Rd ← Rd + Rr Z, C, N, V, H
ADC Rd, Rr Сложение двух регистров с переносом Rd ← Rd + Rr + С Z, C, N, V, H
SUB Rd, Rr Вычитание двух регистров Rd ← Rd - Rr Z, C, N, V, H
SBC Rd, Rr Вычитание двух регистров с заёмом Rd ← Rd - Rr - С Z, C, N, V, H
ADIW Rd, K Сложение регистровой пары с константой R(d+1):Rd ← R(d+1):Rd + K Z, C, N, V, S
SBIW Rd, K Вычитание константы из регистровой пары R(d+1):Rdl ← R(d+1):Rd - K Z, C, N, V, S
SUBI Rd, K Вычитание константы из регистра Rd ← Rd - K Z, C, N, V, H
SBCI Rd, K Вычитание константы из регистра с заёмом Rd ← Rd - K - С Z, C, N, V, H
INC Rd Инкремент регистра Rd ← Rd + 1 Z, N, V
DEC Rd Декремент регистра Rd ← Rd – 1 Z, N, V
MUL Rd, Rr Умножение чисел без знака R1:R0 ← Rd * Rr Z, C
MULS Rd, Rr Умножение чисел со знаком R1:R0 ← Rd * Rr Z, C
MULSU Rd, Rr Умножение числа со знаком с числом без знака R1:R0 ← Rd * Rr Z, C
FMUL Rd, Rr Умножение дробных чисел без знака R1:R0 ← (Rd * Rr) << 1 Z, C
FMULS Rd, Rr Умножение дробных чисел со знаком R1:R0 ← (Rd * Rr) << 1 Z, C
FMULSU Rd, Rr Умножение дробного числа со знаком с числом без знака R1:R0 ← (Rd * Rr) << 1 Z, C
Мнемоника Описание Операция Флаги
CBR Rd, K Очистка разрядов регистра Rd ← Rd and (0FFH – K) Z, N, V
SBR Rd, K Установка разрядов регистра Rd ← Rd or K Z, N, V
CBI P, b Сброс разряда I/O-регистра P.b ← 0
SBI P, b Установка разряда I/O-регистра P.b ← 1
BCLR s Сброс флага SREG SREG.s ← 0 SREG.s
BSET s Установка флага SREG SREG.s ← 1 SREG.s
BLD Rd, b Загрузка разряда регистра из флага T Rd.b ← T
BST Rr, b Запись разряда регистра во флаг T T ← Rd.b T
CLC Сброс флага переноса C ← 0 C
SEC Установка флага переноса C ← 1 C
CLN Сброс флага отрицательного числа N ← 0 N
SEN Установка флага отрицательного числа N ← 1 N
CLZ Сброс флага нуля Z ← 0 Z
SEZ Установка флага нуля Z ← 1 Z
CLI Общий запрет прерываний I ← 0 I
SEI Общее разрешение прерываний I ← 1 I
CLS Сброс флага знака S ← 0 S
SES Установка флага знака S ← 1 S
CLV Сброс флага переполнения дополнительного кода V ← 0 V
SEV Установка флага переполнения дополнительного кода V ← 1 V
CLT Сброс пользовательского флага T T ← 0 T
SET Установка пользовательского флага T T ← 1 T
CLH Сброс флага половинного переноса H ← 0 H
SEH Установка флага половинного переноса H ← 1 H
Мнемоника Описание Операция Флаги
ASR Rd Арифметический сдвиг вправо Rd(i) ← Rd(i+1) (n=0..6), C ← Rd(0) Z, C, N, V
LSL Rd Логический сдвиг влево Rd(i+1) ← Rd(i), Rd(0) ← 0, C ← Rd(7) Z, C, N, V
LSR Rd Логический сдвиг вправо Rd(i) ← Rd(i+1), Rd(7) ← 0, C ← Rd(0) Z, C, N, V
ROL Rd Сдвиг влево через перенос Rd(i+1) ← Rd(i), Rd(0) ← C, C ← Rd(7) Z, C, N, V
ROR Rd Сдвиг вправо через перенос Rd(i) ← Rd(i+1), Rd(7) ← C, C ← Rd(0) Z, C, N, V
SWAP Rd Обмен местами тетрад Rd(3..0) ↔ Rd(7..4)
Мнемоника Описание Операция Флаги
MOV Rd, Rr Пересылка между регистрами Rd ← Rr
MOVW Rd, Rr Пересылка между парами регистров R(d +1):Rd ← R(r+1):Rr
LDI Rd, K Загрузка константы в регистр Rd ← K
LD Rd, X Косвенное чтение Rd ← [X]
LD Rd, X+ Косвенное чтение с пост-инкрементом Rd ← [X], X ← X + 1
LD Rd, -X Косвенное чтение с пред-декрементом X ← X - 1, Rd ← [X]
LD Rd, Y Косвенное чтение Rd ← [Y]
LD Rd, Y+ Косвенное чтение с пост-инкрементом Rd ← [Y], Y ← Y + 1
LD Rd, -Y Косвенное чтение с пред-декрементом Y ← Y - 1, Rd ← [Y]
LDD Rd, Y+q Косвенное чтение со смещением Rd ← [Y+q]
LD Rd, Z Косвенное чтение Rd ← [Z]
LD Rd, Z+ Косвенное чтение с пост-инкрементом Rd ← [Z], Z ← Z + 1
LD Rd, -Z Косвенное чтение с пред-декрементом Z ← Z - 1, Rd ← [Z]
LDD Rd, Z+q Косвенное чтение со смещением Rd ← [Z+q]
LDS Rd, A Непосредственное чтение из ОЗУ Rd ← [A]
ST X, Rr Косвенная запись [X] ← Rr
ST X+, Rr Косвенная запись с пост-инкрементом [X] ← Rr, X ← X + 1
ST -X, Rr Косвенная запись с пред-декрементом X ← X - 1, [X] ← Rr
ST Y, Rr Косвенная запись [Y] ← Rr
ST Y+, Rr Косвенная запись с пост-инкрементом [Y] ← Rr, Y ← Y + 1
ST -Y, Rr Косвенная запись с пред-декрементом Y ← Y - 1, [Y] ← Rr
STD Y+q, Rr Косвенная запись со смещением [Y+q] ← Rr
ST Z, Rr Косвенная запись [Z] ← Rr
ST Z+, Rr Косвенная запись с пост-инкрементом [Z] ← Rr, Z ← Z + 1
ST -Z, Rr Косвенная запись с пред-декрементом Z ← Z - 1, [Z] ← Rr
STD Z+q, Rr Косвенная запись со смещением [Z+q] ← Rr
STS A, Rr Непосредственная запись в ОЗУ [A] ← Rr
LPM Загрузка данных из памяти программы R0 ← {Z}
LPM Rd, Z Загрузка данных из памяти программы в регистр Rd ← {Z}
LPM Rd, Z+ Загрузка данных из памяти программы с пост-инкрементом Z Rd ← {Z}, Z ← Z + 1
SPM Запись в программную память {Z} ← R1:R0
IN Rd, P Пересылка из I/O-регистра в регистр Rd ← P
OUT P, Rr Пересылка из регистра в I/O-регистр P ← Rr
PUSH Rr Сохранение регистра в стеке STACK ← Rr
POP Rd Извлечение регистра из стека Rd ← STACK
Мнемоника Описание Условие Флаги
BRBC s, A Переход если флаг S сброшен Если SREG(S) = 0
BRBS s, A Переход если флаг S установлен Если SREG(S) = 1
BRCS A Переход по переносу Если C = 1
BRCC A Переход если нет переноса Если C = 0
BREQ A Переход если равно Если Z = 1
BRNE A Переход если не равно Если Z = 0
BRSH A Переход если больше или равно Если C = 0
BRLO A Переход если меньше Если C = 1
BRMI A Переход если отрицательное значение Если N = 1
BRPL A Переход если положительное значение Если N = 0
BRGE A Переход если больше или равно (со знаком) Если (N и V) = 0
BRLT A Переход если меньше (со знаком) Если (N или V) = 1
BRHS A Переход по половинному переносу Если H = 1
BRHC A Переход если нет половинного переноса Если H = 0
BRTS A Переход если флаг T установлен Если T = 1
BRTC A Переход если флаг T сброшен Если T = 0
BRVS A Переход по переполнению дополнительного кода Если V = 1
BRVC A Переход если нет переполнения дополнительного кода Если V = 0
BRID A Переход если прерывания запрещены Если I = 0
BRIE A Переход если прерывания разрешены Если I = 1
SBRC Rd, K Пропустить следующую команду если бит в регистре очищен Если Rd[K] = 0
SBRS Rd, K Пропустить следующую команду если бит в регистре установлен Если Rd[K] = 1
SBIC A, b Пропустить еследующую команду если бит в регистре ввода/вывода очищен Если I/O(A, b) = 0
SBIS A, b Пропустить следующую команду если бит в регистре ввода/вывода установлен Если I/O(A, b) = 1

trolsoft.ru

Ликбез по микроконтроллерам AVR. Часть 2. - Информация по МК, FAQ - Микроконтроллеры - Каталог статей

.

Теперь предстоит разобраться – как именно программист может выполнять операции с регистрами AVR при помощи написанной им программы. Для начала немного поговорим об ассемблере, прошу сторонников Си не ругаться, до ЯВУ мы ещё доберёмся.

Как я уже писал в первой части, программа – это заданная программистом последовательность инструкций, каждая из которых предписывает МК выполнить определённое действие. Пример инструкции: загрузить в регистр с именем r16 константу 0x12. Приказ этот для МК в виде 16-битного числа выглядит так: 1110000100000010. Именно это число, которое называется КОД ОПЕРАЦИИ, и будет занесено в 16-битную ячейку памяти программ по соответствующему адресу. Как именно распределяется программа по ячейкам памяти программ – разберём немного позже. Последовательность инструкций в виде 16-битных чисел представляет собой программу для AVR в машинных кодах. Однако, процесс написания программы в машинных кодах очень неудобен для человека. Поэтому в помощь программисту существует АССЕМБЛЕР – переводчик удобных для восприятия человеком команд в машинные коды для МК. Инструкция «загрузить в регистр с именем r16 константу 0x12» на ассемблере выглядит так:
ldi r16,0x12

Сокращение «ldi» образовано от английских слов «load data immediate» - «загрузка данных непосредственная». МНЕМОНИКА команды – запись её в виде ldi Rd, K – достаточно легко запоминается человеком. СИСТЕМА КОМАНД микроконтроллера – это совокупность всех команд, которые могут быть применены к данному МК. Число входящих в систему команд различно для разных семейств МК. Мнемоники также различаются. Поэтому ассемблер для одного семейства МК существенно отличается от предназначенного для другого семейства.
Для ознакомления с системой команд AVR откройте главу 3 книги А.В. Евстифеева «Микроконтроллеры AVR семейства Mega. Руководство пользователя».

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

start: ldi r16,0x02     ; Загрузить константу 0х02 в регистр общего назначения r16
        out DDRB,r16   ; Записать в регистр DDRB данные из регистра r16
                               ; Теперь вывод PB1 оказался настроен на выход
        ldi r16,0x1D     ; Аналогичные действия с регистрами. Выключить
       out PORTB,r16   ; светодиод, который подключен к между PB1 и «общим»
       rjmp start          ; Перейти на метку start
    
Как видите, ничего сложного. Команды ассемблера не должны начинаться с самого начала строки, следует делать отступ. С самой первой строки пишутся МЕТКИ. Метки – это придуманные программистом для своего удобства слова. Ими помечаются те адреса в памяти программ, на которые возможны переходы. Встретив команду перехода на какую-либо метку, ассемблер подставит в код операции соответствующий этой метке адрес. Никто не запрещает программисту указывать адрес непосредственно в виде числа. Просто применение меток делает программу более наглядной и позволяет не следить за возможными изменениями адресов. Подобно тому, как Пупкин может сначала поселиться в гостиничном номере 105, а затем его переселят в номер 209. Но если просто сказать «Пойдём в номер Пупкина», мы разберёмся, по какому адресу идти в данный момент. После имени метки в ассемблере AVR следует ставить двоеточие. Недопустимо ставить в программе 2 метки с одинаковым именем.

После точки с запятой пишутся КОММЕНТАРИИ. Это пояснения, которые программист пишет для себя и тех, кто будет смотреть программу. Микроконтроллеру они не нужны, поэтому ассемблер их просто игнорирует.

Адреса ячеек памяти программ в AVR начинаются с нуля ($0000). Адрес последней ячейки и их общее количество зависят от модели МК. Например, у ATmega16 объём памяти программ составляет 8192 ячейки. Ячейки 16-битные, поэтому память программ занимает 16 килобайт. Память может измеряться и в словах. 1 слово занимает 16 бит или 2 байта. Таким образом, объём памяти ATmega16 составляет 8K слов. Адреса ячеек – от $0000 до $1FFF. Большинство инструкций занимают по 1 ячейке, некоторым необходимо 2. Максимальный размер программы для конкретного МК как раз и ограничивается объёмом его памяти программ.


Откуда МК узнаёт – какую именно команду ему предстоит выполнить сейчас? Адрес ячейки памяти программ со следующей исполняемой командой находится в специальном регистре, который называется ПРОГРАММНЫЙ СЧЁТЧИК или PC. Другое его название – СЧЁТЧИК КОМАНД. В микроконтроллерах AVR, в отличие от PIC, для программиста PC напрямую недоступен. При нормальной работе МК число в регистре PC после выполнения каждой команды автоматически увеличивается на 1 (или на 2, если команда занимает 2 ячейки). При переходах и ещё в некоторых случаях (прерывания, вызов подпрограмм и возврат из них) этот порядок нарушается, и в PC загружается тот адрес, на который выполняется переход. Таким образом, порядок выполнения инструкций, находящихся в памяти программ, соответствует последовательности значений PC.

Скорость работы МК определяется тактовой частотой. 1 машинный цикл AVR выполняется за время 1 периода тактового генератора. Таким образом, при частоте тактового генератора 1 МГц за 1 секунду произойдет 1 миллион тактов. Большая часть команд выполняется микроконтроллерами AVR за 1 машинный цикл. Это стало возможным благодаря конвейерной обработке команд. При отработке команд перехода и ещё некоторых нормальная работа конвейера нарушается, и возникают задержки от 1 до 4 тактов. Подробнее о работе конвейера и причинах возникновения задержек почитайте в книге А.В. Евстифеева «Микроконтроллеры AVR семейства Mega. Руководство пользователя», глава 2, раздел 2.3.

Источники тактового сигнала могут быть различными, по выбору программиста. Самые распространённые варианты – это внутренний RC-генератор (не требует подключения внешних деталей), генератор с внешней RC-цепочкой, или встроенный кварцевый генератор с подключаемым внешним резонатором. Возможно также использование тактового сигнала от внешнего источника. Нижняя граница тактовой частоты архитектурой самого МК не ограничивается, она может быть сколь угодно малой – хоть 1 такт в год от внешнего источника. Верхняя граница зависит от модели МК и нередко составляет 8 или 16 МГц. Подробности, как обычно, можете узнать из даташита на конкретный МК.

Адрес $0000 – это ВЕКТОР СБРОСА. Именно с размещённой по этому адресу команды начинается выполнение программы после включения питания или сброса МК. Значение адреса вектора сброса в некоторых МК может быть изменено, но этот случай нас пока не интересует. Сброс может быть вызван внутренними или внешними причинами. О внутренних разговор будет позже. Одной из причин сброса является падение напряжения питания Vcc ниже определённой величины. Для внешнего сброса предназначен вывод _RESET. Сброс происходит при удержании низкого уровня (не более 0,1Vcc) на этом выводе не менее 1…3 мкс. При работе МК на выводе _RESET должно поддерживаться напряжение (0,9…1,0)Vcc. Во многих AVR имеется внутренний подтягивающий резистор, соединяющий _RESET c Vcc. В этом случае _RESET допустимо никуда не подключать, но для большей надёжности можно установить и дополнительный внешний резистор. Подробности о сбросе можете прочитать в книге А.В. Евстифеева «Микроконтроллеры AVR семейства Mega. Руководство пользователя», глава 4, раздел 4.4.

При сбросе во все регистры ввода/вывода (РВВ) заносятся начальные значения, заданные фирмой-производителем, а в PC загружается адрес вектора сброса. Выполнение программы после сброса начинается не мгновенно, а после некоторой задержки, для надёжности. По адресу $0000 программист обычно размещает команду безусловного перехода к инициализационной части программы, начало которой он обозначает меткой, например, "start”. Это делается для того, чтобы обойти размещённую в начале памяти программ таблицу векторов прерываний.

.org 0
reset: jmp start
……
…… (здесь переходы на обработку прерываний)
……
start: ldi r16,0x12
…… (отсюда продолжается программа)

В этом примере reset и start – метки. Директивой org программист указывает ассемблеру, по какому адресу следует поместить следующую команду в памяти программ. Таким образом, команда jmp start будет размещена по адресу $0000. Перед директивами в ассемблере AVR следует ставить точку. Какую команду следует применить здесь для перехода – двухбайтовую jmp или однобайтовую rjmp – зависит от конкретной модели AVR, смотрите в даташите. По какому адресу будет находиться первая команда инициализационной части (в примере это ldi) – нам в данном случае неважно, пусть ассемблер её сам расположит, а нам достаточно знать метку.

После сброса МК в PC загрузится вектор сброса $0000 и будет выполнена находящаяся по этому адресу команда безусловного перехода к метке start. Следовательно, в PC загрузится соответствующий метке start адрес, и выполнение программы продолжится с команды ldi r16,0x12

Инициализационная часть программы (далее я буду называть её просто инициализацией МК) предназначена для программной настройки микроконтроллера после сброса под нужды программиста. Здесь выполняется настройка выводов портов на вход/выход, включение и настройка периферийных модулей, занесение требуемых начальных значений в регистры. После инициализации МК выполняет возложенные на него программистом задачи.

Выводы по 2 части:


1. Для перевода удобных человеку команд в машинные коды предназначен ассемблер.
2. Набор возможных действий программиста с микроконтроллером определяется системой команд этого МК.
3. Каждая команда имеет определённую мнемонику для лучшего запоминания.
4. При написании программы на ассемблере применяются метки, комментарии и директивы.
5. Максимальный размер программы ограничивается объёмом памяти программ выбранного МК.
6. Порядок выполнения находящихся в памяти программ команд соответствует последовательности значений программного счётчика PC.
7. Скорость работы МК определяется тактовой частотой. 1 такт работы AVR выполняется за 1 период тактовой частоты.
8. Тактирование AVR возможно от внутреннего RC-генератора, подключение внешних деталей при этом не требуется.
9. Выполнение программы после включения питания или сброса МК начинается с адреса вектора сброса (для AVR обычно $0000).
10. Сброс может быть вызван падением напряжения питания ниже определенной величины, воздействием на вывод _RESET, а также некоторыми другими причинами.
11. Программа, как правило, начинается с команды безусловного перехода к инициализационной части.
12. Инициализация предназначена для программной настройки МК после сброса под нужды программиста.

© picmaniac

cxema21.ru

AVR Пишем код на СИ. Зажигаем светодиод

&nbsp

&nbsp

&nbsp

Урок 3

 

 

Сегодня мы научимся писать код на C в среде Atmel Studio, для примера мы возьмём тот же проект, который мы создали на прошлом занятии.

Прежде чем мы начнём непосредственно заниматься написанием кода, мы изучим те строки кода, которые нам уже сгенерировала студия в нашем файле Test01.c.

В самом начале кода мы видим строку в виде следующей директивы

#include <avr/io.h>

Посмотрим определение данной директивы

Директива #include просит препроцессор (компилятор) включить файл, объявленный после нее в исходный код. Имя файла может заключаться либо в треугольные скобки <> либо в кавычки ””. Треугольные скобки используются в случае включения в код файла из самой среды разработки, а кавычки – пользовательского файла.

#include <имя файла>

В нашем случае в текст кода включается файл io.h. Если мы откроем данный файл, то мы увидим, что в зависимости от каких-то условий в наш код включаются ещё определённые заголовочные файлы. В нашем частном случае условием является использование нами определённого микроконтроллера. Так как мы используем Atmega8a, то соответственно включится следующий файл:

#elif defined (__AVR_ATmega8A__)
# include <avr/iom8a.h>

В данном файле находятся макросы для векторов прерываний, для определённых шин. Что такое макросы и как их использовать, мы разберём немного позднее. Движемся дальше по файлу io.h и видим, что в него также включены ещё 3 файла, но нам будет интересен следующий файл:

#include <avr/portpins.h>

В данном файле находятся также макроподстановки для наших лапок портов и прочей периферии, чтобы нам было удобнее писать и читать наш код. Откроем данный файл и изучим в нём данные строки

/* Port Data Register (generic) */
#define PORT7  7
#define PORT6  6
#define PORT5  5
#define PORT4  4
#define PORT3  3
#define PORT2  2
#define PORT1  1
#define PORT0  0

Данные строки нам говорят о том, что, например, если при компиляции проекта препроцессор (интерпретатор команд) встретит в коде слово PORT4, то он его сразу заменит на цифру 4.

Тем самым мы постепенно с вами подошли к изучению ещё одной директивы

Директива #define

Просит препроцессор (компилятор) в случае появления в тексте кода буквосочетания 1 заменить его на буквосочетание 2.

Данная директива используется для удобства чтения кода.

#define <буквосочетание 1> <буквосочетание 2>

Вернёмся в наш код. Далее мы видим следующее

int main(void)
{

}

То, что мы с вами наблюдаем в языке C и C++ называется функция. Функциями мы будем пользоваться постоянно. Функция — это такая подпрограмма, которая вызывается из какого-нибудь участка кода. Самое важное у функции — это её имя (в нашем случае main). По имени мы будем вызывать функцию из другого участка кода. Также у функции существуют входные аргументы, возвращаемые аргументы, а также тело. Входные аргументы находятся сразу после имени в скобках и перечисляются один за другим, а разделяются запятыми. В нашем случае стоит один тип "void", обозначающий, что у нашей функции вообще нет входных аргументов. Поэтому если мы подобную функцию будем вызывать в другом участке кода, то мы в скобках вообще ничего не ставим. Возвращаемый аргумент у функции один. Если нам потребуется больше чем один тип переменных, то мы будем пользоваться глобальными переменными, о которых мы узнаем позже. Изучение переменных вообще не входит в рамки наших уроков, как правило это объясняется непосредственно в уроках и литературе по языкам программирования. Тип возвращаемого аргумента указывается перед именем функции. В нашем случае — это int (целочисленная знаковая переменная). Также у функции существует тело — это участок кода, находящийся между открывающей и закрывающей фигурными скобками. Вот этот участок кода и будет выполняться в случае вызова функции.

Функцию main мы явно нигде не вызываем. Это главная функция нашего приложения, недаром она и называется main, что по английски значит главный. Встретив данное имя, компилятор и начинает выполнение программы с данного места. То есть это своего рода входная точка нашей программы. Отсюда всё и начинается. Сюда мы и начинаем писать свой код.

Давайте же что-нибудь сюда и напишем. Мы пока не будем обращать внимание на строки, уже содержащиеся в теле данной функции.

У программистов, которые пишут программы под ПК, начинать занятия принято с вывода строки "Hello World!", а у тех программистов, которые пишут под мелкие чипы, принято начинать работу с подключения и управления свечением светодиодами. Затем они учат их мигать просто, мигать по очереди, а уже после этого приступать к программированию каких-то более серьёзных вещей. Мы также не будем отступать от данного правила.

Давайте сначала подключим светодиод к какой-нибудь ножке контроллера, например к ножке 0 порта D

 

У порта D, как мы видим из данной распиновки, существует как раз 8 ножек, что соответствует байту (8 бит). Также как биты в байты, ножки портов отсчитываются от 0.

Напишем мы сначала следующую строку

int main(void)
{

DDRD = 0xFF;

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

DDRD — это команда, которая устанавливает состояние лапок порта D. Состояние лапки порта — это то, в каком направлении данная лапка будет работать — на выход или на вход, что соответствует установке определённого бита в 0 или в 1. Но так как мы будем зажигать светодиод, мы должны на определённой ножке порта выставить высокий логический уровень (в нашем случае 5 вольт). А чтобы управлять уровнями ножки, она должна быть определена, как работающая на выход или на вывод. То есть состоянием лапки мы будем управлять из контроллера, а не из внешнего источника уровня. Так как у нас лапка нулевая, то и бит мы и должны выставить в ноль нулевой бит нашего байта, соответствующего нашему порту D. Так как мы не пользуемся сегодня остальными лапками порта, то нам их состояние будет не важно и мы выставляем все лапки портов на вывод. Поэтому мы присваиваем переменной DDRD значение 0xFF. Данное значение мы написали в шестнадцатиричном виде. Этот вид очень удобен для программистов, так как визуально о многом говорит. FF — это в десятичной системе 255, а в двоичной — 11111111, что говорит о том, что все биты в данном числе выставлены в единицу. Также мы видим, что наша строка заканчивается точкой с запятой (;). Данный оператор — это разделитель команд, так как в одной строке мы можем писать не обязательно одну только команду, а можем и несколько, если они небольшие. Также в данной строке мы видим оператор "=" (знак равенства). Данный оператор заставляет наш препроцессор присвоить значение, находящееся справа возле него переменной, находящейся слева.

Ну, вообщем, переключили мы весь наш порт в состояние вывода данных. Теперь осталось включить на лапке PD0 высокий логический уровень. Сделать это мы можем следующей командой:

DDRD = 0xFF;

PORTD = 0b00000001;

 

 

Данная команда или переменная PORTD управляет записью или считыванием значений в порт или из порта в зависимости от состояния. То есть данной командой мы включили нулевую лапку в высокое логическое состояние (в единицу). Здесь мы с вами уже попробуем использовать написание значения в двоичном виде. Чтобы писать значения в данном виде, мы используем префикс 0b. Данный вид удобен тем, что мы здесь видим полностью, как выглядит наш байт побитно. Лапки портов в байте, также как и биты считаются справа налево. То есть данной командой мы выставили в высокое состояние нулевую лапку порта D, а остальные мы выставили в низкое. Вообщем, арифметическо-логическое устройство микроконтроллера сначала включит все ножки порта на выход, а затем установит на нулевой ножке высокое логическое состояние, и после этого у нас должен будет зажечься светодиод, так как через токоограничивающий резистор мы его анодом подключим к данной ножке, а катодом к общему проводу. Тем самым на контактах светодиода появится разность потенциалов, которая заставит его светиться. Кроме написанных нами двух строк далее в коде присутствует команда while. Данная команда является командой условного цикла.

PORTD = 0b00000001;
while(1)
{

}

В скобочках указывается условие, которое должно либо выполняться либо не выполняться. Также как у функции есть тело, то у условия также есть тело, также заключенное в фигурные скобки. И код, находящийся в теле цикла, будет выполняться бесконечно, пока условие, находящееся в скобках будет выполняться, то есть будет истинным. Как только условие перестанет выполняться, а проверяется это тогда, когда код выполнится до конца (до закрывающей фигурной скобки), то мы выходим из цикла и код продолжает выполняться уже дальше тот, который находится уже не в теле цикла, а после закрывающей фигурной скобки. А истина в информатике — это TRUE или 1. Поэтому в данном случае цикл будет бесконечным, так как там стоит единице, а единица всегда равна единице. Бесконечный цикл организован для того, чтобы код, написанный для контроллера, выполнялся постоянно, то есть чтобы наш контроллер постоянно работал и не останавливался. В нашем случае тело пустое, и наш контроллер, вернее его АЛУ, будет всё время висеть в данном цикле и ничего не делать до тех пор, пока мы не отключим питание, либо нам его не отключат в розетке, либо, не дай Бог, сгорит контроллер. То есть светодиод наш будет светиться постоянно.

Сегодня мы не будем пробовать нашу программу прошивать в микроконтроллер, и даже не будем пробовать ещё в виртуальном контроллере, то есть в программе симуляции, а попробуем симуляцию запустить в самой студии, так как на прошлом занятии мы в качестве отладчика и выбрали симулятор. Двойным щелчком мыши либо клавишей F9 мы установим точку останова на команде PORTD = 0b00000001; и, когда мы запустим отладку, то отладчик, как только увидит данную точку, должен будет в этом месте остановить выполнение программы, и мы сможем посмотреть, какие уровни и где у нас установились.

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

Здесь мы наблюдаем, что ещё у нас открылась карта нашей памяти, в которой нам пока ещё ничего не понятно. Если бы мы писали на ассемблере либо на машинном коде, то нам бы это было понятнее. Поэтому нас интересует другая. Карта. Для этого мы нажмём вот эту кнопочку

Данная кнопочка (I/O Wiev) откроет нам окно с данными наших портов ввода-вывода и прочей периферии

 

Нажмем в данном окне на строку PORTD и увидим в нижней половине окна, что весь наш регистр DDRD, отвечающий за направление отдельных ножек порта выставился весь в единички, то есть на выход

А дальше уже проблема. Чтобы нам посмотреть, как сработает следующая команда, которая включит нам нулевую ножку, отладчику необходимо остановиться на следующей строке кода, а у нас её нет, у нас только бесконечный цикл, который для отладчика — не строка. Поэтому мы пока остановим отладчик следующей кнопкой

И мы напишем какую-нибудь ещё строку, например, мы захотим, чтобы данный светодиод у нас погас, а зажегся следующий, который присоединен к следующей лапке, чтобы создать эффект бегущего огня

PORTD = 0b00000001;

PORTD = 0b00000010;

Конечно всё это на практике у нас не сработает, так как мы не успеем заметить свечение предыдущего светодиода. Чтобы задумка заработала практически, мы должны ещё с вами включить между данными командами задержку, а это тема уже других более поздних занятий. Но тем не менее мы данную команду включим, чтобы отладчику было где остановиться. Затем мы запустим заново отладку. Точка останова у нас также находится пока на той строке, на какой и была до этого. Запустим опять отладчик. Собирать проект перед отладкой необязательно, так как отладчик сам его пересоберет. Дожидаемся остановке отладчика на точке. В окошке с вводом-выводом опять нажмём на строке с нашим портом. Дальше начинаем шагать по программе. Для этого нажимаем следующую кнопку или функциональную клавишу F10, о чем нам подсказывает студия, как только мы подносим указатель мыши к данной кнопке

Теперь отладчик остановится на следующей строке

И теперь в окне ввода-вывода мы видим уже следующую картину

Мы видим, что самый левый бит, соответствующий нулевой ножке порта переключился в высокое логическое состояние, причём мы это видим не только в регистре PORTD, но и в регистре PIND, который отвечает за считывание состояния ножек порта D при его работе на ввод. Вот таким вот образом мы и отлаживаем наши программы.

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

После этого текст кода у нас должен будет остаться вот таким

 

Предыдущий урок Программирование МК AVR Следующий урок

 

Исходный код

 

 

Купить программатор можно здесь (продавец надёжный) USBASP USBISP 3.3

 

Смотреть ВИДЕОУРОК

 

 

Post Views: 14 264

narodstream.ru

Осваиваем AVR микроконтроллеры - система команд

Система команд микроконтроллеров 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
Соответственно признаков не меняет, смысла в этой мнемонике также не наблюдается.

 Уффф... Что-то длинная страничка получается. 

Наверное, остальные команды опишу в >>> следующем уроке  >>>

 

nikolaew.org

Питание, система команд и архитектура МК AVR (Лекция) | ЛЕКЦИИ ПО МК

В начало

 

ПЛАН ЛЕКЦИИ

1. Режимы пониженного энергопотребления

2. Система команд AVR

3. Архитектура микроконтроллеров AVR

 

1. Режимы пониженного энергопотребления

AVR  микроконтроллеры могут быть переведены программным путем в один из шести режимов пониженного энергопотребления.

  • Режим холостого хода (IDLE), в котором прекращает работу только процессор и фиксируется содержимое памяти данных, а внутренний генератор синхросигналов, таймеры, система прерываний и WATCHDOG-таймер продолжают функционировать.
  • Режим микропотребления (Power Down), в котором сохраняется содержимое регистрового файла, но останавливается внутренний генератор синхросигналов. Выход из Power Down возможен либо по общему сбросу микроконтроллера, либо по сигналу (уровень) от внешнего источника прерывания. При включенном WATCHDOG-таймере ток потребления в этом режиме составляет около 60...80 мкА, а при выключенном - менее 1 мкА для всех типов AVR. Вышеприведенные значения справедливы для величины питающего напряжения 5 В.
  • Режим сохранения энергии (Power Save), который реализован только у тех AVR, которые имеют в своем составе систему реального времени. В основном, режим Power Save идентичен Power Down, но здесь допускается независимая работа дополнительного таймера/счетчика RTC. Выход из режима Power Save возможен по прерыванию, вызванному или переполнением таймера/счетчика RTC, или срабатыванием блока сравнения этого счетчика. Ток потребления в этом режиме составляет 6...10 мкА при напряжении питания 5 В на частоте 32,768 кГц.
  • Режим подавления шума при работе аналого-цифрового преобразователя (ADC Noise Reduction). Как уже отмечалось, в этом режиме останавливается процессорное ядро, но разрешена работа АЦП, двухпроводного интерфейса I2C и сторожевого таймера.
  • Основной режим ожидания (Standby). Идентичен режиму Power Down, но здесь работа тактового генератора не прекращается. Это гарантирует быстрый выход микроконтроллера из режима ожидания всего за 6 тактов генератора.
  • Дополнительный режим ожидания (Extended Standby). Идентичен режиму Power Save, но здесь работа тактового генератора тоже не прекращается. Это гарантирует быстрый выход микроконтроллера из режима ожидания всего за 6 тактов генератора.

Микроконтроллеры AVR mega64, mega103 и mega128 имеют еще одну примечательную архитектурную особенность, позволяющую значительно снизить энергопотребление всего кристалла в целом, когда в процессе работы возникают вынужденные паузы ожидания. В этом случае целесообразно уменьшить ток потребления центрального процессора и периферийных устройств как в активном режиме, так и в режиме холостого хода, понизив основную тактовую частоту микроконтроллера. Для этой цели на кристалле размещен специальный предделитель, позволяющий делить основную тактовую частоту на целое число в диапазоне от 2 до 129. Включение/выключение данной функции осуществляется одной короткой командой в программе.

AVR функционируют в широком диапазоне питающих напряжений от 1,8 до 6,0 Вольт. Температурные диапазоны работы микроконтроллеров AVR - коммерческий (0С...70С) и индустриальный (-40С...+85С). К сожалению, корпорация Atmel не выпускает и не планирует выпускать AVR для работы в автомобильном (-40С...+125С) и военном (-55С...+125С) температурных диапазонах.


Рис. 2.  Структурная схема AVR

 

            С точки зрения программиста AVR представляет собой 8-разрядный RISC микроконтроллер, имеющий быстрый Гарвардский процессор, память программ, память данных, порты ввода/вывода и различные интерфейсные схемы. Структурная схема микроконтроллера приведена на рис. 2. Гарвардская архитектура AVR реализует полное логическое и физическое разделение не только адресных пространств, но и информационных шин для обращения к памяти программ и к памяти данных, причем способы адресации и доступа к этим массивам памяти также различны. Подобное построение уже ближе к структуре цифровых сигнальных процессоров и обеспечивает существенное повышение производительности. Центральный процессор работает одновременно как с памятью программ, так и с памятью данных; разрядность шины памяти программ расширена до 16 бит.    Следующим шагом на пути увеличения быстродействия AVR является использование технологии конвейеризации, вследствие чего цикл "выборка - исполнение" команды заметно сокращен. Например, у микроконтроллеров семейства MCS51 короткая команда выполняется за 12 тактов генератора (1 машинный цикл), в течение которого процессор последовательно считывает код операции и исполняет ее. В PIC-контроллерах фирмы Microchip, где уже реализован конвейер, короткая команда выполняется в течение 8 периодов тактовой частоты (2 машинных цикла). За это время последовательно дешифрируется и считывается код операции, исполняется команда, фиксируется результат и одновременно считывается код следующей операции (одноуровневый конвейер). Поэтому в общем потоке команд одна короткая команда реализуется за 4 периода тактовой частоты или за один машинный цикл.

            В микроконтроллерах AVR тоже используется одноуровневый конвейер при обращении к памяти программ и короткая команда в общем потоке выполняется, как и в PIC-контроллерах, за один машинный цикл. Главное же отличие состоит в том, что этот цикл у AVR составляет всего один период тактовой частоты. Для сравнения, на рис. 3 приведены временные диаграммы при выполнении типовой команды для различных микроконтроллерных платформ.

 

2. Система команд AVR

Система команд AVR весьма развита и насчитывает до 133 различных инструкций. Почти все команды имеют фиксированную длину в одно слово (16 бит), что позволяет в большинстве случаев объединять в одной команде и код операции, и операнд(ы). Лишь немногие команды имеют размер в 2 слова (32 бит) и относятся к группе команд вызова процедуры CALL, длинных переходов в пределах всего адресного пространства JMP, возврата из подпрограмм RET и команд работы с памятью программ LPM.

Различают пять групп команд AVR: условного ветвления, безусловного ветвления, арифметические и логические операции, команды пересылки данных, команды работы с битами. В последних версиях кристаллов AVR семейства "mega" реализована функция аппаратного умножения, что придает новым микроконтроллерам еще больше привлекательности с точки зрения разработчика.

 

3. Архитектура микроконтроллеров AVR

Файл регистров быстрого доступа, содержит 32 8-разрядных рабочих регистра общего назначения связанных непосредственно с ALU. За один тактовый цикл из файла регистров выбираются два операнда, выполняется операция и результат вновь возвращается в файл регистров.

Шесть из 32 регистров могут быть использованы как три 16-разрядных регистра указателя косвенной адресации адресного пространства данных, обеспечивающие эффективное вычисление адресов. Один из этих указателей адреса используется, также, как указатель адреса для функции непрерывного просмотра таблиц. Эти 16-разрядные дополнительные регистры обозначаются X-регистр, Y-регистр и Z-регистр.

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

На рисунке показана AVR расширенная RISC архитектура микроконтроллеров ATmega603/103.

 

 

Рис. 5. Расширенная RISC архитектура микроконтроллеров ATmega603/103

 

В дополнение к операциям с регистрами, регистровый файл может использоваться и для обычной адресации памяти. Это объясняется тем, что файл регистров располагается по 32 самыми младшими адресами пространства данных, и к ним можно обращаться как к обычным ячейкам памяти.

Пространство памяти I/O содержит 64 адреса периферийных функций CPU таких как: регистры управления, таймеры/счетчики, аналого-цифровые преобразователи и другие I/O функции. К памяти I/O можно обращаться непосредственно или как к ячейкам пространства памяти соответствующим адресам регистра файлов $20 - $5F.

В микроконтроллерах AVR использованы принципы Гарвардской архитектуры - отдельные память и шины для программ и данных. При работе с памятью программ используется одноуровневый конвейер - в то время, как одна команда выполняется, следующая команда выбирается из памяти программ, Такой прием позволяет выполнять команду в каждом тактовом цикле. Памятью программ является внутрисистемно программируемая Flash память. За малым исключением AVR команды имеют формат одного 16-разрядного слова, в связи с чем каждый адрес памяти программ содержит одну 16-разрядную команду.        

В процессе обработки прерываний и вызовов подпрограмм адрес возврата счетчика команд (PC) сохраняется в стеке. Стек размещается в SRAM данных и, следовательно размер стека ограничен только общим размером SRAM и уровнем ее использования. Все пользовательские программы в подпрограммах возврата (прежде, чем подпрограммы или прерывания будут выполняться) должны инициализировать указатель стека (SP). 16-разрядный указатель стека, с возможностью чтения/записи располагается в пространстве I/O.

AVR архитектура поддерживает пять различных режимов адресации 4000 байт SRAM данных. Гибкий модуль обработки прерываний имеет в пространстве I/O свой управляющий регистр с дополнительным битом разрешения глобального прерывания в регистре статуса. Все прерывания имеют свои векторы прерывания в таблице векторов прерывания, располагаемой в начале памяти программ. Приоритеты прерываний соответствуют положению векторов прерываний - прерывание с наименьшим адресом вектора имеет наивысший приоритет.  

По разнообразию и количеству реализованных инструкций AVR больше похожи на CISC, чем на RISC процессоры. Например, у PIC-контроллеров система команд насчитывает до 75 различных инструкций, а у MCS51 она составляет 111. В целом, прогрессивная RISC архитектура AVR в сочетании с наличием регистрового файла и расширенной системы команд позволяет в короткие сроки создавать работоспособные программы с эффективным кодом как по компактности реализации, так и по скорости выполнения.

 

3.1.Регистровый файл быстрого доступа

Следующая отличительная черта архитектуры микроконтроллеров AVR - регистровый файл быстрого доступа, структурная схема которого показана на рис. 4. Каждый из 32-х регистров общего назначения длиной 1 байт непосредственно связан с арифметико-логическим устройством (ALU) процессора. Другими словами, в AVR существует 32 регистра - аккумулятора (сравните, например, с MCS51). Это обстоятельство позволяет в сочетании с конвейерной обработкой выполнять одну операцию в ALU за один машинный цикл. Так, два операнда извлекаются из регистрового файла, выполняется команда и результат записывается обратно в регистровый файл в течение только одного машинного цикла.

Рис. 3. Сравнительная характеристика некоторых микропроцессорных платформ

 

Шесть из 32-х регистров файла могут использоваться как три 16-разрядных указателя адреса при косвенной адресации данных. Один из этих указателей (Z Pointer) применяется также для доступа к данным, записанным в памяти программ микроконтроллера. Использование трех 16-битных указателей (X, Y и Z Pointers) существенно повышает скорость пересылки данных при работе прикладной программы.

 


Рис. 4.  Регистровый файл

 

Регистровый файл занимает младшие 32 байта в общем адресном пространстве SRAM AVR. Такое архитектурное решение позволяет получать доступ к быстрой "регистровой" оперативной памяти микроконтроллера двумя путями - непосредственной адресацией в коде команды к любой ячейке и другими способами адресации ячеек SRAM.

В технической документации фирмы Atmel это полезное свойство носит название "быстрое контекстное переключение" и является еще одной отличительной особенностью архитектуры AVR, повышающей эффективность работы микроконтроллера и его производительность. Особенно заметно данное преимущество при реализации процедур целочисленной 16-битной арифметики, когда исключаются многократные пересылки между различными ячейками памяти данных при обработке арифметических операндов в ALU.

 

mc-plc.ru

Ассемблер – переводчик удобных для восприятия человеком команд в машинные коды для мк. Инструкция «загрузить в регистр с именем r16 константу 0x12» на ассемблере выглядит так: ldi

Ассемблер – переводчик удобных для восприятия человеком команд в машинные коды для - страница №1/1


Ликбез по микроконтроллерам AVR. Часть 2. Автор статьи picmaniac.
Эти статьи я буду писать специально для тех, кто только начинает освоение микроконтроллеров и намеревается поработать с микроконтроллерами AVR. Сам я раньше программировал только PIC. Сейчас взялся за освоение AVR. Шаги, пройденные мной на пути освоения микроконтроллерной премудрости, я и намерен оформить в виде цикла статей. Речь в статье будет именно о 8-битных AVR, все упоминания о других микроконтроллерах будут отмечены особо.
Теперь предстоит разобраться – как именно программист может выполнять операции с регистрами AVR при помощи написанной им программы. Для начала немного поговорим об ассемблере, прошу сторонников Си не ругаться, до ЯВУ мы ещё доберёмся.

Как я уже писал в первой части, программа – это заданная программистом последовательность инструкций, каждая из которых предписывает МК выполнить определённое действие. Пример инструкции: загрузить в регистр с именем r16 константу 0x12. Приказ этот для МК в виде 16-битного числа выглядит так: 1110000100000010. Именно это число, которое называется КОД ОПЕРАЦИИ, и будет занесено в 16-битную ячейку памяти программ по соответствующему адресу. Как именно распределяется программа по ячейкам памяти программ – разберём немного позже. Последовательность инструкций в виде 16-битных чисел представляет собой программу для AVR в машинных кодах. Однако, процесс написания программы в машинных кодах очень неудобен для человека. Поэтому в помощь программисту существует АССЕМБЛЕР – переводчик удобных для восприятия человеком команд в машинные коды для МК. Инструкция «загрузить в регистр с именем r16 константу 0x12» на ассемблере выглядит так:

ldi r16,0x12

Сокращение «ldi» образовано от английских слов «load data immediate» - «загрузка данных непосредственная». МНЕМОНИКА команды – запись её в виде ldi Rd, K – достаточно легко запоминается человеком. СИСТЕМА КОМАНД микроконтроллера – это совокупность всех команд, которые могут быть применены к данному МК. Число входящих в систему команд различно для разных семейств МК. Мнемоники также различаются. Поэтому ассемблер для одного семейства МК существенно отличается от предназначенного для другого семейства.

Для ознакомления с системой команд AVR откройте главу 3 книги А.В. Евстифеева «Микроконтроллеры AVR семейства Mega. Руководство пользователя».

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


start: ldi r16,0x02 ; Загрузить константу 0х02 в регистр общего назначения r16

out DDRB,r16 ; Записать в регистр DDRB данные из регистра r16

; Теперь вывод PB1 оказался настроен на выход

ldi r16,0x1D ; Аналогичные действия с регистрами. Выключить

out PORTB,r16 ; светодиод, который подключен к между PB1 и «общим»

rjmp start ; Перейти на метку start
Как видите, ничего сложного. Команды ассемблера не должны начинаться с самого начала строки, следует делать отступ. С самой первой строки пишутся МЕТКИ. Метки – это придуманные программистом для своего удобства слова. Ими помечаются те адреса в памяти программ, на которые возможны переходы. Встретив команду перехода на какую-либо метку, ассемблер подставит в код операции соответствующий этой метке адрес. Никто не запрещает программисту указывать адрес непосредственно в виде числа. Просто применение меток делает программу более наглядной и позволяет не следить за возможными изменениями адресов. Подобно тому, как Пупкин может сначала поселиться в гостиничном номере 105, а затем его переселят в номер 209. Но если просто сказать «Пойдём в номер Пупкина», мы разберёмся, по какому адресу идти в данный момент. После имени метки в ассемблере AVR следует ставить двоеточие. Недопустимо ставить в программе 2 метки с одинаковым именем.

После точки с запятой пишутся КОММЕНТАРИИ. Это пояснения, которые программист пишет для себя и тех, кто будет смотреть программу. Микроконтроллеру они не нужны, поэтому ассемблер их просто игнорирует.

Адреса ячеек памяти программ в AVR начинаются с нуля ($0000). Адрес последней ячейки и их общее количество зависят от модели МК. Например, у ATmega16 объём памяти программ составляет 8192 ячейки. Ячейки 16-битные, поэтому память программ занимает 16 килобайт. Память может измеряться и в словах. 1 слово занимает 16 бит или 2 байта. Таким образом, объём памяти ATmega16 составляет 8K слов. Адреса ячеек – от $0000 до $1FFF. Большинство инструкций занимают по 1 ячейке, некоторым необходимо 2. Максимальный размер программы для конкретного МК как раз и ограничивается объёмом его памяти программ.


Рис.2.1. Память программ AVR на примере ATmega16
Откуда МК узнаёт – какую именно команду ему предстоит выполнить сейчас? Адрес ячейки памяти программ со следующей исполняемой командой находится в специальном регистре, который называется ПРОГРАММНЫЙ СЧЁТЧИК или PC. Другое его название – СЧЁТЧИК КОМАНД. В микроконтроллерах AVR, в отличие от PIC, для программиста PC напрямую недоступен. При нормальной работе МК число в регистре PC после выполнения каждой команды автоматически увеличивается на 1 (или на 2, если команда занимает 2 ячейки). При переходах и ещё в некоторых случаях (прерывания, вызов подпрограмм и возврат из них) этот порядок нарушается, и в PC загружается тот адрес, на который выполняется переход. Таким образом, порядок выполнения инструкций, находящихся в памяти программ, соответствует последовательности значений PC.

Скорость работы МК определяется тактовой частотой. 1 машинный цикл AVR выполняется за время 1 периода тактового генератора. Таким образом, при частоте тактового генератора 1 МГц за 1 секунду произойдет 1 миллион тактов. Большая часть команд выполняется микроконтроллерами AVR за 1 машинный цикл. Это стало возможным благодаря конвейерной обработке команд. При отработке команд перехода и ещё некоторых нормальная работа конвейера нарушается, и возникают задержки от 1 до 4 тактов. Подробнее о работе конвейера и причинах возникновения задержек почитайте в книге А.В. Евстифеева «Микроконтроллеры AVR семейства Mega. Руководство пользователя», глава 2, раздел 2.3.

Источники тактового сигнала могут быть различными, по выбору программиста. Самые распространённые варианты – это внутренний RC-генератор (не требует подключения внешних деталей), генератор с внешней RC-цепочкой, или встроенный кварцевый генератор с подключаемым внешним резонатором. Возможно также использование тактового сигнала от внешнего источника. Нижняя граница тактовой частоты архитектурой самого МК не ограничивается, она может быть сколь угодно малой – хоть 1 такт в год от внешнего источника. Верхняя граница зависит от модели МК и нередко составляет 8 или 16 МГц. Подробности, как обычно, можете узнать из даташита на конкретный МК. Полезно прочитать главу 4 книги А.В. Евстифеева «Микроконтроллеры AVR семейства Mega. Руководство пользователя».

Адрес $0000 – это ВЕКТОР СБРОСА. Именно с размещённой по этому адресу команды начинается выполнение программы после включения питания или сброса МК. Значение адреса вектора сброса в некоторых МК может быть изменено, но этот случай нас пока не интересует. Сброс может быть вызван внутренними или внешними причинами. О внутренних разговор будет позже. Одной из причин сброса является падение напряжения питания Vcc ниже определённой величины. Для внешнего сброса предназначен вывод _RESET. Сброс происходит при удержании низкого уровня (не более 0,1 Vcc) на этом выводе не менее 1…3 мкс. При работе МК на выводе _RESET должно поддерживаться напряжение (0,9…1,0) Vcc. Во многих AVR имеется внутренний подтягивающий резистор, соединяющий _RESET c Vcc. В этом случае _RESET допустимо никуда не подключать, но для большей надёжности можно установить и дополнительный внешний резистор. Подробности о сбросе можете прочитать в книге А.В. Евстифеева «Микроконтроллеры AVR семейства Mega. Руководство пользователя», глава 4, раздел 4.4.

При сбросе во все регистры ввода/вывода (РВВ) заносятся начальные значения, заданные фирмой-производителем, а в PC загружается адрес вектора сброса. Выполнение программы после сброса начинается не мгновенно, а после некоторой задержки, для надёжности. По адресу $0000 программист обычно размещает команду безусловного перехода к инициализационной части программы, начало которой он обозначает меткой, например, “start”. Это делается для того, чтобы обойти размещённую в начале памяти программ таблицу векторов прерываний. О прерываниях ещё предстоит отдельный большой рассказ.

.org 0


reset: jmp start

……

…… (здесь переходы на обработку прерываний)

……

start: ldi r16,0x12

…… (отсюда продолжается программа)
В этом примере reset и start – метки. Директивой org программист указывает ассемблеру, по какому адресу следует поместить следующую команду в памяти программ. Таким образом, команда jmp start будет размещена по адресу $0000. Перед директивами в ассемблере AVR следует ставить точку. Какую команду следует применить здесь для перехода – двухбайтовую jmp или однобайтовую rjmp – зависит от конкретной модели AVR, смотрите в даташите. По какому адресу будет находиться первая команда инициализационной части (в примере это ldi) – нам в данном случае неважно, пусть ассемблер её сам расположит, а нам достаточно знать метку.

После сброса МК в PC загрузится вектор сброса $0000 и будет выполнена находящаяся по этому адресу команда безусловного перехода к метке start. Следовательно, в PC загрузится соответствующий метке start адрес, и выполнение программы продолжится с команды

ldi r16,0x12

Инициализационная часть программы (далее я буду называть её просто инициализацией МК) предназначена для программной настройки микроконтроллера после сброса под нужды программиста. Здесь выполняется настройка выводов портов на вход/выход, включение и настройка периферийных модулей, занесение требуемых начальных значений в регистры. После инициализации МК выполняет возложенные на него программистом задачи.


Выводы по 2 части:

  1. Для перевода удобных человеку команд в машинные коды предназначен ассемблер.

  2. Набор возможных действий программиста с микроконтроллером определяется системой команд этого МК.

  3. Каждая команда имеет определённую мнемонику для лучшего запоминания.

  4. При написании программы на ассемблере применяются метки, комментарии и директивы.

  5. Максимальный размер программы ограничивается объёмом памяти программ выбранного МК.

  6. Порядок выполнения находящихся в памяти программ команд соответствует последовательности значений программного счётчика PC.

  7. Скорость работы МК определяется тактовой частотой. 1 такт работы AVR выполняется за 1 период тактовой частоты.

  8. Тактирование AVR возможно от внутреннего RC-генератора, подключение внешних деталей при этом не требуется.

  9. Выполнение программы после включения питания или сброса МК начинается с адреса вектора сброса (для AVR обычно $0000).

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

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

  12. Инициализация предназначена для программной настройки МК после сброса под нужды программиста.

umotnas.ru

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *