avr assembly basics - el-pths/w GitHub Wiki
Шпаргалка для заданий на контроллерах архитектуры AVR
Контроллеры AVR были разработаны фирмой Atmel в начале 2000х годов и до сих пор активно используются (например в платах Arduino). Для более полного "погружения" в тему мы используем контроллеры собственноручно распаянные на тестовых платах и программируем их непосредственно в процессорных командах (т.н. язык ассемблера)
Назначение выводов тестовой платы
Верхний (короткий) ряд ног используется для соединения с программатором когда нужно "прошить" новую программу.
Нижним рядом ног плата втыкается в обычную "макетную" плату. Порядок ног слева направо:
PB3 PB4 __ GND __ +5V __ PB0 PB1 PB2 __ +9V
Обратите внимание - батарейка для питания контроллера подключается минусом к GND а плюсом к +9V
, в этом случае напряжение от нее проходит через регулятор (стабилитрон) и понижается до 5V
нужных контроллеру. Не подключайте батарейку прямо в +5V
если её напряжение больше!
Общие сведения по структуре контроллера
-
Процессор содержит 32 регистра "общего назначения" которые используются как обычные переменные, их имена от
R0
доR31
. Поскольку они однобайтовые, в них можно записать число от0
до255
. Можно использовать также шестнадцатеричную запись (0x00 .. 0xFF
) или двоичную, особенно при работе с отдельными битами (0b00000000 .. 0b11111111
). -
Для управления устройствами контроллера используются дополнительные 64 ячейки, которые будем называть "управляющие ячейки". Есть две команды
in
иout
позволяющие пересылать значения из обычных регистров в "управляющие". Эти ячейки на самом деле не являются ячейками памяти а непосредственно связаны с выводами контроллера, таймерами, аналого-цифровым преобразователем и т.п. Т.е. запись в такую ячейку вызывает какие-то физические изменения в состоянии чипа. -
Процессор имеет постоянное запоминающее устройство (Flash) объёмом 1 или несколько килобайт, куда записываются команды программы для выполнения. После включения он начинает выполнять их последовательно с нулевого адреса (хотя существуют команды переходов, позволяющие выполнять ветвления и циклы в программе).
Общий вид программы
Программа начинается с нескольких строк не являющихся собственно командами:
.device ATtiny13
Такая строчка указывает компилятору на какой процессор ему следует ориентироваться (например, какие команды он в принципе умеет, сколько у него памяти программ и т.п.)
.equ PORTB = 0x18
.equ DDRB = 0x17
.equ PINB = 0x16
Слово .equ
(сокращение от "equivalence") используется для задания удобных имён каким-нибудь важным константам. В данном случае мы хотим назначить имена трём адресам управляющих ячеек, используемых для непосредственной работы с сигналами на ногах контроллера (см. ниже)
start:
; в начале мы выполняем всякую настройку, например
; настроить ногу PB0 как "выход" (по умолчанию все ноги работают как вход и ничего не выдают)
ldi R16, 0b00000001
out DDRB, R16
loop:
; переключить ногу PB0 в состояние "1" (на ней появится 5 вольт)
ldi R16, 0b00000001
out DDRB, R16
; а теперь переключить её же в состояние "0"
ldi R16, 0b00000000
out DDRB, R16
rjmp loop
Такая примитивная программа будет доходить до rjmp loop
и перескакивать снова на метку loop:
благодаря чему напряжение на ноге PB0 будет
меняться почти миллион раз в секунду. Не очень-то полезно :)
Основные команды
LDI R16, 123
- загрузка числа в регистр. Регистр может быть один из R16..R31, число от 0 до 255.
MOV R5, R16
- копирование из регистра в регистр (из R16 в R5 в данном случае).
ADD R19, R16
- прибавление к первому регистру значения из второго.
SUB R20, R18
- вычитание из первого регистра
SUBI R23, 5
- вычитание из регистра непосредственного значения (числа, а не другого регистра) - если число отрицательное, очевидно будет работать как добавление :)
INC R18
- увеличение регистра на 1, аналогично DEC R25
- уменьшение на единицу
RJMP metka
- прыжок (переход) на команду перед которой стоит указанная метка (с двоеточием)
BRNE metka
- переход, но только в том случае если результат предшествующей арифметической операции не равено 0
(аналог IF...THEN
)
BREQ metka
- наоборот, переход только если результат равен нулю
OUT some_addr, R17
- отправка значения из регистра в управляющую ячейку с таким-то адресом
IN R18, some_addr
- получить значение из управляющей ячейки в регистр