Примеры программ avr ассемблер

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Switch branches/tags
Branches Tags
Could not load branches
Nothing to show
Could not load tags

Nothing to show

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Cancel Create

  • Local
  • Codespaces

HTTPS GitHub CLI
Use Git or checkout with SVN using the web URL.
Work fast with our official CLI. Learn more about the CLI.

Sign In Required

Please sign in to use Codespaces.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching Xcode

If nothing happens, download Xcode and try again.

Лекция 4. Архитектура AVR. Ассемблер

Launching Visual Studio Code

Your codespace will open once ready.

There was a problem preparing your codespace, please try again.

Latest commit

Git stats

Files

Failed to load latest commit information.

Latest commit message
Commit time
November 10, 2020 12:02
April 13, 2021 19:11
December 6, 2020 18:20
March 11, 2021 02:05

November 6, 2020 19:13

README.md

Конспект по AVR ASM

Для удобного просмотра таблицы команд разверните файл

3 вида памяти в AVR:

1) Flash 16-bits — память программ

Не очень много памяти. 0x0000 — 0xFFFF

2) SRAM 8-bits — Static Random access memory

Лучше хранит данные, без необходимости их обновлять. 0x0000 — 0xFFFF

  1. 0x0000 — 0x001F — POH
  2. 0x0020 — 0x005F — I/O (все данные подключенные к процессору, настройки переферии)
  3. 0x0060 — RAMEND — Внутренняя SRAM (хранить что хочется)
  4. RAMEND+1 — 0xFFFF — Внешняя SRAM

Всегда 32 регистра. В каждом по байту.

Адресация:

2-х битные могут объединяться по парам (X, Y, Z):

  1. X — 26, 27
  2. Y — 28, 29
  3. Z — 30, 31

Регистры

Данные между включениями и выключениями

SP (Stack Pointer) — указатель стека, указывает на начало стека. Стек растет в верх, указатель стека вниз. При добавлении элемента указатель стека уменьшается

SPH , SPL – Если у МК больше 256 байт памяти для адресации стека требуется 16 бит

.dseg — Данные после запуска МК

.cseg — Сегмент кода

RESET — Код если МК сломан

SREG — Регистр статуса

Список флагов:

Флаг Расшифровка Описание
C Carry Флаг переноса
Z Zero Флаг нулевого значения
N Negative Флаг отрицательного значения (Старший бит после операции)
V Two’s complement overflow indictor Флаг указатель переполнения (Переполнение перешло в знак)
S Signed Test Флаг для проверок со знаком (S = V xor N)
H Half Carry Флаг полупереноса (Переполнение 4 бита)
T Transfer bit Флаг переноски (Используется как временный флаг)
I Interrupt Enable Flag Флаг разрешения глобального прерывания

AVR Ассемблер. Урок 1. Вводный. AVR Assembler. Lesson 1. Promo.

Синтаксис команд:

Список команд:

Команда Синтаксис Биты команды Операнды Такты Флаги Описание
NOP NOP 0000 0000 | 0000 0000 1 Ничего не делать
MOV MOV Rd, Rr 0010 11rd | dddd rrrr 1 Копировать регистр
LDI LDI Rd, K 1110 KKKK | dddd KKKK 16 1 Загрузить значение в регистр
ADD ADD Rd, Rr 0000 11rd | dddd rrrr 1 H+S+V+N+Z+C+ Сложить без переноса
INC INC Rd 1001 010d | dddd 0011 1 S+V+N+Z+ Инкрементировать
DEC DEC Rd 1001 010d | dddd 1010 1 S+V+N+Z+ Декрементировать
SUB SUB Rd, Rr 0001 10rd | dddd rrrr 1 H+S+V+N+Z+C+ Вычесть без переноса
SUBI SUBI Rd, K 0101 KKKK | dddd KKKK 16 1 H+S+V+N+Z+C+ Вычесть значение из регистра
ADIW ADIW Rdl, K 1001 0110 | KKdd KKKK dl (X, Y, Z), 0 2 S+V+N+Z+C+ Сложить значение с парой регистров (16 бит)
SBIW SBIW RDl, K 1001 0111 | KKdd KKKK dl (X, Y, Z), 0 2 S+V+N+Z+C+ Вычесть значение из пары регистров
ADC ADC Rd, Rr 0001 11rd | dddd rrrr 1 H+S+V+N+Z+C+ Сложение двух регистров и содержимого флага переноса
SBC SBC Rd, Rr 0000 10rd | dddd rrrr 1 H+S+V+N+Z+C+ Вычитание содержимого регистра и содержимого флага переноса (С)
SBCI SBCI Rd, K 0100 KKKK | dddd KKKK 1 H+S+V+N+Z+C+ Вычитание константы и содержимого флага переноса
СOM COM Rd 1001 010d | dddd 0000 1 S+V0N+Z+C1 Перевод в обратный код
NEG NEG Rd 1001 010d | dddd 0001 1 H+S+V+N+Z+C+ Перевод в дополнительный код(Значение 0x80 не изменно)
AND AND Rd, Rr 0010 00rd | dddd rrrr 1 S+V0N+Z+ Логические И между двумя регистрами
ANDI ANDI Rd, K 0111 KKKK | dddd KKKK 16 1 S+V0N+Z+ Логическое И между регистром и значением
OR OR Rd, Rr 0010 10rd | dddd rrrr 1 S+V0N+Z+ Логическое ИЛИ между двумя регистрами
ORI ORI Rd, K 0110 KKKK | dddd KKKK 16 1 S+V0N+Z+ Логическое ИЛИ между ригистром и значением
EOR EOR Rd, Rr 0010 01rd | dddd rrrr 1 S+V0N+Z+ Исключающее ИЛИ между двумя регистрами
LSL LSL Rd 0000 11dd | dddd dddd 1 H+S+V+N+Z+C+ Логический сдвинуть влево (7-й бит выгружается во флаг переноса (C))
LSR LSR Rd 1001 010d | dddd 0110 1 S+V+N0Z+C+ Логически сдвинуть вправо
ROL ROL Rd 0001 11dd | dddd dddd 1 H+S+V+N+Z+C+ Логически сдвинуть влево через перенос (Флаг переноса (С) смещается на место бита 0 регистра Rd. Бит 7 смещается во флаг переноса (С))
ROR ROR Rd 1001 010d | dddd 0111 1 S+V+N+Z+C+ Логически сдвинуть вправо через перенос (Флаг переноса (С) на место 0-го бита, 7-й бит смещается во флаг переноса (С))
ASR ASR Rd 1001 010d | dddd 0101 1 S+V+N+Z+C+ Арифметически сдвинуть вправо (Флаг переноса (С) смещается на место 7-го бита, 0-й бит выгружается во флаг переноса (С))
SEP SEP Rd 1110 1111 | dddd 1111 16 1 Включить все биты регистра
CLR CLR Rd 0010 01dd | dddd dddd 1 S0V0N0Z1 Очистить регистр
RJMP RJMP k 1100 kkkk | kkkk kkkk -2K≤k≤2K 2 Перейти относительно
JMP JMP k 1001 010k | kkkk 110k | kkkk kkkk | kkkk kkkk 3 Перейти абсолютно
BRCC BRCC k 1111 01kk | kkkk k000 -64 1 or 2 Перейти если флаг С очищен
BRCS BRCS k 1111 00kk | kkkk k000 -64 1 or 2 Перейти если флаг С установлен
BRNE BRNE k 1111 01kk | kkkk k001 -64 1 or 2 Перейти если флаг Z очищен
BREQ BREQ k 1111 00kk | kkkk k001 -64 1 or 2 Перейти если флаг Z установлен
CP CP Rd, Rr 0001 01rd | dddd rrrr 1 H+S+V+N+Z+C+ Сравнить без переноса
CPC CPC Rd, Rr 0000 01rd | dddd rrrr 1 H+S+V+N+Z+C+ Сравнить с учетом переноса
CPI CPI Rd, K 0011 KKKK | dddd KKKK 16 1 H+S+V+N+Z+C+ Сравнить с константой
CPSE CPSE Rd, Rr 0001 00rd | dddd rrrr 1or2or3 H+S+V+N+Z+C+ Сравнить и пропустить если равно
OUT OUT P, Rr 1011 1PPr | rrrr PPPP 1 Записать данные из регистра в порт I/O
PUSH PUSH Rd 1001 001d | dddd 1111 2 Загрузить регистр в стек
POP POP Rd 1001 000d | dddd 1111 2 Загрузить значение из стека в регистр
IN IN Rd, P 1011 0PPd | dddd PPPP 1 Загрузить данные из порта I/O в регистр
RCALL RCALL k 1101 kkkk | kkkk kkkk 3 Вызов процедуры находящейся по адресу удаленному от текущему PC на k. Адрес возврата в стеке
CALL CALL k 1001 010k | kkkk 111k | kkkk kkkk kkkk kkkk 4 Вызов процедуры находящейся по адресу k. Адрес возврата в стеке
RET RET 1001 0101 | 0XX0 1000 4 Возвращает из подпрограммы. Адрес возврата берется из стека
STS STS k, Rr 1001 001d | dddd 0000 | kkkk kkkk kkkk kkkk 3 Загрузить значение в SRAM
LDS LDS Rd, k 1001 000d | dddd 0000 | kkkk kkkk kkkk kkkk 3 Выгрузить значение из SRAM
ST ST X(X+)(-X), Rr 1001 001r | rrrr 1100(01)(10) 2 Записать из регистра в SRAM
SEI SEI 1001 0100 | 0111 1000 1 I1 Установить флаг глобального прерывания
CLI CLI 1001 0100 | 1111 1000 1 I0 Очистить флаг глобального прерывания
Читайте также:
Программа которая скрывает файлы и папки

