avr assembly basics - el-pths/w GitHub Wiki

Шпаргалка для заданий на контроллерах архитектуры AVR

Контроллеры AVR были разработаны фирмой Atmel в начале 2000х годов и до сих пор активно используются (например в платах Arduino). Для более полного "погружения" в тему мы используем контроллеры собственноручно распаянные на тестовых платах и программируем их непосредственно в процессорных командах (т.н. язык ассемблера)

Назначение выводов тестовой платы

Общий вид тестовой платы с ATTiny13a

Верхний (короткий) ряд ног используется для соединения с программатором когда нужно "прошить" новую программу.

Нижним рядом ног плата втыкается в обычную "макетную" плату. Порядок ног слева направо:

PB3 PB4 __ GND __ +5V __ PB0 PB1 PB2 __ +9V

Обратите внимание - батарейка для питания контроллера подключается минусом к GND а плюсом к +9V, в этом случае напряжение от нее проходит через регулятор (стабилитрон) и понижается до 5V нужных контроллеру. Не подключайте батарейку прямо в +5V если её напряжение больше!

Общие сведения по структуре контроллера

  1. Процессор содержит 32 регистра "общего назначения" которые используются как обычные переменные, их имена от R0 до R31. Поскольку они однобайтовые, в них можно записать число от 0 до 255. Можно использовать также шестнадцатеричную запись (0x00 .. 0xFF) или двоичную, особенно при работе с отдельными битами (0b00000000 .. 0b11111111).

  2. Для управления устройствами контроллера используются дополнительные 64 ячейки, которые будем называть "управляющие ячейки". Есть две команды in и out позволяющие пересылать значения из обычных регистров в "управляющие". Эти ячейки на самом деле не являются ячейками памяти а непосредственно связаны с выводами контроллера, таймерами, аналого-цифровым преобразователем и т.п. Т.е. запись в такую ячейку вызывает какие-то физические изменения в состоянии чипа.

  3. Процессор имеет постоянное запоминающее устройство (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 - получить значение из управляющей ячейки в регистр