.cseg
.org 0
rjmp initial
.......
.org 0x20
initial: ldi temp,low(RAMEND)
out SPL,
ldi temp,high(RAMEND)
out SPH,
cbi PORTB,LED
sbi DDRB,LED
.......
-------------------------------------------------------------------------
------------------------------------
-------------------------------------------------------------------------
------------------------------------
Память
Примечания.
1. Не во всех моделях ATtiny и только из области загрузчика.
2. Доступны не все FUSE-биты.
3. Только в режиме отладки.
Тип памяти
Прикладная программа
Последовательное
программирование при низком напряжении
Параллельное и последовательное
программирование при высоком напряжении
Интерфейс JTAG
Интерфейс debugWire
Чтение
Запись
Чтение
Запись
Чтение
Запись
Чтение
Запись
Чтение
Запись
FLASH
+ (1)
+
+
SRAM
+(3)
+(3)
EEPROM
+
+
Конфигурационные ячейки
+(1)
+(2)
+(2)
Ячейки защиты
+(1)
+
+
+(2)
+(2)
Калибровочные
ячейки и ячейки идентификатора
-
Память программ FLASH
-------------------------------------------------------------------------
------------------
Линейная память данных AVR разбита на три отдельные части, как показано
на рис.6. Это регистры общего назначения (РОН) или GPR (General Purpose
Registers), регистры ввода-вывода (РВВ) или IO (Input-Output Registers) и
ОЗУ микроконтроллера. РОН и РВВ, кроме этого имеют индивидуальный
диапазон адресов (собственное адресное пространство), который могут
использовать только команды определенного типа.
-------------------------------------------------------------------------
-----
eeprom_write:
sbic EECR,EEWE ;ожидаем пока запись не будет закончена
rjmp eeprom_write;предыдущая операция записи в EEPROM
out EEARH,R18 ;задаем адрес ячейки EEPROM, в которую
out EEARL,R17 ;необходимо записать байт данных
out EEDR,R16 ;заносим в регистр данных байт для записи
sbi EECR,EEMWE ;разрешаем запись
sbi EECR,EEWE ;начинаем запись байта в EEPROM
ret
eeprom_read:
sbic EECR,EEWE ;ожидаем пока запись не будет закончена
rjmp eeprom_write;предыдущая операция записи в EEPROM
out EEARH,R18 ;задаем адрес ячейки EEPROM, из которую
out EEARL,R17 ;необходимо прочитать байт данных
sbi EECR,EERE ;начинаем чтение байта из EEPROM
in R16,EEDR ;извлекаем байт из регистра данных
ret
-------------------------------------------------------------------------
---------------------------
Конфигурационные ячейки
Номер
бита
Название
Заводское значение
Назначение
CKSEL0
CKSEL1
CKSEL2
CKSEL3
SUT0
5
SUT1
BODEN
BODLEVEL
Задает порог срабатывания схемы BOD. При BODEN=1 значения этого бита
игнорируются. Заводское значение BODLEVEL=1 устанавливает порог
срабатывания 4.0 В.
BOOTRST
BOOTSZ0
2
BOOTSZ1
EESAVE
CKOPT
SPIEN
WDTON
RSTDISBL
1
-------------------------------------------------------------------------
------------------------
Ячейки защиты
Ячейки бывают двух типов. К первому из них относятся биты LB1, LB2,
которые имеются во всех без исключения AVR- микроконтроллерах. Их
комбинация определяет степень доступа к памяти FLAS и EEPROM в
соответствии с табл.3.
Ячейки защиты
Описание
LB1
LB2
Ячейки второго типа содержаться только в тех моделях AVR, которые имеют
возможность самопрограммирования. Одна пара этих ячеек BLB02, BLB01
определяет режим защиты прикладной программы, а вторая пара BLB12, BLB11
– режим защиты секции загрузчика. Эти биты накладывают определенные
ограничения на функционирование инструкций lpm/spm и не имеют слишком
большого практического значения.
-------------------------------------------------------------------------
------------------------
-------------------------------------------------------------------------
-------------------
Арифметико-логическое устройство
Арифметико-логическое устройство
Рис.8 Арифметико-логическое устройство
Таким образом, сложить любые два регистра можно двумя разными способами:
add R16,R17 (сложить R16 с R17 и поместить сумму в R16) или add R17,R16
(сложить R17 с R16 и поместить сумму в R17). Причем выборка содержимого
регистров, сложение и сохранение результата займет всего 1 период
тактовой частоты.
Номер бита
в регистре
Название флага
Описание
N
Флаг отрицательного результата. В этот флаг копируется содержимое 7-мого
MSB результата операции.
Стек
.include "m8def.inc"
Стек AVR, помимо сохранения адресов возврата, имеет еще одно очень важное
предназначение. Он позволяет сохранять любые данные специально
предназначенными для этого командами push Rr (загрузка в стек) и pop Rd
(выгрузка из стека). Каждый раз при выполнении push Rr содержимое Rr
копируется в стек, после чего SP уменьшается на единицу. При выполнении
pop Rr содержимое ячейки стека, на которую указывает SP,
восстанавливается в Rr, а само значение SP инкрементируется. Стек
подобного рода имеет организацию Last In First Out (Первый Вошел
Последний Вышел): регистр, сохраненный последней командой push, будет
восстановлен первой командой pop:
; SP Уровень стека
после команды
-------------------------------------------------------------------------
---------------------------
Прерывания
Номер
Флаг прерывания
Описание события
0x0001
INT0 из GICR
INTF0 из GIFR
Внешнее прерывание 0
0x0002
INT1 из GICR
INTF1 из GIFR
Внешнее прерывание 1
3
0x0003
OCIE2 из TIMSK
OCF2 из TIFR
0x0004
TOIE2 из TIMSK
TOV2 из TIFR
Переполнение TCNT2
0x0005
TICIE1 из TIMSK
ICF1 из TIFR
Захват в ICP1
0x0006
OCIE1A из TIMSK
OCF1A из TIFR
0x0007
OCIE1B из TIMSK
OCF1B из TIFR
0x0008
TOIE1 из TIMSK
TOV1 из TIFR
Переполнение TCNT1
0x0009
TOIE2 из TIMSK
TOV2 из TIFR
Переполнение TCNT0
10
0x000A
SPIE из SPCR
SPIF из SPSR
11
0x000B
RXCIE из UCSRB
RXC из UCSRA
0x000C
UDRIE из UCSRB
UDRE из UCSRA
13
0x000D
TXCIE из UCSRB
TXC из UCSRA
14
0x000E
ADIE из ADCSRA
ADIF из ADCSRA
Прерывание от АЦП
15
0x000F
EERIE из EECR
EEMWE из EECR
16
0x0010
ACIE из ACSR
ACI из ACSR
Прерывание от компаратора
17
0x0011
TWIE из TWCR
TWINT из TWCR
18
0x0012
SPMIE из SPMCR
SPMIE из SPMEN
.cseg
.org 0 ;начало с нулевого адреса памяти программ
main:
ldi R16,low(RAMEND) ;инициализируем указатель стека
out SPL,R16
ldi R16,high(RAMEND)
out SPH,R16
sbi PORTD,PD2 ;настраиваем на ввод линию 2 порта D
(альтернативная
sbi DDRD,PD2 ;функция INT0) и подключаем к ней внутренний
резистор
ldi R16,1«ISC01 ;задаем условием прерывания изменения
out MCUCR,R16 ;состояния вывода INT0 с лог.1 на лог.0
ldi R16,1«INT0 ;разрешаем прерывание INT0
out GICR,R16
sei ;разрешаем прерывания глобально (I=1)
.
service_INT0:
push R16 ;сохраняем в стеке R16
in R16,SREG
push R16 ;сохраняем в стеке SREG
.
pop R16 ;восстанавливаем из стека SREG
out SREG,R16
pop R16 ;восстанавливаем из стека R16
reti
service_INT0:
push R16 ;сохраняем в стеке R16
in R16,SREG
push R16 ;сохраняем в стеке SREG
sei ;разрешаем прерывания во время обработчика
.
pop R16 ;восстанавливаем из стека SREG
out SREG,R16
pop R16 ;восстанавливаем из стека R16
reti
-------------------------------------------------------------------------
-----
Порты ввода-вывода
-------------------------------------------------------------------------
-------
Система команд
Команды данного типа содержат адреса двух РОН, один из которых является
источником, а другой приемником результата в арифметических операциях, а
также операциях пересылки. Примеры команд: mov Rd, Rr, add Rd, Rr, sub
Rd, Rr, and Rd,Rr и т.д. Адреса обоих регистров лежат в пределах 0…31, но
в некоторых командах умножения могут использоваться только РОНы 16…31
(muls Rd,Rr и fmuls Rd,Rr) или 16…23 (mulsu Rd,Rr и fmulsu Rd,Rr).
Прямая адресация ОЗУ встречается в командах lds Rd,k и sts k,Rr. Первая
инструкция пересылает байта из SRAM микроконтроллера в один из РОНов,
вторая копирует содержимое РОНа в ячейку SRAM. В обеих командах под поле
адреса ячейки памяти отводится 16 битов, а значит, имеется возможность
напрямую обращаться к любому адресу SRAM из диапазона 0…65535. Инструкции
работают со всеми РОНами 0…31 и имеют размер в 2 слова (4 байта).
Разновидности косвенной адресации
-------------------------------------------------------------------------
---------------------
key_press:
adiw R24,1 ; инкрементируем счётчик R25:R24
sbis PINB,0 ; пока на линии 0 порта PORTB низкий
rjmp key_press ; логический уровень
Имеется две команды с прямой адресацией РОН: sub Rd,Rr (Вычитание двух
регистров), sbc Rd,Rr (Вычитание двух регистров с учётом заема). При
совместном использовании они позволяют получить разность чисел любой
разрядности. Для связи байт, при этом, и здесь служит флаг C. Но в
отличие от сложения он устанавливается, когда разность оказалась
отрицательной(Rd < Rr) и имеет в этом случае смысл заема, который должен
быть вычтен из разности старших байт командой sbc Rd,Rr:
delay:
sbiw R24,1 ; декрементируем счётчик R25:R24 пока
brne delay ; его содержимое не станет 0, формируя
. ; задержку времени 4*R25:R24 циклов
Но в отличие от ser R16 или, что тоже самое, ldi R16,0xFF - будут
изменены значения флагов N и Z, что может повлиять на правильный ход
выполнение программы. По той же причине в ряде случаев для обнуления
регистра лучше использовать ldi R16,0 вместо clr R16 (eor R16,R16); все
флаги в регистре SREG останутся неизменными. Единственное, что мешает
повсеместному применению команды ldi Rd,K, это ограниченный набор РОН с
которыми она работает. Только регистры R16…R31 могут использоваться с
этой инструкцией. Это существенное ограничение наложено и на все
арифметические и логические команды, которые используют непосредственную
адресацию (действие над регистром и константой).
У AVR имеются также команды прямого и обратного счёта. Первая из них inc
Rd (Инкремент) увеличивает на единицу содержимое регистра, а вторая dec
Rd (Декремент), соответственно, уменьшает. Конечно, действия
инкрементирования и декрементирования могут быть заменены, например, на
прибавление 1 и вычитание 1 из регистра Rd (subi R16,-1 эквивалентно inc
R16, а subi R16,1 тоже, что и dec Rd). Но, несмотря на это обе команды
имеют большое самостоятельное значение. Главная их особенность в том, что
они не влияют на флаг переноса C и тем самым оптимизированы для
формирования циклов, в которых он может использоваться:
Для умножения целых чисел разработаны три команды: mul Rd,Rr (Умножение
беззнаковых чисел), muls Rd,Rr (Умножение знаковых чисел), mulsu Rd,Rr
(Умножение знакового числа на беззнаковое).
Знаковые числами должны быть представлены в дополнительном коде. При этом
для первых двух команд безразлично на месте каких операндов будут
находиться множитель и множимое. К одному и тому же результату приведут,
например, mul R16,R17 и mul R17,R16 (muls R16,R17 и muls R17,R16). В
случае mulsu Rd,Rr на месте Rd обязательно должно стоять знаковое число.
Помимо флага Z (один из операндов 0), умножение оказывает влияние и на
флаг переноса C. В него заносится старший бит регистра R1. Таким образом,
в командах muls Rd,Rr, mulsu Rd,Rr он фактически является флагом знака и
устанавливается когда произведение отрицательное. Необходимо также
помнить, что инструкция muls Rd, Rr может использоваться только с
регистрами R16…R31. Ещё меньше поддерживает команда mulsu Rd,Rr, только
R16…R23.
-------------------------------------------------------------------------
------------
Для обращения к РВВ служат команды: in Rd,P (Ввод из порта), out P,Rr
(Вывод в порт). Первая считывает значение РВВ в один из РОНов, а вторая
производит пересылку РОН в РВВ.
.org 0x1000
string: .db "Hello World", 0
-------------------------------------------------------------------------
----------------------
.org 0x0200
label:. ;метка в программе по адресу 0x0200
.org 0x0002
rjmp service_INT0 ;вектор внешнего прерывания INT0
.org 0x0100
service_ INT0: ???????? ;обработчик прерывания INT0
reti ;возврат в основную программу
Инструкция cpse Rd,Rr выполняется иначе. Она относится к типу Test and
Skip (Проверка и пропуск). По логике работы команды такого рода выполняют
проверку определённого условия и если оно истинно (в данном случае если
Rd=Rr), то следующая в тексте команда пропускается. При этом все флаги
программы остаются неизменными.
button_press:
sbic PINB,1 ; задержка пока на выводе 1 порта B
rjmp button_press ; не появится низкий уровень
.
В отличии от команд sbrs Rr,b, sbrc Rr,b, которые работают со всеми без
исключения РОН, инструкции sbis P,b, sbic P,b могут использовать только
первые 32 РВВ. Если учесть, что число управляющих РВВ на много больше то,
это довольно существенное ограничение. Конечно те РВВ, доступ к битам
которых наиболее важен, разработчики постарались разместить именно в этой
области. К ним относятся все регистры управления портами A,B,C,D,E,F, а
также ряд других, отвечающих за работу EEPROM, USART, SPI т.д. Во всех
остальных случаях необходимо cкопировать содержимое РВВ в один из РОН и
уже дальше анализировать состояние соответствующего бита. Программное
ожидание сброса бита 2 порта J должно выглядеть следующим образом:
button_press:
lds R16,PINJ ; задержка пока на выводе 2 порта J
sbrc R16,2 ; не появится низкий уровень
rjmp button_press
.
inc_cnt:
adiw R24,1 ; добавление 1 к регистровой паре R25:R24
brcc PC+2 ; и если возникает перенос, то
adiw R26,1 ; увеличение на 1 регистровой пары R27:R26
ret
-------------------------------------------------------------------------
-----------------
Команды данной группы доступны всем без исключения моделям AVR и сведены
в табл.5.
Так или иначе старший бит результата при lsl Rd и младший при lsr Rd
теряется. В тех случаях, когда это недопустимо, необходимо использовать
циклический сдвиг rol Rd (Вращение влево через флаг переноса С) и ror Rd
(Вращение вправо через флаг переноса C). Обе команды функционируют
подобно lsl Rd, lsr Rd, но с одним важным отличием: старший разряд Rd
после команды rol Rd (младший после ror Rd) заносятся во флаг переноса С
из регистра флагов SREG. При этом содержимое самого бита С предварительно
копируется в младший разряд регистра при rol Rd (старший после rol Rd).
Так при циклическом сдвиге того же числа 0b11010111 = 0xD7 влево получим
0b1010111c, а вправо 0bc1101011, где на месте c будет значение C до
выполнения команды. После операции флаг C окажется установленным (у числа
0b11010111 = 0xD7 MSB, MLB = 1). Обратим внимание на то, что вместо lsl
Rd на самом деле выполняется add Rd,Rd, а вместо rol Rd - adс Rd,Rd.
Ещё одна с виду необычная сдвиговая команда asr Rd. (Арифметический сдвиг
вправо) разработана для деления на два знаковых чисел, представленных в
дополнительном коде. В ходе операции все биты регистра сдвигаются на один
разряд вправо (как при lsr Rd), кроме старшего 7-го, который остается
неизменным (MSB является знаком результата и не может изменится при
делении на положительное число 2). Если применить asr Rd к регистру в
котором находится, например, число 0b11010010 = -46, то получим
0b11101001 = -23. Разумеется такое деление будет безошибочным, только для
знаковых 1-байтовых чисел из диапазона -128…127.
-------------------------------------------------------------------------
--------------------
-------------------------------------------------------------------------
---------------
-------------------------------------------------------------------------
-----------------
Синтаксис ассемблера
Исходный текст программы на языке ассемблера может быть создан в любом
текстовом редакторе и должен быть размещен в файлах с расширениями .asm,
.inc или .txt. Удобнее всего для этих целей использовать встроенный в AVR
Studio редактор.
------------------------------------------------------------------
Директивы ассемблера
Директива .include
Синтаксис написания:
.include "{путь к файлу}"
Пример использования:
Директива .exit
Синтаксис написания:
.exit
Пример использования:
Директива .equ
Синтаксис написания:
.equ {символьное имя} = {выражение}
Пример использования:
Директива .set
Синтаксис написания:
.set {символьное имя} = {выражение}
Пример использования:
label:
.db 0xFA, 250, -6, 0b11111010
.dw 0xFADE, 64222, -1314, 0b1111101011011110
.dd 0xFADEEFCA, 4208914378, -86052918
.dq 0xFADEEFCAEFBACDEF, 18077149609196178927, -521103510453211
Директива .byte
Синтаксис написания:
{метка}: .byte {количество резервируемых данных}
Пример использования:
Директива .org
Синтаксис написания:
.org {начальный адрес}
Пример использования:
Директива .listmac
Синтаксис написания:
.listmac
Пример использования:
-------------------------------------------------------------------------
----
-------------------------------------------------------------------------
--------------
Структура программы
11. .cseg
12. .org 0
13. rjmp initial
;0xC01F
14. rjmp 0 ;rjmp service_INT0 ;внешнее прерывание 0
0xCFFE
15. rjmp 0 ;rjmp service_INT1 ;внешнее прерывание 1 0xCFFD
16. rjmp 0 ;rjmp service_OC2 ;совпадение TCNT2 и OCR2
0xCFFC
17. rjmp 0 ;rjmp service_OVF2 ;переполнение TCNT2
0xCFFB
18. rjmp 0 ;rjmp service_ICP1 ;захват в ICP1 0xCFFA
19. rjmp 0 ;rjmp service_OC1A ;совпадение TCNT1 и OCR1A
0xCFF9
20. rjmp 0 ;rjmp service_OC1B ;совпадение TCNT1 и OCR1B
0xCFF8
21. rjmp 0 ;rjmp service_OVF1 ;переполнение TCNT1 0xCFF7
22. rjmp 0 ;rjmp service_OVF0 ;переполнение TCNT0
0xCFF6
23. rjmp 0 ;rjmp service_SPI ;прерывание от модуля SPI
0xCFF5
24. rjmp 0 ;rjmp service_URXC ;получение байта по USART
0xCFF4
25. rjmp 0 ;rjmp service_UDRE ;опустошение UDR в USART
0xCFF3
26. rjmp 0 ;rjmp service_UTXC ;передача байта по USART
0xCFF2
27. rjmp 0 ;rjmp service_ADCC ;прерывание от АЦП
0xCFF1
28. rjmp 0 ;rjmp service_ERDY ;завершение записи в EEPROM
0xCFF0
29. rjmp 0 ;rjmp service_ACI ;прерывание от компаратора
0xCFEF
30. rjmp 0 ;rjmp service_TWI ;прерывание от модуля TWI
0xCFEE
31. rjmp 0 ;rjmp service_SPMR ;завершение выполнения spm
0xCFED
Конечно, адрес в команде может быть указан и явно. В данном примере его
можно задать безошибочно (rjmp 0x20 вместо rjmp initial). Но, это
возможно только потому, что директива .org 0x20 (строка 32) заставляет
компилятор поместить команду в строке 33 по адресу 32-го слова FLASH-
памяти программ. Однако, в большинстве случаев, адрес размещения той или
иной команды заранее неизвестен и, кроме того, он может изменяться по
мере того, как в программу будут вноситься изменения. Именно поэтому
предпочтительней использовать метки. Назначение их адресов производится
автоматически на этапе компиляции. Да и символьные имена меток,
предоставляют об объектах намного больше информации, чем просо какие-то
числа.
-------------------------------------------------------------------------
------------------------------
Макросы
.
add16 XH,XL,0x1234 ;сложение XH:XL с 16-разрядным числом 0x1234
.
Все метки в теле макроса, как, например, метка loop в макросе pulse_low,
являются локальными. Область их видимости ограничена директивами .macro и
.endm. В ассемблере AVR допускается использование макросов в макросе (до
8 уровней вложения).
-------------------------------------------------------------------------
----------
Отладку можно вести как в пошаговом (кнопки Step Into, Step Over, Step
Out), так в автоматическом (Auto Step) или ускоренном (Run) режимах.
Имеется возможность использовать также точки останова. Симулятор,
встречая строку, в которой находится точка останова, принудительно
останавливает свое выполнение, после чего можно детально изучить
содержимое отладочных окон. Управление точками останова производится
кнопками Toggle Brekpoint и Remove all Program Brekpoints. В окне
Disassembler можно видеть соответствующие машинных кодов командам
ассемблера AVR.
-------------------------------------------------------------------------
-------
Структура HEX-файла
:020000020000FC
:100000001FC0FECFFDCFFCCFFBCFFACFF9CFF8CF8B
:10001000F7CFF6CFF5CFF4CFF3CFF2CFF1CFF0CFCC
:06002000EFCFEECFEDCFA3
:100040000FE50DBF04E00EBFC298BA9A04E018B3E2
:10005000102718BB01D0FBCFB3ECA0E51197F1F747
:02006000089501
:00000001FF
NN AAAA CC DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD SS
: 10 0000 00 1FC0FECFFDCFFCCFFBCFFACFF9CFF8CF 8B
10 + 00 + 00 + 00 + 1F + … + CF + F8 + CF + 8B = 0.
------------------------------------