LDI R16, 5 LDI R18, 5 NEG R18 ADD R16, R18 ; 5 + (-5)

  • Swap двух регистров без временного регистра:

A = A xor B B = A xor B A = A xor B

  • Загрузить старшие биты числа 1234 в регистр R28, а в регистр R29 записать младшие биты числа 1234:

Источник: github.com

Теория

Память программ микроконтроллеров AVR, помимо своего прямого предназначения может быть использована для хранения константных данных. Для этого в AVR ассемблере есть специальные директивы .db и .dw. Первая определяет константный байт или несколько байтов, вторая константное слово или несколько слов. (слово — это 2 байта). Для того чтобы указать, что заданные константы расположены во flash памяти микроконтроллера, используется директива .cseg

Пример:

.cseg //эта директива определяет начало сегмента памяти программ
// данные следующие после нее будут размещены во flash

//массив байтов
key1: .db 12,66,7,19,26

//строка
text: .db “hi gringo”

//массив шестнадцатиразрядных слов
key2: .dw 0xff12, 0x0134, 0x3056, 0x01ff

//массив указателей на подпрограммы
func: .dw Led1On, Led1Off, Led2On, Led2Off

С помощью этих директив можно организовывать во flash памяти массивы данных, массивы указателей на подпрограммы, многомерные массивы, а также структуры и массивы структур. Массив — это набор данных одного типа последовательно размещенных в памяти, тогда как структура – это набор данных разного типа. Конечно, тип данных, массив, структура — термины языков высокого уровня, в частности Си. В ассемблере никаких типов данных нет. Просто эту терминологию удобно использовать, чтобы как-то разграничить обычные данные и указатели на подпрограммы.

Память программ микроконтроллеров AVR имеет 16-разрядную организацию. Доступ к данным в памяти программ осуществляется с помощью команды lpm и индексного регистра Z. При этом старшие 15 разрядов содержимого регистра определяют адрес 16-разрядного слова, а младший разряд определяет, какой из байтов слова будет прочитан: 0 – младший байт, 1 – старший байт.

Читайте также:
Лучшие программы для решения уравнений

Пример использования инструкции lpm:

.cseg
key1: .db 12,66,7,19,26


ldi ZH, High(key1<<1) //инициализируем индексный регистр
ldi ZL, Low(key1<<1) //адресом метки key1
lpm r16, Z+ //считываем в r16 первый байт массива – 12
//значение Z увеличивается на единицу
lpm r16, Z //считывем в r16 второй байт массива — 66

Итак, мы можем хранить во flash памяти данные и имеем к ним доступ. Важно четко понимать, как это происходит.

Практика

Я долго думал как изложить этот материал. Привести сначала абстрактный пример, а потом рабочий, как в статье про switch или сразу разбирать что-то конкретное. В конце концов остановился на втором варианте. Сам по себе знаю как трудно пробираться через дебри чужого ассемблерного кода, но что поделать. Напрягитесь и не будете разочарованы.

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

