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

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

Таблицы команд ассемблера AVR — Микроконтроллеры для всех

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

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

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

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

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

КомандаОписаниеДействиеЦиклыКод операцииФлаги
add Rd,RrAdd two RegistersRd←Rd+Rr10000 11rd dddd rrrrZ,C,S,N,V,H
adc Rd,RrAdd with Carry two RegistersRd←Rd+Rr+C10001 11rd dddd rrrrZ,C,S,N,V,H
adiw Rdl,KAdd Immediate to WordRdh:Rdl←Rdh:Rdl+K21001 0110 KKdd KKKKZ,C,S,N,V
sub Rd,Rr
Subtract two Registers
Rd←Rd-Rr10001 10rd dddd rrrrZ,C,S,N,V,H
sbc Rd,RrSubtract with Carry two RegistersRd←Rd-Rr-C10000 10rd dddd rrrrZ,C,S,N,V,H
subi Rd,KSubtract Constant from RegisterRd←Rd-K11010 KKKK dddd KKKKZ,C,S,N,V,H
sbci Rd,KSubtract with Carry Constant from RegisterRd←Rd-K-C10100 KKKK dddd KKKKZ,C,S,N,V,H
sbiw Rdl,KSubtract Immediate from WordRdh:Rdl←Rdh:Rdl-K21001 0111 KKdd KKKKZ,C,S,N,V
and Rd,RrLogical AND RegistersRd←Rd AND Rr10010 00rd dddd rrrrZ,S,N
andi Rd,KLogical AND Register and ConstantRd←Rd AND K10111 KKKK dddd KKKKZ,S,N
or Rd,RrLogical OR RegistersRd←Rd OR Rr10010 10rd dddd rrrrZ,S,N
ori Rd,KLogical OR Register and ConstantRd←Rd OR K10110 KKKK dddd KKKKZ,S,N
eor Rd,RrExclusive OR RegistersRd←Rd EOR Rr10010 01rd dddd rrrrZ,S,N
com RdOne’s complementRd←0xFF-Rd11001 010d dddd 0000Z,S,N
neg RdTwo’s complementRd←0x00-Rd11001 010d dddd 0001 Z,C,S,N,V,H
sbr Rd,KSet Bit (s) in RegisterRd←Rd OR K10110 KKKK dddd KKKKZ,S,N
cbr Rd,KClear Bit (s) in RegisterRd←Rd AND (0xFF- K)10111 KKKK dddd KKKKZ,S,N
inc RdIncrementRd←Rd+111001 010d dddd 0011Z,S,N,V
dec RdDecrementRd←Rd-111001 010d dddd 1010Z,S,N,V
tst RdTest for Zero or MinusRd←Rd AND Rd10010 00dd dddd ddddZ,S,N
clr RdClear RegisterRd←Rd EOR Rd10010 01dd dddd dddd
Z,S,N
ser RdSet RegisterRd←0xFF11110 1111 dddd 1111None

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

КомандаОписаниеДействиеЦиклыКод операцииФлаги
mov Rd,RrMove Between RegistersRd←Rr10010 11rd dddd rrrrNone
movw Rd,RrCopy Register WordRd+1:Rd←Rr+1:Rr10000 0001 dddd rrrrNone
ldi Rd,K
Load ImmediateRd←K11110 KKKK dddd KKKKNone
ld Rd,XLoad IndirectRd← (X)21001 000d dddd 1100None
ld Rd,X+Load Indirect and
Post-Inc.
Rd← (X), X←X+121001 000d dddd 1101None
ld Rd, -XLoad Indirect and
Pre-Dec.
X←X-1, Rd← (X)21001 000d dddd 1110None
ld Rd,YLoad IndirectRd← (Y)21000 000d dddd 1000None
ld Rd,Y+Load Indirect and
Post-Inc.
Rd← (Y), Y←Y+12
1001 000d dddd 1001
None
ld Rd, -YLoad Indirect and
Pre-Dec.
Y←Y-1, Rd← (Y)21001 000d dddd 1010None
ldd Rd,Y+qLoad Indirect with DisplacementRd← (Y+q)210q0 qq0d dddd 1qqqNone
ld Rd,ZLoad IndirectRd← (Z)21000 000d dddd 0000None
ld Rd,Z+Load Indirect and
Post-Inc.
Rd← (Z), Z←Z+121001 000d dddd 0001None
ld Rd, -ZLoad Indirect and
Pre-Dec.
Z←Z-1, Rd← (Z)21001 000d dddd 0010None
ldd Rd,Z+qLoad Indirect with DisplacementRd← (Z+q)210q0 qq0d dddd 0qqqNone
lds Rd,kLoad Direct from SRAMRd← (k)21001 000d dddd 0000kkkk kkkk kkkk kkkkNone
st X,RrStore Indirect(X) ←Rr21001 001r rrrr 1100None
st X+,RrStore Indirect and
Post-Inc.
(X) ←Rr, X←X+121001 001r rrrr 1101None
st -X,RrStore Indirect and
Pre-Dec.
X←X-1, (X) ←Rr21001 001r rrrr 1110None
st Y,RrStore Indirect(Y) ←Rr21000 001r rrrr 1000None
st Y+,RrStore Indirect and
Post-Inc.
(Y) ←Rr, Y←Y+121001 001r rrrr 1001None
st -Y,RrStore Indirect and
Pre-Dec.
Y←Y-1, (Y) ←Rr21001 001r rrrr 1010None
std Y+q,RrStore Indirect with Displacement(Y+q) ← Rr210q0 qq1r rrrr 1qqqNone
st Z,RrStore Indirect(Z) ←Rr21000 001r rrrr 0000None
st Z+,RrStore Indirect and
Post-Inc.
(Z) ←Rr, Z←Z+121001 001r rrrr 0001 None
st -Z,RrStore Indirect and
Pre-Dec.
Z←Z-1, (Z) ←Rr21001 001r rrrr 0010None
std Z+q,RrStore Indirect with Displacement(Z+q) ← Rr210q0 qq1r rrrr 0qqqNone
sts k,RrStore Direct to SRAM(k) ←Rr21001 001r rrrr 0000kkkk kkkk kkkk kkkkNone
lpmLoad Program MemoryR0← (Z)31001 0101 1100 1000None
lpm Rd,ZLoad Program MemoryRd← (Z)31001 000d dddd 0100None
lpm Rd,Z+Load Program Memory
and Post-Inc.
Rd← (Z), Z←Z+131001 000d dddd 0101None
spmStore Program Memory(Z) ←R1:R01001 0101 1110 1000None
in Rd,PIn PortRd←P11011 0PPd dddd PPPPNone
out P,RrOut PortP←Rr11011 1PPr rrrr PPPPNone
push RrPush Register in StackSTACK←Rr, SP←SP-121001 001r rrrr 1111None
pop RdPop Register from StackSP←SP+1, Rd←STACK21001 000d dddd 1111None

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

КомандаОписаниеДействиеЦиклыКод операцииФлаги
rjmp kRelative JumpPC←PC+k+121100 kkkk kkkk kkkkNone
ijmpIndirect Jump to (Z)PC← (Z)21001 0100 0000 1001None
*jmp kDirect JumpPC←k31001 010k kkkk 110kkkkk kkkk kkkk kkkkNone
rcall kRelative Subroutine CallSTACK←PC+1,PC←PC+k+1,SP←SP-2 or 3¾1101 kkkk kkkk kkkkNone
icallIndirect Call to (Z)STACK←PC+1, PC← (Z),SP←SP-2 or 3¾1001 0101 0000 1001None
*call kDirect Subroutine CallSTACK←PC+1, PC←k,SP←SP-2 or 34/51001 010k kkkk 111kkkkk kkkk kkkk kkkkNone
retSubroutine ReturnPC←STACK,
SP←SP+2 or 3
4/51001 0101 0000 1000None
retiInterrupt ReturnPC←STACK,
SP←SP+2 or 3
4/51001 0101 0001 1000I
cpse Rd,RrCompare, Skip if Equalif (Rd=Rr)
PC←PC+2 or 3
½/30001 00rd dddd rrrrNone
cp Rd,RrCompareRd-Rr10001 01rd dddd rrrrZ,C,S,
N,V,H
cpc Rd,RrCompare with CarryRd-Rr-C10000 01rd dddd rrrrZ,C,S,
N,V,H
cpi Rd,KCompare Register with ImmediateRd-Rr-K10011 KKKK dddd KKKKZ,C,S,
N,V,H
sbrc Rr,bSkip if Bit in
Register is Cleared
if (Rr (b)=0)
PC←PC+2 or 3
½/31111 110r rrrr obbbNone
sbrs Rr,bSkip if Bit in
Register is Set
if (Rr (b)=1)
PC←PC+2 or 3
½/31111 111r rrrr obbbNone
sbic P,bSkip if Bit in IO
Register is Cleared
if (P (b)=0)
PC←PC+2 or 3
½/31001 1001 PPPP PbbbNone
sbis P,bSkip if Bit in IO
Register is Set
if (P (b)=1)
PC←PC+2 or 3
½/31001 1011 PPPP PbbbNone
brbc s,kBranch if Status
Flag is Cleared
if (SREG (s)=0)
PC←PC+k+1
½1111 01kk kkkk ksssNone
brbs s,kBranch if Status
Flag is Set
if (SREG (s)=1)
PC←PC+k+1
½1111 00kk kkkk ksssNone
brcc kBranch if Carry
Flag is Clearsd
if (C=0) PC←PC+k+1½1111 01kk kkkk k000None
brcs kBranch if Carry
Flag is Set
if (C=1) PC←PC+k+1½1111 00kk kkkk k000None
brsh kBranch if Same
or Higher
if (C=0) PC←PC+k+1½1111 01kk kkkk k000None
brlo kBranch if Lowerif (C=1) PC←PC+k+1½1111 00kk kkkk k000None
brne kBranch if Not Equalif (Z=0) PC←PC+k+1½1111 01kk kkkk k001None
breq kBranch if Equalif (Z=1) PC←PC+k+1½1111 00kk kkkk k001None
brpl kBranch if Plusif (N=0) PC←PC+k+1½1111 01kk kkkk k010None
brmi kBranch if Minusif (N=1) PC←PC+k+1½1111 00kk kkkk k010None
brvc kBruach if Overflow
Flag is Cleared
if (V=0) PC←PC+k+1½1111 01kk kkkk k011None
brvs kBranch if Overflow
Flag is Set
if (V=1) PC←PC+k+1½1111 00kk kkkk k011None
brge kBranch if Greate or
Equal, Signed
if (S=0) PC←PC+k+1½1111 01kk kkkk k100None
brlt kBranch if Less than
Zero, Signed
if (S=1) PC←PC+k+1½1111 00kk kkkk k100None
brhc kBranch if Half Carry
Flag is Cleared
if (H=0) PC←PC+k+1½1111 01kk kkkk k101None
brhs kBranch if Half Carry
Flag is Set
if (H=1) PC←PC+k+1½1111 00kk kkkk k101None
brtc kBranch if Transfer
Flag is Cleared
if (T=0) PC←PC+k+1½1111 01kk kkkk k110None
brts kBranch if Transfer
Flag is Set
if (T=1) PC←PC+k+1½1111 00kk kkkk k110None
brid kBranch if Interrupt
Disable
if (T=0) PC←PC+k+1½1111 01kk kkkk k111None
brie kBranch if Interrupt
Enable
if (T=1) PC←PC+k+1½1111 00kk kkkk k111None

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

 

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

ПроверкафлагаКоманда условногопереходаАльтернативнаяФорма написанияУсловие перехода
Cbrbc 0,kbrcc kПереход если флаг переноса установлен
brsh kПереход если больше или равно
brbs 0,kbrcs kПереход если флаг переноса сброшен
brlo kПереход если меньше
Zbrbc 1,kbreq kПереход если равно
brbs 1,kbrne kПереход если не равно
Nbrbc 2,kbrpl kПереход если плюс
brbs 2,kbrmi kПереход если минус
Vbrbc 3,kbrvc kПереход если флаг дополнительного кода сброшен
brbs 3,kbrvs kПереход если флаг дополнительного кода установлен
Sbrbc 4,kbrge kПереход если больше или равно нулю (знаковое)
brbs 4,kbrlt kПереход если меньше нуля (знаковое)
Hbrbc 5,kbrhc kПереход если флаг половинного переноса сброшен
brbs 5,kbrhs kПереход если флаг половинного переноса установлен
Tbrbc 6,kbrtc kПереход если флаг хранения бита сброшен
brbs 6,kbrts kПереход если флаг хранения бита установлен
Ibrbc 7,kbrid kПереход если прерывания запрещены
brbs 7,kbrie kПереход если прерывания разрешены

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

КомандаОписаниеДействиеЦиклыКод операцииФлаги
sbi P,bSet Bit in I/O ReristerI/O (P,b) ←121001 1010 PPPP PbbbNone
cbi P,bClear Bit in I/OReristerI/O (P,b) ←021001 1000 PPPP PbbbNone
lsl RdLogical Shift LeftRd (n+1) ←Rd (n), Rd (0) ←010000 11dd dddd ddddZ,C,N,V
lsr RdLogical Shift RightRd (n) ←Rd (n+1), Rd (7) ←011001 010d dddd 0110Z,C,N,V
rol RdRotate Left through CarryRd (0) ←C, Rd (n+1) ←Rd (n), C←Rd (7)10001 11dd dddd ddddZ,C,N,V
ror RdRotate Right through CarryRd (7) ←C, Rd (n) ←Rd (n+1), C←Rd (0)11001 010d dddd 0111Z,C,N,V
asr RdArithmetic Shift RightRd (n) ←Rd (n+1),
n=0…6
11001 010d dddd 0101Z,C,N,V
swap RdSwap NibblesRd (3…0) ←Rd (7…4),Rd (7…4) ←Rd (3…0)11001 010d dddd 0010None
bst Rr,bBit Store from
Rerister to T
T←Rr (b)11111 101b bbbb 0bbbT
bld Rd,bBit Load from T
to Rerister
Rd (b) ←T11111 100b bbbb 0bbbNone
bset sFlag SetSREG (s) ←111001 0100 0sss 1000SREG (s)
bclr sFlag ClearSREG (s) ←011001 0100 1sss 1000SREG (s)
secSet CarryC←111001 0100 0000 1000C
clcClear CarryC←011001 0100 1000 1000C
sezSet Zero FlagZ←111001 0100 0001 1000Z
clzClear Zero FlagZ←011001 0100 1001 1000Z
senSet Negative FlagN←111001 0100 0010 1000N
clnClear Negative FlagN←011001 0100 1010 1000N
sevSet Twos Complement OverflowV←111001 0100 0011 1000V
clvClear Twos Complement OverflowV←011001 0100 1011 1000V
sesSet Signed Test FlagS←111001 0100 0100 1000S
clsClear Signed Test FlagS←011001 0100 1100 1000S
sehSet Half Carry FlagH←111001 0100 0101 1000H
clhClear Half Carry FlagH←011001 0100 1101 1000H
setSet Transfer bitT←111001 0100 0110 1000T
cltClear Transfer bitT←011001 0100 1110 1000T
seiGlobal Interrupt EnableI←111001 0100 0111 1000I
cliGlobal Interrupt DisableI←011001 0100 1111 1000I

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

КомандаОписаниеДействиеЦиклыКод операцииФлаги
nopNo operation10000 0000 0000 0000None
sleepSleep11001 0101 1000 1000None
wdrWatchdog Reset11001 0101 1010 1000None

 

 

Понравилась статья? Поделиться с друзьями:

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

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

МнемоникаОписаниеОперацияФлаги
ADD Rd, RrСложение двух регистровRd ← Rd + RrZ, C, N, V, H
ADC Rd, RrСложение двух регистров с переносомRd ← Rd + Rr + СZ, C, N, V, H
SUB Rd, RrВычитание двух регистровRd ← Rd — RrZ, 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 + KZ, C, N, V, S
SBIW Rd, KВычитание константы из регистровой парыR(d+1):Rdl ← R(d+1):Rd — KZ, C, N, V, S
SUBI Rd, KВычитание константы из регистраRd ← Rd — KZ, C, N, V, H
SBCI Rd, KВычитание константы из регистра с заёмомRd ← Rd — K — СZ, C, N, V, H
INC RdИнкремент регистраRd ← Rd + 1Z, N, V
DEC RdДекремент регистраRd ← Rd – 1Z, N, V
MUL Rd, RrУмножение чисел без знакаR1:R0 ← Rd * RrZ, C
MULS Rd, RrУмножение чисел со знакомR1:R0 ← Rd * RrZ, C
MULSU Rd, RrУмножение числа со знаком с числом без знакаR1:R0 ← Rd * RrZ, C
FMUL Rd, RrУмножение дробных чисел без знакаR1:R0 ← (Rd * Rr) << 1Z, C
FMULS Rd, RrУмножение дробных чисел со знакомR1:R0 ← (Rd * Rr) << 1Z, C
FMULSU Rd, RrУмножение дробного числа со знаком с числом без знакаR1:R0 ← (Rd * Rr) << 1Z, C
МнемоникаОписаниеОперацияФлаги
CBR Rd, KОчистка разрядов регистраRd ← Rd and (0FFH – K)Z, N, V
SBR Rd, KУстановка разрядов регистраRd ← Rd or KZ, N, V
CBI P, bСброс разряда I/O-регистраP.b ← 0
SBI P, bУстановка разряда I/O-регистраP.b ← 1
BCLR sСброс флага SREGSREG.s ← 0SREG.s
BSET sУстановка флага SREGSREG.s ← 1SREG.s
BLD Rd, bЗагрузка разряда регистра из флага TRd.b ← T
BST Rr, bЗапись разряда регистра во флаг TT ← Rd.bT
CLCСброс флага переносаC ← 0C
SECУстановка флага переносаC ← 1C
CLNСброс флага отрицательного числаN ← 0N
SENУстановка флага отрицательного числаN ← 1N
CLZСброс флага нуляZ ← 0Z
SEZУстановка флага нуляZ ← 1Z
CLIОбщий запрет прерыванийI ← 0I
SEIОбщее разрешение прерыванийI ← 1I
CLSСброс флага знакаS ← 0S
SESУстановка флага знакаS ← 1S
CLVСброс флага переполнения дополнительного кодаV ← 0V
SEVУстановка флага переполнения дополнительного кодаV ← 1V
CLTСброс пользовательского флага TT ← 0T
SETУстановка пользовательского флага TT ← 1T
CLHСброс флага половинного переносаH ← 0H
SEHУстановка флага половинного переносаH ← 1H
МнемоникаОписаниеОперацияФлаги
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+Загрузка данных из памяти программы с пост-инкрементом ZRd ← {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

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

Система команд микроконтроллеров AVR

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

Итак, микроконтроллер имеет  своем составе 32 регистра. Первая их половина (R0-R15) не может быть использована в операциях с непосредственным операндом. Во второй половине есть специфические регистровые пары, которые могут использоваться в операциях пересылки данных между регистрами и памятью и некоторых других действий (X,Y и Z). Заметим к тому же, что «возможности» этих регистровых пар различны!

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

Ну и последнее — периферия, или регистры ввода-вывода (I/O). Можно прочитать данные из I/O в регистр общего назначения и записать из регистра общего назначения в I/O. Кроме этого, у части регистров ввода-вывода, а точнее — у тех, чей адрес не превышает 0x1F, возможна установка отдельных бит в состояние 0 или 1.

Операнды команд будем обозначать следующим (стандартным) способом:

Rdрегистр — приемник, место, куда сохраняется результат выполнения команды
Rsрегистр — источник в двухоперандных командах. Его значение после выполнения команды не изменяется.
I/Oрегистр ввода-вывода, или периферия. Это порты, таймеры и т.д.
K8-ми разрядная константа в операциях со «старшими» регистрами общего назначения (R16-R31)
bНомер бита в операциях с регистрами ввода-вывода
A16-ти разрядный адрес при работе с памятью данных
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 имеются следующие биты:

ISREG.7

Бит разрешения прерывания. Если он = 0, то все прерывания в МК запрещены. Если он =1, то разрешением прерываний будут управлять соответствующие биты периферии.

TSREG.6

Битовый аккумулятор. С этим битом работают команды BST  и BLD

HSREG.5

Флаг переноса из младшей тетрады

SSREG.4

Sign — ислючающее ИЛИ битов N и V

VSREG.3

oVerflow — переполнение

NSREG.2

Negative — Результат операции < 0

ZSREG.1

Zero — Результат операции равен нулю

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

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

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

 

Ликбез по микроконтроллерам 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

Как понять ассемблер для AVR / Хабр

Всем добрый вечер! Веду свою трансляцию из уютного мира, который называется «ассемблер». Сразу поясню что тема касается микроконтроллеров AVR — и я пока ещё не знаю, пригодится ли этот пост тем, кто хочет использовать ассемблер для любой другой задачи. Дело в том, что я буквально несколько дней назад начал учить ассемблер с нуля — нужно сделать одно устройство — и я решил сделать в нём всё самостоятельно. Так вот — в один прекрасный день понял, что учить ассемблер абсолютно бесполезно! Ассемблер можно только понять! То есть всем тем, кто хочет программировать на ассемблере я настоятельно рекомендую детально вникнуть в то, каким образом ФИЗИЧЕСКИ работает микроконтроллер, а затем уже изучать тонкости команд.
Так вот, я пожалуй начну небольшой цикл статей, в которых буду с самого начала рассказывать как именно я понял те или иные вещи в программировании на ассемблере — думаю для тех, кто вообще не понимает что такое асм я буду как раз таким «переводчиком» с языка тех, кто в этом деле очень хорошо шарит.

Сразу скажу, что я более-менее вкурил эту тему с подачи DIHALT — поэтому эти статейки будут являться неким переводом с супер-пупер-ассемблерно-микроконтроллерного языка на язык понятный большинству людей. Ну а гуру надеюсь будут меня поправлять по ходу пьесы и если вдруг я что то объясню неправильно — то они поправят меня.
Итак первые выводы об ассемблере, которые я сделал пару дней назад, меня потрясли до глубины души — и я просидел за статьями DI HALT’а с 11 вечера до 5 утра — после чего лёг спать довольным и счастливым. Я понял суть программирования на ассемблере для микроконтроллеров.
Как же это объяснить ещё проще? Думаю нужно начать с самой сути.
***
Изначально не будем вдаваться в технические подробности (о них мы поговорим в следующей статье) — просто представьте, что есть 3 персонажа:
1. Микроконтроллер — это англичанин Стив, который приехал к русскому. Он идеально знает английский язык, но по-русски он вообще не понимает — ни единого слова. Только английский. Он проиграл в споре и обязался делать бесприкословно всё то, о чём его попросит русский.
2. Ассемблер — это переводчик Вася у которого мама англичанка а папа русский. Он знает идеально и английский и русский язык.
3.Мы —это русский, к которому приехал англичанин. Ну то есть мы это мы=) При этом мы идеально знаем русский язык и (!!!) чуть-чуть английский — самую малость, со словариком.
***
Представьте такую ситуацию — англичанин сидит у Вас в комнате на стуле. А Вы сидите себе за компом и читаете этот пост, как вдруг у Вас внезапно открылась форточка! Вот ведь незадача! Ветер дует, занавеска превратилась в парус… Было бы неплохо закрыть! Но вот ведь как лень вставать со стула, снимать ноги с системника, запихивать их в тапочки, отставлять кружку с кофе(пивом) и идти бороться со стихией. И тут Вы внезапно осознаёте, что у нас то в комнате есть проспоривший англичанин, которого самое время погонять! И вы ему так мило говорите «Дружище! Закрой форточку пожалуйста, а потом можешь опять присесть на стул!» а он сидит, смотрит на вас с недоумением и ничего не делает! Можно конечно по щам надавать — но он же тогда всё равно вас не поймёт! Тогда Вы звоните своему другу-переводчику Василию — он приходит, и садится рядом с англичанином на стул. И вы говорите — Переведи: «Стив, пойди и закрой форточку, а потом обратно сядь на стул!» Переводчик переводит на английский — англичанин понимает и идёт закрывает форточку, а затем приходит и садится на стул.
В этом моменте нужно просто понять роль ассемблера в этой цепочке «Мы-Ассемблер-Контроллер»
То есть как бы что такое ассемблер все поняли? Тогда читаем дальше.
***

Так вот, представляем такую ситуацию. Васе говоришь — «Слушай, ну короче такое дело — я калькулятор дома забыл, раздели 56983 на 2 и скажи Стиву, чтобы он столько раз отжался на кулаках» и Вася на калькуляторе считает и говорит Стиву по-английски » Отожмись на кулаках 28491 раз» Это называется «ДИРЕКТИВА» — другими словами директива это задание для Васи, результат выполнения которой это действие Стива.

Есть другая ситуация — Вы говорите Васе «Скажи Стиву, чтобы он отжался 28491 раз» и Вася просто переводит Ваши слова на английский. Это называется ОПЕРАТОР

Всё просто — есть директива и есть оператор. Оператор — это Ваше прямое указание что делать Стиву — Вася тут только переводит Ваше требование на инглиш. А Директива — это задание для самого Васи — и Вася сначала делает то, что Вы ему сказали, а потом уже в зависимости от результата говорит Стиву что-либо.

Теперь мы будем мучать англичанина регулярно! Но предварительно нужно получше познакомиться с нашим переводчиком Васей. Нужно знать следующее — Вася всегда Вас слушается беспрекословно — что ему сказали, то он и делает. Васин калькулятор не имеет десятичных знаков — если вы глянете пример с отжиманиями то 56983 \ 2 = 28491.5 — но у Васи всё после запятой обрубается — и он видит только целое число — причём неважно там будет 28491.000001 или там будет 28491.9999999 — для Васи это один фиг будет 28491 в обоих случаях. Ничего не округляется. Ещё важная информация про Васю. Вася жесток — ему пофиг на то, что Стив затрахается отжиматься двадцать восемь тысяч раз. Ему сказали — Вася перевёл. Причём не только перевёл — но и заставил сделать то, что Вы попросили. Так что если Стив помрёт на двадцать три тысячи пятьсот тринадцатом отжимании — то это будет исключительно Ваша вина.

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

Программирование МК AVR на языке assembler в среде Linux / Хабр


Ни для кого не секрет, что микроконтроллеры семейства AVR прочно вошли в практику домашних поделок. Кроме того, уже несколько лет наблюдается массовое (на грани эпидемии) увлечение отладочными платами типа Arduino, построенными на базе все тех же AVR. Не буду судить, хорошо это или плохо, ибо статей на эту тему на ресурсе более чем достаточно. Хочу уберечь и моего читателя от споров на тему «что такое Arduino и хорошо это или плохо». Статья не об этом.

Рано или поздно для любого «ардуиньщика» (при условии что он хочет выйти на более высокий профессиональный уровень) наступает момент когда в рамках платформы Arduino ему становится тесно и он начинает задумываться о том а что же в действительности происходит под капотом. И ответы на все его вопросы уже есть, например в виде замечательного курса «AVR. Учебный курс» от глубокоуважаемого DIHALT. Если вы пользователь OS Windows, то и недостатка в инструментах разработки у вас не будет, достаточно бесплатной Atmel Studio, закрывающей все вопросы разработки ПО для МК AVR.

Хоть я и тимлид в коллективе разработчиков ПО прикладного уровня, вопросы «железа» которое в нашей конторе делается на базе AVR с недавних пор стали интересовать меня очень остро. Возникло желание хорошо разобраться во всех аспектах разработки ПО для МК. И так как я являюсь убежденным приверженцем использования в разработке OS на базе ядра Linux, меня заинтересовал вопрос, а как там в линуксах: можно/нельзя ли писать и отлаживать ПО, зашивать его в кристалл с тем же (или примерно тем же) уровнем удобства, который нам доступен в Windows. Тех кого тоже интересует этот вопрос, и в особенности тех, кому тема поста кажется надуманной, приглашаю под кат.

Что касается разработки на C/C++, в среде линукс с этим особых проблем и нет, в виду общей ориентированности этой системы на использование данного языка и наличия достойного набора инструментария. Однако, тот же DIHALT, например, утверждает что программирование для МК неотделимо от знания ассемблера, в чем я с ним соглашусь, в виду логичности его тезисов, изложенных в «Учебном курсе» и собственного (пусть небольшого) опыта системной разработки под x86.

Руководствуясь тезисом, что от асма AVR нам никуда не уйти и сидим мы под линуксом, попробуем посмотреть на то, как можно писать и отлаживать программы. Я использую дистрибутив Arch Linux, поэтому в своем повествовании буду опираться на его экосистему.


Сразу скажу, что связку Atmel Studio + wine я предлагать не буду. Не люблю я wine (хоть и пользуюсь по необходимости). Остановимся на нативных средствах, прежде всего компиляторов, обзор которых в сети и личные ковырялки дали выход на триумвират gavrasm, avra и avr-as. Выбор произошел по двум противоречивым критериям: поддержка синтаксиса предлагаемого Atmel и возможность отладки прошивки по шагам в эмуляторе. Последнее для меня более важно, а в плоскости курса @DIHAL так прям вообще необходимо для понимания процесса работы микроконтроллера. Общность синтаксиса с компиляторами от Atmel дает, опять таки с моей точки зрения, лишь возможность без труда адаптировать проекты Atmel Studio к работе в линуксах, что весьма сомнительное преимущество, ибо тот же avr-as существует и под Windows. Предлагаю читателю обзор перечисленной троицы.

gavrasm и avra


Поддерживают синтаксис Atmel. Первый нашелся в AUR и устанавливается командой
$ yaourt -S gavrasm

Второй так же доступен в AUR
$ yaourt -S avra

Программа вида

test.S

;---- Определяем целевое устройство
        .device atmega16
;---- Сегмент данных
        .dseg
;---- Сегмент кода
        .cseg
        .org 0x0000

        ldi r16, 10
M1:
        inc r16
        rjmp M1

;---- Сегмент EEPROM
        .eseg

Собирается обоими компиляторами сразу в *.hex и результат работы выглядит примерно одинаково. Чтобы не возмущать благородных донов длинными портянками, помещаю результаты компиляции под спойлерыВыхлоп gavrasm
$ gavrasm test.S
+------------------------------------------------------------+
| gavrasm gerd's AVR assembler Version 3.5 (C)2015 by DG4FAC |
+------------------------------------------------------------+
Compiling Source file: test.S
-------
Pass:        1
14 lines done.

Pass 1 ok.
-------
Pass:        2
14 lines done.


3 words code, 0 words constants, total=3 =  0.0%

No warnings!
Compilation completed, no errors. Bye, bye ...

$ ls -l
итого 12
-rw-rw----+ 1 maisvendoo users  52 июл 29 15:46 test.hex
-rw-rw----+ 1 maisvendoo users 741 июл 29 15:46 test.lst
-rw-rw----+ 1 maisvendoo users  92 июл 29 15:46 test.S

Содержимое hex-файла прошивки
:020000020000FC
:060000000AE00395FECFAB
:00000001FF

Содержимое файла листинга

gavrasm Gerd's AVR assembler version 3.5 (C)2015 by DG4FAC
----------------------------------------------------------
Source file: test.S
Hex file: test.hex
Eeprom file: test.eep
Compiled: 29.07.2017, 15:46:38
Pass: 2
1: .device atmega16
2:
3: .dseg
4:
5: .cseg
6: .org 0x0000
7:
8: 000000 E00A ldi r16, 10
9: M1:
10: 000001 9503 inc r16
11: 000002 CFFE rjmp M1
12:
13: .eseg
14:

Program : 3 words.
Constants : 0 words.
Total program memory: 3 words.
Eeprom space : 0 bytes.
Data segment : 0 bytes.
Compilation completed, no errors.
Compilation endet 29.07.2017, 15:46:38


Выхлоп avra
$ avra -l test.lst test.S 
AVRA: advanced AVR macro assembler Version 1.3.0 Build 1 (8 May 2010)
Copyright (C) 1998-2010. Check out README file for more info

   AVRA is an open source assembler for Atmel AVR microcontroller family
   It can be used as a replacement of 'AVRASM32.EXE' the original assembler
   shipped with AVR Studio. We do not guarantee full compatibility for avra.

   AVRA comes with NO WARRANTY, to the extent permitted by law.
   You may redistribute copies of avra under the terms
   of the GNU General Public License.
   For more information about these matters, see the files named COPYING.

Pass 1...
Pass 2...
done

Used memory blocks:
   Code      :  Start = 0x0000, End = 0x0002, Length = 0x0003

Assembly complete with no errors.
Segment usage:
   Code      :         3 words (6 bytes)
   Data      :         0 bytes
   EEPROM    :         0 bytes
$ ls -l
итого 16
-rw-rw----+ 1 maisvendoo users 92 июл 29 15:46 test.S
-rw-rw----+ 1 maisvendoo users  0 июл 29 15:55 test.S.cof
-rw-rw----+ 1 maisvendoo users 13 июл 29 15:55 test.S.eep.hex
-rw-rw----+ 1 maisvendoo users 55 июл 29 15:55 test.S.hex
-rw-rw----+ 1 maisvendoo users 61 июл 29 15:55 test.S.obj

Содержимое hex-файла
:020000020000FC
:060000000AE00395FECFAB
:00000001FF

Листинг генерируется дополнительным ключем -l при сборке
$ cat test.lst

AVRA Ver. 1.3.0 test.S Sat Jul 29 16:02:05 2017

.device atmega16

.dseg

.cseg
.org 0x0000

C:000000 e00a ldi r16, 10
M1:
C:000001 9503 inc r16
C:000002 cffe rjmp M1

.eseg

Segment usage:
Code : 3 words (6 bytes)
Data : 0 bytes
EEPROM : 0 bytes

Assembly completed with no errors.



Анализируя результаты можно сказать, что:
  1. Генерируется файл в формате Intel HEX, пригодный сразу для прошивки в МК
  2. Синтаксис совместим с Atmel

Определенно в синтаксисе avra есть отличия, например
        .device atmel16

дает указание на МК, скрывая от программиста явное указание ссылок на *.inc файл макроопределений. Существует и ряд других нюансов, о которых проще прочесть в документации или в хорошей обзорной статье Valber’а на русском языке. Об особенностях gavrasm можно почитать тут.

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

Debugging support AVRA creates a coff file everytime the assembly was sucessful. This file allows AVR Studio or any coff compatible debugger to simulate or emulate the program.

но *.cof файл в выхлопе неизменно оказывается пустым. Отсутствие отладочной информации исключает адекватную отладку по шагам, остро необходимую начинающим. Так что от этих (к слову довольно старых альтернатив) переходим к другому, более могучему компилятору из семейства GNU

avr-as


Установка этого инструментария доступна из официальных репозиториев любого достаточно популярного дистрибутива. В случае с Arch Linux
$ sudo pacman -S avr-gcc avr-libc avr-binutils

GNU assembler (gas) является бэкэндом к компилятору gcc и обычно явно не вызывается. Связано это с идеологией *nix систем, ориентированных на разработку на C/C++, в которой ассемблеру отводится роль младшего нелюбимого сына. Вместе с тем это обеспечивает глубокую интеграцию ассемблерного кода в программы на C/C++ что, редко, но бывает необходимо. К тому же, если говорить об архитектурах x86/x86_64 синтаксис «гнутого» ассемблера (AT&T) разительно отличается от принятой Intel-нотации (хотя на gas можно использовать и интел-синтаксис, компилятор дает такую возможность). Чего стоит обратный по отношению к интел-нотации порядок операндов в командах, например

Применительно к AVR gas не отходит от нотации Atmel в части оформления команд — порядок операнд здесь привычный, например команда:

ldi r16, 10

в gas для AVR выглядит привычно. Другое дело макросы и директивы компилятора, они отличаются от Atmel. Приведенная выше тестовая программа будет выглядеть так:

test.S

#include	"/usr/avr/include/avr/io.h"	

/* Секция данных */
	.data

/* Секция кода */
	.section .text

	.org 0x0000

/* Точка входа, обязательная при вызове avr-gcc вместо avr-as */
	.global main

main:

	ldi r16, 10
M1:
	inc r16
	rjmp M1

Как видно из исходника секция кода определяется директивой предпроцессора .section .text (аналог .cseg). Аналогом .dseg служит .data. Единственное, чего я пока не понял и не узрел в документации, как определяется содержимое EEPROM (аналог .eseg). Надеюсь среди читателей найдется добрый гуру, который натолкнет меня на ответ. Новичкам же, подобным мне, советую покурить документацию тут и вот здесь для уяснения специфики использования gas для AVR.

Мы же теперь соберем hex-файл, пригодный для прошивки МК. Команда:

$ avr-as -mmcu=atmega16 -o test.o test.S

генерирует объектный файл для соответствующего контроллера (в нашем случае ATMega 16). Далее данный объектный файл преобразуется в hex
$ avr-objcopy -O ihex test.o test.hex

Получая на выходе hex-файл вида

test.hex
:060000000AE00395FECFAB
:00000001FF

Тем не менее, мы не ответили на главный вопрос и не обозначили преимущество gas по возможности организации пошаговой отладки. Для этого прежде всего


В линуксах нет достойной альтернативы GDB. Для его использования применительно к МК AVR ставим фронтэнд
$ sudo pacman -S avr-gdb

Данный отладчик обладает всем комплексом противоречий, пугающих новичков: при справедливо заявленной термоядерной мощи порог вхождения его довольно высок. Чтобы разучиться боятся gdb и начать в нем работать очень рекомендую статью величайшего и могучего и, к сожалению, ныне покойного (земля тебе пухом, Мыщъх!) Николая Лихачева aka Крис Касперски «Погружение в технику и философию GDB».

Первое, что нужно для использования gdb — собрать код соответствующим образом, сгенерировав ELF-образ, содержащий отладочные символы

$ avr-as -mmcu=atmega16 -g --gstabs -o test.o test.S

Ключи -g и —gstabs генерируют соответственно отладочные символы и добавляют возможность использовать образ для удаленной отладки в gdb. Компонуем полученный объектный файл в ELF

$ avr-ld -m avr4 -o test.elf test.o

Полученный образ мы используем для отладки нашего теста. Из него же можно сгенерировать и hex-файл

$ avr-objcopy -j .text -j .data -O ihex test.elf test.hex

явно указывая ключем -j включаемые в прошивку секции, ключем -O ihex формат вывода (intel HEX). Получаем тот же файл, что и в предыдущем случае:

test.hex
:060000000AE00395FECFAB
:00000001FF

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


Этот вопрос сложнее прочих. Мною было найдено два достойных кандидата: simavr, имеющийся в официальных репозиториях арча и устанавливаемый простым:
$ sudo pacman -S simavr

и более популярный симулятор simulavr, который не был найден даже в AUR, при том что основная масса полезной инфы в сети именно о нем. Собрать из исходников с целью создания PKGBUILD для AUR у меня не вышло, хотя я перебрал все адекватные ветки в официальном репозитории. Пришлось прибить зверский костыль, скачав DEB-пакет для Debian, превратив его в пакет для арча с помощью утилиты debtap.
 $ debtap simulavr_0.1.2.2-7+b2_amd64.deb

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

Версия эта довольно древняя, а текущий релиз (судя по дате последнего коммита в репозитории) ушел довольно далеко.

Что же касается simavr, то он ставится без проблем, поддерживает большее число МК, но на попытки подключения к нему отладчиком выдает в консоль сообщения о крэше эмулятора и разобраться с этим мне пока не удалось. Тут я снова апеллирую к сведующему в вопросе читателю и рассчитываю на подсказку.

Пока же мы используем для отладки костыльно поставленный simulavr


Итак, сначала отладим программу хардкорно — из консоли запустим эмулятор
$ simulavr -d atmega16 -c 8000000 -g -P simulavr-disp

запускаем эмулятор ATMega 16 (ключ -d) на частоте 8 МГц (ключ -с) с опцией удаленной отладки и возможность красивого просмотра регистров контроллера (опция -P, которая по данным из сети в свежайшей версии эмулятора убрана). Видим окошко терминала с содержимым регистров и памяти

наблюдаем в консоли запуска сообщение

Waiting on port 1212 for gdb client to connect...

сообщающее нам о том, что эмулятор ждет подключения отладчика на порту 1212 (порт можно указать при запуске ключем -p). В другой консоли стартуем отладчик:
$ avr-gdb -q -tui

первый ключ уберет пафосный выхлоп gdb при запуске, вторая группа ключей активирует просмотр исходников в процессе отладки в применена мной для наглядности (на деле эта опция неудобна по ряду причин). В консоли мы увидим следующее:

Подлючаемся к эмулятору

(gdb) target remote:1212

Загружаем ELF-образ в эмулятор (да, именно его а не hex, на чем я обжегся в самом начале) d ‘vekznjh
(gdb) load test.elf

Загружаем отладочные символы:
(gdb) file test.elf

ответив «yes» на заданный вопрос, получая следующую картину:

Что же, мы видим наш исходник и отладчик, готовый к приему команд. Даем команду next

(gdb) n

и видим как отладчик бодро переместился по коду.

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

так и в окне отладчика:

(gdb) info registers
.
.
.
r16            0xa      10
.
.
.
SREG           0x0      0
SP             0x0      0x0 <main>
PC2            0x2      2
pc             0x2      0x2 <M1>

С этого момента нам доступен весь богатейший инструментарий, предоставляемый отладчиком gdb. Однако, что линуксоиду хорошо то виндузятнику смерть меня упрекнут мол «чувак, в Atmel Studio есть нормальная отладка с отображением исходников, перемещением по коду хоткеями и просмотром значений вразумительным графическим способом» и будут правы, поэтому попытаемся хотя бы частично решить проблему дружественности отладки, совместив её с разработкой
IDE Eclipse известна давно. За время своего существования она прочно утвердилась в разных областях разработки ПО и может «тупо всё», благодаря обширному набору плагинов, расширяющих её функциональность. В свое время я восторгался ей, но время это прошло, так как в обыденной работе у неё есть масса мелких нюансов, раздувающихся в недостатки (на работе в продакшене я предпочел для того же C/C++ QtCreator в силу специфики деятельности, о чем не жалею).

Тем не менее, с точки зрения решаемой нами задачи она вполне удовлетворяет её требованиям. Для работы с AVR в Eclipse потребуется установка следующих плагинов

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

Eclipse по своей сути ориентирован на C/C++ разработку, поэтому для создания ассемблерного проекта воспользуемся генерацией проекта через имеющийся Makefile, который и напишем для нашего теста. Вот он

Makefile

# Декларируем необходимые переменные
DEVICE = atmega16
TARGET = test
OBJECTS = $(TARGET).o
ELF = $(TARGET).elf
HEX = $(TARGET).hex

# Задаем правила компиляции
COMPILE = avr-as -mmcu=$(DEVICE) -g --gstabs

# Главная цель - HEX-файл прошивки
all:	hex

# Правило сборки объекрных молулей: беруться все исходники 
# с расширением *.S и компилятся в объектные модули *.o
.S.o:
           $(COMPILE) -c $< -o $@
	
# Правило очитски - удаляем все продукты сборки
clean:
           rm -f $(HEX) $(ELF) $(OBJECTS)
	
# Компоновка всех объектных модулей в ELF
elf:   $(OBJECTS)
        avr-ld -m avr4 -o $(ELF) $(OBJECTS)

# Преобразование ELF в HEX
hex: elf
        avr-objcopy -j .text -j .data -O ihex $(ELF) $(HEX)

Написав этот опус открываем Eclipse и создаем новый проект File -> New -> Project, выбирая сишный проект на основе Makefile

жмем Next, в следующем окне выбирая расположение каталога с исходниками и Makefile

Шлепаем Finish и видим наш проект во всей красе

Идем в меню Project -> Build all и получаем все необходимые нам бинарники:

19:34:51 **** Build of configuration Default for project test ****
make all 
avr-as -mmcu=atmega16 -g --gstabs -c test.S -o test.o
avr-ld -m avr4 -o test.elf test.o
avr-objcopy -j .text -j .data -O ihex test.elf test.hex

19:34:51 Build Finished (took 128ms)

Теперь настроим запуск эмулятора, как внешнего инструмента проекта зайдя в Run -> External Tools, создав новую конфигурацию с настройками соответствующими приведенным скринам

Тут мы сообщаем среде, что хотим запускать эмулятор с нужными нам параметрами командной строки, поместив пункт запуска в меню Run → External Tools.

Применяем настройки, идем в меню Run → External Tools → atmega16 и наблюдаем запуск эмулятора:

Хорошо, теперь настроим конфигурацию отладки нашего проекта. Идем в меню Run → Debug Configuratuions и настраиваем аппаратную отладку через GDB.

не забывая указать тип соединения с сервером симуляции:

и указав, какие действия следует выполнить при запуске отладки:

Обязательно ставим галки на Load image и Load Symbols — это позволяет отладчику загрузить прошивку в эмулятор и прочесть отладочные символы. Ставим точку останова на метку M1.

Жмем кнопки Apply и Debug и… вуаля!

Отладчик послушно стал на указанной точке останова. Доступен просмотр дампа памяти и содержимого регистров. Жмем F5 (или F6) и трассируем наш код по шагам.

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


Что хочу сказать в финале? Я уже тысячу раз говорил о том, что все мои статьи на ресурсах хабр и гиктаймс — отражение личного опыта и рупор субъективного мнения. Решена задача — организация разработки ПО для контроллеров AVR в среде Linux. Эта статья — продукт долгого гугления и сбора информации из разрозненных сетевых источников. Цель её — натолкнуть новичка на поиск в нужном направлении. Статья не претендует на академичность, она лишь продукт моих собственных копаний и попытка поделится собранной информацией, а так же привлечь заинтересованных людей к интересной мне теме.

Тут много о чем не сказано, например о прошивке через avrdude, который (sic!) есть кроссплатформенная утилита прошивки для семейства AVR. Если у читателей будет желание, а у меня возможность, мы рассмотрим и её, помигаем светодиодами, пошлем слово «жопа» «счастье» через USART и так далее. Тема неисчерпаема и достойна продолжения. Время покажет.

А пока, благодарю моего читателя за внимание и надеюсь на новую встречу!

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

 image001

У порта 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; и, когда мы запустим отладку, то отладчик, как только увидит данную точку, должен будет в этом месте остановить выполнение программы, и мы сможем посмотреть, какие уровни и где у нас установились.

002

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

003

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

004

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

 005

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

006

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

007

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

PORTD = 0b00000001;

PORTD = 0b00000010;

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

008

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

009

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

010

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

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

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

011

 

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

 

Исходный код

 

 

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

 

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

 

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

 

Post Views: 28 580

Проект электронной машины для голосования (EVM) на базе микроконтроллера

AVR с принципиальной схемой и кодом

Всякий раз, когда мы идем голосовать на выборах, мы видим электронные машины для голосования. В этом проекте мы собираемся спроектировать и разработать простую машину для голосования с использованием микроконтроллера ATmega32A . Хотя мы можем использовать контроллер, чтобы получить машину для голосования более 32 человек, для простоты мы собираемся сделать систему голосования для четырех человек. У нас будет четыре кнопки для четырех человек, и при каждом нажатии кнопки будет Голосование идет за соответствующего человека, и количество голосов, поданных каждым человеком, отображается на ЖК-дисплее.

Необходимые компоненты

Оборудование:

АТМЕГА32

Блок питания (5в)

ПРОГРАММАТОР AVR-ISP

JHD_162ALCD (ЖК-дисплей 16×2)

Конденсатор 100 нФ (пять штук), конденсатор 100 мкФ (подключен к источнику питания)

кнопка (пять штук),

резистор 10КОм (пять штук).

Программное обеспечение:

Атмель студия 6.1

прогисп или флеш магия.

Принципиальная схема и рабочее пояснение

Electronic Voting Machine Circuit Diagram

Как показано на приведенной выше схеме электронного устройства для голосования , PORTA микроконтроллера ATMEGA32 подключается к порту данных ЖК-дисплея 16×2. Здесь следует не забыть отключить связь JTAG в PORTC ATMEGA, изменив байты предохранителя, если кто-то хочет использовать PORTC в качестве обычного порта связи. В ЖК-дисплее 16×2 всего 16 контактов, если есть подсветка, если нет подсветки, будет 14 контактов.Можно включить или оставить контакты подсветки. Теперь в 14 контактах 8 контактов данных (7-14 или D0-D7), 2 контакта источника питания (1 и 2 или VSS & VDD или gnd & + 5v), 3 контакта rd для контроля контрастности (VEE-контролирует толщину символов. должен быть показан), 3 контакта управления (RS, RW и E).

В схеме вы можете заметить, что я взял только два управляющих контакта, поскольку это дает гибкость для лучшего понимания. Бит контраста и READ / WRITE используются нечасто, поэтому их можно замкнуть на массу.Это переводит ЖК-дисплей в режим максимальной контрастности и чтения. Нам просто нужно управлять контактами ENABLE и RS, чтобы отправлять символы и данные соответственно.

Подключения, которые выполняются для ЖК-дисплея, приведены ниже:

PIN1 или VSS — земля

PIN2 или VDD или VCC — питание +5 В

PIN3 или VEE — заземление (дает максимальный контраст лучше всего для новичков)

PIN4 или RS (выбор регистра) — PD6 uC

PIN5 или RW (чтение / запись) — земля (переводит ЖК-дисплей в режим чтения, что упрощает обмен данными для пользователя)

PIN6 или E (включить) — PD5 uC

PIN7 или D0 — PA0 из uC

PIN8 или D1 — PA1 из uC

PIN9 или D2 — PA2 из uC

PIN10 или D3 — PA3 из uC

PIN11 или D4 — PA4 из uC

PIN12 или D5 — PA5 из uC

PIN13 или D6 — PA6 из uC

PIN14 или D7 — PA7 из ОК

В схеме вы можете видеть, что мы использовали 8-битную связь (D0-D7), однако это не обязательно.Мы можем использовать 4-битную связь (D4-D7), но с 4-битной коммуникацией программа становится немного сложной, поэтому я просто выбрал 8-битную связь.

Итак, просто наблюдая за таблицей выше, мы подключаем 10 контактов ЖК-дисплея к контроллеру, в котором 8 контактов являются контактами данных и 2 контакта для управления. Здесь присутствуют пять кнопок, четыре для увеличения голосов кандидатов и пятая для обнуления голосов кандидата.

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

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

Когда кнопка, представляющая соответствующего человека, нажата, контроллер выбирает ее и увеличивает соответствующий номер человека в своей памяти, после того, как приращение показывает соответствующее количество людей на ЖК-дисплее 16×2.

Принцип работы устройства для электронного голосования на базе микроконтроллера объясняется шаг за шагом кода C ниже,

,

ср. 8- RISC AVR

:

:


(SREG)
SREG :
К :
Z :
N :
В :
S : NV,
H :
Т :, BLD BST
I :/
Rd : ()
Rr :
R :
К : (8)
к :
b : В / В (3)
с : (3)
X, Y, Z : (X = R27: R26, Y = R29: R28, Z = R31: R30)
п. : ввода / вывода
q : (6)
ввод / вывод
RAMPX, RAMPY, RAMPZ : X, Y Z, 64
:
СТЕК :
СП :
:
,
0 :
1 :
:,



— — DOC — — — — — — —
.Программирование АРН

01: Введение | Hackaday

Нам нравится смотреть на хардкорные проекты электроники с мощным микроконтроллером и сотнями, если не тысячами, строк кода в его центре. Но всем нужно как-то туда попасть.

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

План развития серии

:

Необходимые знания

Хорошие новости: я установил довольно низкую планку. Вам необходимы базовые знания по установке программ на ваш компьютер и их использованию. Вы должны иметь некоторое представление о том, как работает беспаечная макетная плата, и желательно иметь мультиметр и знать, как с его помощью измерять напряжение. И не бойтесь использовать Google для исследования вопросов, на которые здесь нет прямого ответа.

Что на самом деле делает микроконтроллер?

Это загруженный вопрос.Для понимания я свожу это к самому простому объяснению:

  1. Микроконтроллер принимает какой-то ввод
  2. Он принимает решение на основе написанного вами программного обеспечения
  3. Выходы изменяются на основе решения на шаге 2.

Микроконтроллер делает то, что вы его запрограммировали. Делает это быстро и надежно.

Как это работает?

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

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

Посмотрите на сам чип

Я решил использовать микроконтроллер ATmega168. Это мощный чип, но его не сложнее использовать, чем его младшие собратья. Это даст вам много возможностей для развития ваших проектов, оставаясь при этом доступным (менее 4,50 долларов США). Вот схема:

Это часто называют распиновкой, поскольку она показывает, что на самом деле делает каждый из 28 контактов на микросхеме. Все эти контакты выполняют несколько функций, поэтому рядом с каждой из них есть длинные строки текста, за исключением пяти, у которых есть только одно имя.Это контакты, связанные с напряжением и землей (VCC, GND, AVCC, AREF, AGND), важная проблема с микроконтроллерами.

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

Еще раз взгляните на распиновку и найдите контакты, имена которых начинаются с PD. Всего их должно быть восемь, с обозначениями от PD0 до PD 7. Это фантастический пример 8-битной природы этих микросхем. PD обозначает порт D, один из регистров ввода и вывода. Все в этих микросхемах ориентировано на 8 бит. Это последовательность из восьми единиц или нулей в различных комбинациях. Если вы хотите включить или выключить определенные функции, вы меняете один или несколько битов в 8-битном регистре.Каждый раз, когда вы хотите изменить один пин, вы должны адресовать все восемь в регистре. Мы узнаем об этом гораздо больше, но не раньше третьей части серии.

Программирование

ATmega168 — это программируемый микроконтроллер. Но еще лучше, его можно перепрограммировать. Фактически, когда вы работаете над проектом, вы, скорее всего, перепрограммируете его несколько раз в час.

Этот чип имеет ограничение на размер программного пространства в 16 килобайт. В наше время 64-гигабайтных плееров iPod 16 килобайт может показаться ничтожным.Но на самом деле это 16 килобайт машинного кода. Вы можете многое сделать с этим… поверьте мне.

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

Делай домашнее задание

Чтобы подготовиться к оставшейся части этой серии руководств, мне нужно, чтобы вы собрали несколько инструментов. У вас должен быть компьютер какого-то типа, будь то Linux, Mac или ПК с Windows.Это запустит программное обеспечение, которое берет наш код, компилирует его во что-то, что может использовать микроконтроллер, а затем сообщает программисту, как записать его в наш чип.

Составитель

В конечном итоге мы собираемся написать наш собственный код для AVR, который использует архитектуру RISC. Но мы делаем это на компьютере с архитектурой x86. Инструмент, необходимый для этого, называется кросс-компилятором. Это, пожалуй, лучшая причина выбрать AVR для разработки, поскольку существует отличная цепочка инструментов, которую можно легко установить на нескольких платформах.

  • Пользователи Mac: установите CrossPack
  • Пользователи Windows: установите WinAVR
  • Пользователи Linux: Пользователи Debian и Ubuntu должны установить пакет GCC-AVR, который включает всю цепочку инструментов. Другие могут захотеть взглянуть на страницу инструментальной цепочки AVR-libc для помощи в компиляции пакетов.

Это не единственный вариант. Многие пользователи Windows доверяют бесплатному программному обеспечению AVR Studio от Atmel. Это единственный раз, когда я буду ссылаться на него, поскольку у меня нет компьютера с Windows, и я никогда не пробовал этот пакет.

Программное обеспечение для программирования

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

 avrdude -h 

Появится экран справки. Если вы получили сообщение об ошибке, вам следует убедиться, что вы правильно установили набор инструментов на предыдущем шаге, или загрузите AVRdude самостоятельно.

Что ждет в будущем

На этом завершается вводная часть этой серии.

Часть 2: В следующей части этой серии мы рассмотрим несколько аппаратных средств, которые можно использовать для программирования микроконтроллера AVR. Я написал программу hello world и расскажу, как построить схему на макетной плате, подключить микросхему к программатору и использовать AVRdude для записи этой простой прошивки на устройство. Я не хочу вас слишком волновать, но это действительно связано с миганием светодиода.

Часть 3: Предварительно скомпилированный HEX-файл использовался для программирования микроконтроллера AVR во второй части данной серии статей. В этой части мы рассмотрим исходный код языка C, из которого состояла эта прошивка. Я также подробно расскажу о периферийных устройствах, имеющихся в чипе, и подробно расскажу, как их использовать. В завершение мы добавим функциональность к исходной программе, перекомпилируем ее и перепрограммируем чип с обновленной версией.

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

Следуй за мной:

@szczys

,

Начало работы с микроконтроллерами AVR®

Переключить навигацию

  • Инструменты разработки
    • Какие инструменты мне нужны?
    • Программные средства
      • Начни здесь
      • MPLAB® X IDE
        • Начни здесь
        • Установка
        • Введение в среду разработки MPLAB X
        • Переход на MPLAB X IDE
          • Переход с MPLAB IDE v8
          • Переход с Atmel Studio
        • Конфигурация
        • Плагины
        • Пользовательский интерфейс
        • Проектов
        • файлов
        • Редактор
          • Редактор
          • Интерфейс и ярлыки
          • Основные задачи
          • Внешний вид
          • Динамическая обратная связь
          • Навигация
          • Поиск, замена и рефакторинг
          • Инструменты повышения производительности
            • Инструменты повышения производительности
            • Автоматическое форматирование кода
            • Список задач
            • Сравнение файлов (разница)
            • Создать документацию
        • Управление окнами
        • Сочетания клавиш
        • Отладка
        • Контроль версий
        • Автоматизация
          • Язык управления стимулами (SCL)
          • Отладчик командной строки (MDB)
          • Создание сценариев IDE с помощью Groovy
        • Поиск и устранение неисправностей
        • Работа вне MPLAB X IDE
        • Прочие ресурсы
      • MPLAB Xpress
      • MPLAB IPE
      • Программирование на C
      • Компиляторы MPLAB® XC
        • Начни здесь
        • Компилятор MPLAB® XC8
        • Компилятор MPLAB XC16
        • Компилятор MPLAB XC32
        • Компилятор MPLAB XC32 ++
        • Охват кода
        • MPLAB
      • Компилятор IAR C / C ++
      • Конфигуратор кода MPLAB (MCC)
      • Гармония MPLAB v2
      • Гармония MPLAB v3
      • среда разработки Atmel® Studio
      • Atmel СТАРТ (ASF4)
      • Advanced Software Framework v3 (ASF3)
        • Начни здесь
        • ASF3 Учебники
          • ASF Audio Sine Tone Учебное пособие
          • Интерфейс ЖК-дисплея с SAM L22 MCU Учебное пособие
      • Блоки устройств MPLAB® для Simulink®
      • Утилиты
      • Инструменты проектирования
      • FPGA
      • Аналоговый симулятор MPLAB® Mindi ™
    • Аппаратные средства
      • Начни здесь
      • Сравнение аппаратных средств
      • Средства отладки и память устройства
      • Исполнительный отладчик
      • Демо-платы и стартовые наборы
      • Внутрисхемный эмулятор MPLAB® REAL ICE ™
      • Эмулятор SAM-ICE JTAG
      • Внутрисхемный эмулятор
      • Atmel® ICE
      • Power Debugger
      • Внутрисхемный отладчик MPLAB® ICD 3
      • Внутрисхемный отладчик MPLAB® ICD 4
      • Внутрисхемный отладчик
      • PICkit ™ 3
      • Внутрисхемный отладчик MPLAB® PICkit ™ 4
      • MPLAB® Snap
      • MPLAB PM3 Универсальный программатор устройств
      • Принадлежности
        • Заголовки эмуляции и пакеты расширения эмуляции
        • Пакеты расширения процессора и отладочные заголовки
          • Начни здесь
          • Обзор
          • PEP и отладочных заголовков
          • Требуемый список заголовков отладки
            • Таблица обязательных отладочных заголовков
            • AC162050, AC162058
            • AC162052, AC162055, AC162056, AC162057
            • AC162053, AC162054
            • AC162059, AC162070, AC162096
            • AC162060
            • AC162061
            • AC162066
            • AC162083
            • AC244023, AC244024
            • AC244028
            • AC244045
            • AC244051, AC244052, AC244061
            • AC244062
          • Необязательный список заголовков отладки
            • Дополнительный список заголовков отладки — устройства PIC12 / 16
            • Дополнительный список заголовков отладки — устройства PIC18
            • Дополнительный список заголовков отладки — Устройства PIC24
          • Целевые следы заголовка отладки
          • Отладочные подключения заголовков
      • SEGGER J-Link
      • Решения для сетевых инструментов
      • K2L
      • Рекомендации по проектированию средств разработки
      • Ограничения отладки — микроконтроллеры PIC
      • Инженерно-технические примечания (ETN) [[li]] Встраиваемые платформы chipKIT ™
  • Проектов
    • Начни здесь
    • Преобразование мощности
      • AN2039 Четырехканальный силовой секвенсор PIC16F1XXX
    • 8-битные микроконтроллеры PIC®
    • 8-битные микроконтроллеры AVR®
    • 16-битные микроконтроллеры PIC®
    • 32-битные микроконтроллеры SAM
    • 32-разрядные микропроцессоры SAM
      • Разработка приложений SAM MPU с помощью MPLAB X IDE
      • Примеры пакетов программного обеспечения
      • SAM MPU
    • Запланировано дополнительное содержание…
  • Продукты
    • 8-битные микроконтроллеры PIC
    • 8-битные микроконтроллеры AVR
      • Начни здесь
      • Структура 8-битного микроконтроллера AVR®
      • 8-битные периферийные устройства AVR®
        • Осциллятор
        • USART
        • прерываний
        • аналоговый компаратор и опорное напряжение
        • Таймер / счетчики
        • Внутренний датчик температуры
        • Работа с низким энергопотреблением
        • Сброс источников
      • Начало работы с микроконтроллерами AVR®
      • Использование микроконтроллеров AVR® с Atmel START
      • Запланировано дополнительное содержание…
    • 16-битные микроконтроллеры PIC и dsPIC DSC
    • 32-битные микроконтроллеры
      • Начни здесь
      • Выбор 32-битного микроконтроллера
      • микроконтроллеров PIC32M
      • SAM MCU
        • Различия между семействами ARM Cortex
        • Семейные справочные страницы
        • Доступ к регистрам SAM MCU в C
        • SAM D21 Семейное обучение
          • SAM D21 MCU Обзор
          • SAM D21 Примеры кода Листинг
          • Ядро процессора
            • Обзор процессора
            • Системный таймер (SysTick)
            • Контроллер вложенных векторных прерываний (NVIC)
            • Шина ввода-вывода (IOBUS)
            • Блок управления системой (SCB)
            • Микро-трассовый буфер (MTB)
          • Периферийные устройства
            • Система часов
            • Универсальный контроллер тактовой частоты (GCLK)
            • Системный контроллер (SYSCTRL)
            • Высокоскоростной автобус (HPB)
            • Память
            • Мост AHB-APB
            • Внешний контроллер прерываний (EIC)
            • Блок обслуживания устройства (DSU)
            • Менеджер питания (PM)
            • Контроллер периферийного доступа (PAC)
            • Контроллер прямого доступа к памяти (DMAC)
            • Контроллер энергонезависимой памяти (NVMCTRL)
            • Сторожевой таймер (WDT)
            • Часы реального времени (RTC)
            • Таймер / счетчик (TC)
            • Цифро-аналоговый преобразователь (ЦАП)
            • Аналоговый компаратор (переменного тока)
            • Периферийный сенсорный контроллер (PTC)
            • Система событий (EVSYS)
            • Универсальная последовательная шина (USB)
            • Последовательная связь (SERCOM SPI Master)
            • Последовательная связь (SERCOM I²C Slave)
            • Звуковой контроллер
            • Inter-IC (I²S ™)
        • SAM C21 Семейное обучение
        • SAM L10 Семейное обучение
.

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

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