Menu1.asm – главный файл проекта
Menu.asm – файл содержащий обработчик кнопок и таблицы.

Новый проект можно сказать здесь.

Программа, реализующая меню на switch`е, состояла из двух отдельных частей – диспетчера и четырех обработчиков. Диспетчер был построен с помощью инструкции косвенного перехода ijmp. А основу обработчиков составляли ветви switch`а построенные на макросе Case. Ему “передавались” три параметра – текущее состояние(где находимся сейчас), следующее состояние(куда перейти потом), имя подпрограммы. Ветви switch`а были зеркальным отражением таблицы, которую я приводил в предыдущей статье.

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

Таблицы

У нас есть четыре кнопки – Up, Down, Enter, Cancel. Для каждой кнопки во flash памяти микроконтроллера существует своя таблица. Строки таблиц определены с помощью директивы .db и имеют следующую структуру.

(где находимся сейчас)

(куда перейти потом)

.equ End = 255

HUpButton:
.db 1,1, Low(Empty), High(Empty)
.db End

где HUpButton – метка, название таблицы,
Low(Empty) – младший байт указателя на подпрограмму Empty,
High(Empty) – старший байт указателя на подпрограмму Empty,
End – маркер конца таблицы.

Запись вида Low(Empty), High(Empty) довольно неудобна, поэтому я изменил ее с помощью директивы препроцессора define. Благо AVR ассемблер поддерживает такие директивы

#define func(x) Low(x),High(x)

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

#define func(x) Low(x),High(x)
.equ End = 255

HUpButton:
.db 1,1, func(Empty)
.db 2,1, func(lcdSelectLed1)
.db 3,3, func(Empty)
.db 4,3, func(lcdSelectLed1)
.db 5,5, func(Empty)
.db 6,5, func(lcdSelectLed1)
.db End

Довольно наглядная запись. (Кстати, это чистой воды массив Си структур).

Еще во flash памяти микроконтроллера есть массив, в котором содержатся указатели на таблицы кнопок. Он определен с помощью директивы .dw

Handlers:
.dw HUpButton, HDownButton, HEnterButton, HCancelButton

Обработчик

Обработчик имеет следующий вид.

HandlerMenu:
//вычисляем указатель на таблицу
dec r16
clr zl
clr zh
mov zl,R16
lsl zl
subi zl, LOW(-(Handlers <<1))
sbci zh, HIGH(-(Handlers <<1))
lpm R16, Z+
lpm R17, Z
movw ZH:ZL, R17:R16
lsl zl
rol zh

//ищем нужную строку таблицы
lds r19, pCurrentState
CheckState:
lpm r16, z
cp r16, r19
breq ChangeState
cpi r16, End
breq ExitHM
adiw Z, 4
rjmp CheckState

//если нашли – то меняем текущее состояние
//и вызываем подпрограмму
ChangeState:
adiw Z, 1
lpm r16, Z+
sts pCurrentState, r16
lpm R16, Z+
lpm R17, Z
movw ZH:ZL, R17:R16
icall
ExitHM:
ret

Читайте также:
Программа 1с для кадровика как выглядит

Разберем алгоритм его работы

Регистр r16 содержит считанный из ОЗУ номер кнопки. Он помещается туда перед вызовом обработчика HandlerMenu. Номер кнопки используется как смещение для доступа к соответствующему элементу массива Handlers. Кнопки имеют номера от 1 до 4. А смещение имеет диапазон от 0 до 3. (потому что элементы массива нумеруются начиная с нулевого) Итак, мы декрементируем значение r16, очищаем регистровую пару ZH:ZL, загружаем в нее значение r16 и сдвигаем ZL.

dec r16
clr zl
clr zh
mov zl,R16
lsl zl

Теперь нам нужно сложить адрес метки Handlers и смещение. В системе команд микроконтроллера AVR нет команды сложения регистра с константой. Инструкцию adiw не в счет, потому что она не может прибавить к регистру больше 63. Выход из положения следующий. Вычитаем отрицательное значение адреса метки из регистров ZH:ZL.

Минус на минус дает плюс и в итоге получается, что мы на самом деле складываем адрес метки со смещением.

subi zl, LOW(-(Handlers <<1))
sbci zh, HIGH(-(Handlers<<1))

Считываем указатель на нужную таблицу в r16 и r17, копируем в регистровую пару ZH:ZL и сдвигаем влево.

lpm R16, Z+
lpm R17, Z
movw ZH:ZL, R17:R16
lsl zl
rol zh

Понятно? Мы взяли адрес адрес метки Handlers, добавили смещение и считали из памяти программ адрес метки таблицы.
Ок. Теперь переходим к поиску нужной строки таблицы.

Считываем из ОЗУ текущее состояние, а затем в цикле сравниваем его с первым байтом строки таблицы. Если они не равны – проверяем, не дошли ли мы до маркера конца таблицы. Если дошли — выходим из обработчика, если не дошли – прибавляем к регистровой паре ZH:ZL смещение. Здесь то нам и пригодилась команда adiw.

Каждая строка таблицы состоит из четырех байтов, и вся таблица расположена во flash памяти непрерывно. Собственно, поэтому мы и имеем доступ к ее строкам, зная только начальный адрес и значение смещения.

lds r19, pCurrentState
CheckState:
lpm r16, z
cp r16, r19
breq ChangeState
cpi r16, End
breq ExitHM
adiw Z, 4
rjmp CheckState

На метку ChangeState микроконтроллер попадает, если нашел нужную строчку в таблице. Здесь мы считываем второй байт строки, который определяет следующее состояние, и записываем его в ОЗУ по адресу pCurrentState. Далее считываем указатель на подпрограмму (это 3 и 4 байты) и вызываем ее.

ChangeState:
adiw Z, 1
lpm r16, Z+
sts pCurrentState, r16
lpm R16, Z+
lpm R17, Z
movw ZH:ZL, R17:R16
icall

Источник: chipenable.ru

Примеры программ avr ассемблер

симуляция программы микроконтроллера в AVRStudio

Написание макросов в ассемблере

12.02.2011 3 Mins Read

При освоении языка программирования, Ассемблер, в описании инструментов этого языка, упоминается такой элемент, как — Макрос. Зачем он нужен и какая от него польза? Чтобы реально это понять, вероятно, лучше это показать на конкретном примере, конкретной программы.

регистр EEAR с адресом ячейки памяти EEPROM

Работа с энергонезависимой памятью EEPROM

22.03.2010 1 Min Read

Кроме FLASH-памяти программ и оперативной памяти RAM в микроконтроллере есть другой вид памяти — EEPROM. В отличии от RAM-памяти данные…

Регистры и порты микроконтроллера AVR

02.02.2009 1 Min Read

Одним из самых важных аспектов программирования микроконтроллеров является работа с регистрами и портами. У микроконтроллеров серии AVR несколько регистров ввода/вывода…

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

02.02.2009 1 Min Read

Для изучения азов программирования микроконтроллеров AVR на ассемблере AVR Studio необходимо понимать значения ассемблерных мнемоник. В новейших микроконтроллерах AVR семейства…

Пример работы ШИМ и АЦП на ассемблере AVRStudio

02.02.2008 1 Min Read

Простенькая программка иллюстрирует работу ШИМ в режиме Fast PWM таймера Timer1 и АЦП. Написана на ассемблере, компилируется в AVR Studio.…

Моя первая программа на ассемблере

06.01.2008 1 Min Read

Напишем простенькую программку для микроконтроллера. Рассмотрим пример простой программы «мигалка», написанной на ассемблере для микроконтроллера ATtiny2313. Разобравшись с этой программой Вы сможете писать собственные!

Уроки ассемблера для микроконтроллеров AVR

28.12.2007 1 Min Read

Занятия с Радиодедом помогут Вам разобраться с программированием микроконтроллеров AVR на ассемблере. Самоучитель состоит из лекций, читать желательно попорядку. Изложены азы:…

Создание нового проекта в AVR Studio

Создание проекта в AVR Studio

28.12.2007 1 Min Read

Надеюсь, Вы уже установили AVR Studio. Приступим к созданию простенького проекта. Рассмотрим процесс создания, компиляции и симуляции программы для микроконтроллера.

Разделы
  • Полезные советы
  • Программирование микроконтроллеров
  • Проекты на Arduino
  • Схемы на микроконтроллерах

Источник: radioded.ru

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru