Site Loader

Как программировать Arduino на ассемблере | by smith_rich

Читаем данные с датчика температуры DHT-11 на «голом» железе Arduino Uno ATmega328p используя только ассемблер

Попробуем на простом примере рассмотреть, как можно “хакнуть” Arduino Uno и начать писать программы в машинных кодах, т.е. на ассемблере для микроконтроллера ATmega328p. На данном микроконтроллере собственно и собрана большая часть недорогих «классических» плат «duino». Данный код также будет работать на практически любой demo плате на ATmega328p и после небольших возможных доработок на любой плате Arduino на Atmel AVR микроконтроллере. В примере я постарался подойти так близко к железу, как это только возможно. Для лучшего понимания того, как работает микроконтроллер не будем использовать какие-либо готовые библиотеки, а уж тем более Arduino IDE. В качестве учебно-тренировочной задачи попробуем сделать самое простое что только возможно — правильно и полезно подергать одной ногой микроконтроллера, ну то есть будем читать данные из датчика температуры и влажности DHT-11.

Arduino очень клевая штука, но многое из того что происходит с микроконтроллером специально спрятано в дебрях библиотек и среды Arduino для того чтобы не пугать новичков. Поигравшись с мигающим светодиодом я захотел понять, как микроконтроллер собственно работает. Помимо утоления чисто познавательного зуда, знание того как работает микроконтроллер и стандартные средства общения микроконтроллера с внешним миром — это называется «периферия», дает преимущество при написании кода как для Arduino так и при написания кода на С/Assembler для микроконтроллеров а также помогает создавать более эффективные программы. Итак, будем делать все наиболее близко к железу, у нас есть: плата совместимая с Arduino Uno, датчик DHT-11, три провода, Atmel Studio и машинные коды.

Для начало подготовим нужное оборудование.

Писать код будем в Atmel Studio 7 — бесплатно скачивается с сайта производителя микроконтроллера — Atmel.

Atmel Studio 7

Весь код запускался на клоне Arduino Uno — у меня это DFRduino Uno от DFRobot, на контроллере ATmega328p работающем на частоте 16 MHz — отличная надежная плата. Каких-либо отличий от стандартного Uno в процессе эксплуатации я не заметил. Похожая чорная плата от DFBobot, только “Mega” отлетала у меня 2 года в качестве управляющего контроллера квадрокоптера — куда ее только не заносило — проблем не было.

DFRduino Uno

Для просмотра сигналов длительностью в микросекунды (а это на минутку 1 миллионная доля секунды), я использовал штуку, которая называется “логический анализатор”. Конкретно, я использовал клон восьмиканального USBEE AX Pro. Как смотреть для отладки такие быстрые процессы без осциллографа или логического анализатора — на самом деле даже не знаю, ничего посоветовать не могу.

Прежде всего я подключил свой клон Uno — как я говорил у меня это DFRduino Uno к Atmel Studio 7 и решил попробовать помигать светодиодиком на ассемблере. Как подключить описанно много где, один из примеров по ссылке в конце. Код пишется прямо в студии, прошивать плату можно через USB порт используя привычные возможности загрузчика Arduino -через AVRDude. Можно шить и через внешний программатор, я пробовал на китайском USBASP, по факту у меня оба способа работали. В обоих случаях надо только правильно настроить прошивальщик AVRDude, пример моих настроек на картинке

Полная строка аргументов:
-C “C:\avrdude\avrdude.conf” -p atmega328p -c arduino -P COM7 115200 -U flash:w:”$(ProjectDir)Debug\$(TargetName).hex:i

В итоге, для простоты я остановился на прошивке через USB порт — это стандартный способ для Arduio. На моей UNO стоит чип ATmega 328P, его и надо указать при создании проекта. Нужно также выбрать порт к которому подключаем Arduino — на моем компьютере это был COM7.

Для того, чтобы просто помигать светодиодом никаких дополнительных подключений не нужно, будем использовать светодиод, размещенный на плате и подключенный к порту Arduino D13 — напомню, что это 5-ая ножка порта «PORTB» контроллера.

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

Для того чтобы увидеть, когда он светится и когда он потушен, мы зажжем светодиод и займем процессор какой-либо бесполезной работой на примерно 1 секунду. Саму задержку можно рассчитать вручную зная частоту — одна команда выполняется за 1 такт или используя специальный калькулятор по ссылки внизу. После установки задержки, код выполняющий примерно то же что делает классический «Blink» Arduino может выглядеть примерно так:

еще раз — на моей плате светодиод Arduino (D13) сидит на 5 ноге порта PORTB ATmeg-и.

Но на самом деле так писать не очень хорошо, поскольку мы полностью похерили такие важные штуки как стек и вектор прерываний (о них — позже).

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

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

Забегая на один шаг вперед, хорошо бы понять, а что собственно с прочитанными данными будем делать? Ну хорошо прочитали мы значение датчика и установили значение переменной в памяти контроллера в 23 градуса по Цельсию, соответственно. Как посмотреть на эти цифры? Решение есть! Полученные данные я буду смотреть на большом компьютере выводя их через USART контроллера через виртуальный COM порт по USB кабелю прямо в терминальную программу типа PuTTY. Для того чтобы компьютер смог прочитать наши данные будем использовать преобразователь USB-TTL — такая штука которая и организует виртуальный COM порт в Windows.

Сама схема подключения может выглядеть примерно так:

Сигнальный вывод датчика подключен к ноге 2 (PIN2) порта PORTD контролера или (что то же самое) к выводу D2 Arduino. Он же через резистор 4.7 kOm “подтянут” на “плюс” питания. Плюс и минус датчика подключены — к соответствующим проводам питания. USB-TTL переходник подключен к выходу Tx USART порта Arduino, что значит PIN1 порта PORTD контроллера.

В собранном виде на breadboard:

Разбираемся с датчиком и смотрим datasheet. Сам по себе датчик несложный, и использует всего один сигнальный провод, который надо подтянуть через резистор к +5V — это будет базовый «высокий» уровень на линии. Если линия свободна — т.е. ни контроллер, ни датчик ничего не передают, на линии как раз и будет базовый «высокий» уровень. Когда датчик или контроллер что-то передают, то они занимают линию — устанавливают на линии «низкий» уровень на какое-то время. Всего датчик передает 5 байт. Байты датчик передает по очереди, сначала показатели влажности, потом температуры, завершает все контрольной суммой, это выглядит как “HHTTXX”, в общем смотрим datasheet. Пять байт — это 40 бит и каждый бит при передаче кодируется специальным образом.

Для упрощения, будет считать, что «высокий» уровень на линии — это «единица», а «низкий» соответственно «ноль». Согласно datasheet для начала работы с датчиком надо положить контроллером сигнальную линию на землю, т.е. получить «ноль» на линии и сделать это на период не менее чем 20 милсек (миллисекунд), а потом резко отпустить линию. В ответ — датчик должен выдать на сигнальную линию свою посылку, из сигналов высокого и низкого уровня разной длительности, которые кодируют нужные нам 40 бит. И, согласно datasheet, если мы удачно прочитаем эту посылку контроллером, то мы сразу поймем что: а) датчик собственно ответил, б) передал данные по влажности и температуре, с) передал контрольную сумму. В конце передачи датчик отпускает линию. Ну и в datasheet написано, что датчик можно опрашивать не чаще чем раз в секунду.

Итак, что должен сделать микроконтроллер, согласно datasheet, чтобы датчик ему ответил — нужно прижать линию на 20 миллисекунд, отпустить и быстро смотреть, что на линии:

Датчик должен ответить — положить линию в ноль на 80 микросекунд (мксек), потом отпустить на те же 80 мксек — это можно считать подтверждением того, что датчик на линии живой и откликается:

После этого, сразу же, по падению с высокого уровня на нижний датчик начинает передавать 40 отдельных бит. Каждый бит кодируются специальной посылкой, которая состоит из двух интервалов. Сначала датчик занимает линию (кладет ее в ноль) на определенное время — своего рода первый «полубит». Потом датчик отпускает линию (линия подтягивается к единице) тоже на определенное время — это типа второй «полубит». Длительность этих интервалов — «полубитов» в микросекундах кодирует что собственно пытается передать датчик: бит “ноль” или бит “единица”.

Рассмотрим описание битовой посылки: первый «полубит» всегда низкого уровня и фиксированной длительности — около 50 мксек. Длительность второго «полубита» определят, что датчик собственно передает.

Для передачи нуля используется сигнал высокого уровня длительностью 26–28 мксек:

Для передачи единицы, длительность сигнала высокого увеличивается до 70 микросекунд:

Мы не будет точно высчитывать длительность каждого интервала, нам вполне достаточно понимания, что если длительность второго «полубита» меньше чем первого — то закодирован ноль, если длительность второго «полубита» больше — то закодирована единица. Всего у нас 40 бит, каждый бит кодируется двумя импульсами, всего нам надо значит прочитать 80 интервалов. После того как прочитали 80 интервалов будем сравнить их попарно, первый “полубит” со вторым.

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

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

Определения:

Как я уже писал сам датчик подключен на 2 ногу порта D. В Arduino Uno это цифровой выход D2 (смотрим для проверки Arduino Pinout).

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

Смотрим анализатором — а ответил ли датчик?

Да, ответ есть — вот те сигналы после нашего первого импульса в 20 милсек — это и есть ответ датчика. Для просмотра посылки я использовал китайский клон USBEE AX Pro который подключен к сигнальному проводу датчика.

Растянем масштаб так чтобы увидеть окончание нашего импульса в 20 милсек и лучше увидеть начало посылки от датчика — смотрим все как в datasheet — сначала датчик выставил низкий/высокий уровень по 80 мксек, потом начал передавать биты — а данном случае во втором «полубите» передается «0»

Значит датчик работает и данные нам прислал, теперь надо эти данные правильно прочитать. Поскольку задача у нас учебная, то и решать ее будем тупо в лоб. В момент ответа датчика, т.е. в момент перехода с высокого уровня в низкий, мы запустим цикл с счетчиком числа повторов нашего цикла. Внутри цикла, будем постоянно следить за уровнем сигнала на ноге. Итого, в цикле будем ждать, когда сигнал на ноге перейдет обратно на высокий уровень — тем самым определив длительность сигнала первого «полубита». Наш микроконтроллер работает на частоте 16 MHz и за период например в 50 микросекунд контроллер успеет выполнить около 800 инструкций. Когда на линии появится высокий уровень — то мы из цикла аккуратно выходим, а число повторов цикла, которые мы отсчитали с использованием счетчика — запоминаем в переменную.

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

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

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

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

Для расчета временных задержек мы будет использовать тот же подход, который мы использовали при мигании светодиодом — подберем параметры пустого цикла для формирования нужной паузы. Я использовал специальный калькулятор. При желании можно посчитать число рабочих инструкций и вручную.

Памяти в нашем контроллере довольно много — аж 2 (Два) килобайта, так что мы не будем жлобствовать с памятью, и тупо сохраним данные счетчиков относительно наших 80 ( 40 бит, 2 интервала на бит) интервалов в память.

Объявим переменную

CYCLES: .byte 80 ; буфер для хранения числа циклов

И сохраним все считанные циклы в память.

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

Для того чтобы передавать данные в большой компьютер будем использовать USART контроллера, который через USB кабель будет передавать данные в программу — терминал, например PuTTY. Передаем опять же тупо в лоб — засовываем байт в нужный регистр управления USART-а и ждем, когда он передастся. Для удобства я также использовал пару подпрограмм, типа — передать несколько байт, начиная с адреса в Y, ну и перевести каретку в терминале для красоты.

Отправив в терминал число отсчётов для 80 интервалов, можно попробовать собрать собственно значащие биты. Делать будем как написано в учебнике, т.е. в datasheet — попарно сравним число циклов первого «полубита» с числом циклов второго. Если вторые пол-бита короче — значит это закодировать ноль, если длиннее — то единица. После сравнения биты накапливаем в аккумуляторе и сохраняем в память по-байтово начиная с адреса BITS.

Итак, здесь мы собрали в памяти начиная с метки BITS те пять байт, которые передал контроллер. Но работать с ними в таком формате не очень неудобно, поскольку в памяти это выглядит примерно, как:
34002100ХХ, где 34 — это влажность целая часть, 00 — данные после запятой влажности, 21 — температура, 00 — опять данные после запятой температуры, ХХ — контрольная сумма. А нам надо бы вывести в терминал красиво типа «Temperature = 21.00». Так что для удобства, растащим данные по отдельным переменным.

Определения

И сохраняем байты из BITS в нужные переменные

После этого преобразуем цифры в коды ASCII, чтобы данные можно было нормально прочитать в терминале, добавляем названия данных, ну там «температура» из флеша и шлем в COM порт в терминал.

PuTTY с данными

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

Основной цикл после этого выглядит примерно так:

Прошиваем, подключаем USB-TTL кабель (преобразователь)к компьютеру, запускаем терминал, выбираем правильный виртуальный COM порта и наслаждаемся нашим новым цифровым термометром. Для проверки можно погреть датчик в руке — у меня температура при этом растет, а влажность как ни странно уменьшается.

Ссылки по теме:
AVR Delay Calc
Как подключить Arduino для программирования в Atmel Studio 7
DHT11 Datasheet
ATmega DataSheet
Atmel AVR 8-bit Instruction Set
Atmel Studio
Код примера на github

Программирование микроконтроллеров AVR: от Arduino к ассемблеру

Ревич Юрий Всеволодович

Артикул2684
ISBN 978-5-9775-4076-6
Количество страниц 448
Формат издания 165 x 233 мм
Печать Черно-белая
Серия Электроника

921 ₽
691 ₽

# AVR# ассемблер# электроника и схемотехника#Arduino

  • Описание
  • Детали
  • Отзывы (1)

Описание

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

Даны готовые рецепты для программирования большинства основных функций современной микроэлектронной аппаратуры.

Ревич Юрий Всеволодович – инженер-электронщик, журналист и писатель с многолетним стажем. Основной круг интересов – проектирование микроэлектронных устройств от принципиальной схемы до пользовательского интерфейса, информационные технологии, их влияние на современное общество, технологические инновации, история компьютеров. Автор 16 книг, в том числе «Занимательной электроники», выдержавшей 5 изданий в течение 15 лет, а также нескольких сотен публикаций в журналах, газетах и сетевых изданиях, в том числе ряда статей на портале Habr. ru.

Детали

Артикул2684
ISBN978-5-9775-4076-6
Количество страниц448
Серия Электроника
ПереплетМягкая обложка
Печать Черно-белая
Год2020
Габариты, мм233 × 165 × 19
Вес, кг0.412

  • Новинки на 2 недели раньше магазинов
  • Цены от издательства ниже до 30%
  • Акции и скидки только для подписчиков
  • Важные новости БХВ

ПОЛЕЗНАЯ РАССЫЛКА КНИЖНЫХ НОВОСТЕЙ

Подписываясь на рассылку, вы соглашаетесь с политикой конфиденциальности и обработкой своих персональных данных.


Рекомендуем также

  •  

    Изучаем Arduino: инструменты и методы технического волшебства – Бумажная книга

    660₽
  •  Гадре Д. , Мэлхотра Н.

    Нет в наличии

    Занимательные проекты на базе микроконтроллеров tinyAVR

    325 ₽
  •  Иго Том

    Умные вещи: Arduino, датчики и сети для связи устройств: Пер. с англ. 3-е изд.

    1650 ₽
    1237 ₽
  •  

    Ассемблер – это просто. Учимся программировать. 2-е изд – Бумажная книга

    656₽

Программирование Arduino Uno (ATmega386P) на ассемблере · GitHub

В Интернете есть несколько различных источников, описывающих способы программирования Arduino Uno/ATmega328P на ассемблере, и за последние пару дней мне пришлось переключаться между большинством из них только для того, чтобы основные настройки и начальные программы работали. Это попытка объединить все эти источники в централизованный документ с двумя простыми примерами программ.

Требования

Есть два основных варианта задачи (о которых я знаю), и установка, на которой я остановился, является случайной в ретроспектива 1 . Но вы можете самостоятельно исследовать альтернативную установку, основанную на проекте AVR Libc.

Для установки, которую я использую, вам нужны: avrdude и avra. Обратите внимание, что я использую Linux, и если вы используете другую операционную систему, вы будете самостоятельно устанавливать/настраивать эти инструменты.

Необязательный (но должен быть прочитан)

При подключении через USB мой последовательный интерфейс Uno будет сопоставлен с /dev/ttyACM0 . Поскольку я хотел более интуитивно понятное имя устройства (и тот факт, что мне потребовалось некоторое время, чтобы узнать, какое имя устройства было в первом имени), я написал 9Правило 0015 udev для сопоставления моей платы Uno с

/dev/arduino-uno .

$ кот /etc/udev/rules.d/10-arduino.rules
KERNEL=="ttyACM0", SYMLINK+="arduino-uno", OWNER="mhitza" 

Если вы создаете символическую ссылку, не забудьте также включить директиву OWNER ; в противном случае каждый раз, когда вы загружаете новую программу в Uno, вам придется звонить по номеру avrdude с sudo .

ПРИМЕЧАНИЕ Если вы пропустили этот шаг, обязательно замените все вхождения /dev/arduino-uno с /dev/ttyACM0 и префикс всех вызовов

avrdude с sudo в последующем Makefile.

Также вы увидите ссылку на picocom (программа, используемая для последовательной связи с платой) в Makefile, который я использую, и он должен работать, но я еще не тестировал его.

Простой Makefile

ПРИМЕЧАНИЕ Уже существует популярный проект Makefile для Arduino, однако он основан на проекте AVR Libc. Как и в случае с другими готовыми решениями, такими как oh-my-zsh, я предпочитаю начинать с небольшой базы. Мне легче понять и поддерживать.

Makefile доступен ближе к концу страницы.

Дана программа с именем blink.asm

  • make (или make blink. hex ) — скомпилировать в шестнадцатеричный файл
  • make program=blink upload — загрузить программу на плату Arduino. Если вы не выполнили предыдущий шаг вручную, он также скомпилирует программу для вас
  • .
  • сделать монитор — контролировать последовательные данные

Откуда берутся имена?

При чтении других примеров ассемблерного кода в Интернете вы найдете ссылки на именованные константы, которые не встроены в ассемблер. Обычно они приходят из m328Pdef.inc. Откуда ты скачать этот файл на самом деле не имеет значения, так как в основном каждый носит с собой копию; или так кажется.

2

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

Проект по образцу код

Проект представлен на 123d. circuits.io

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

Будут показаны две реализации, первая — это то, как большинство людей — я думаю — написали бы реализацию (с точки зрения реакции на нажатия кнопок, не обязательно, как они будут переключать светодиоды) (при условии, что они не знают о прерывания еще), а вторая версия будет использовать прерывание вместо «опроса» вывода на предмет изменения напряжения (состояния).

Ссылки

ПРИМЕЧАНИЕ руководство по ассемблеру предназначено для AVRASM32.exe , а не avra . Однако avra является совместимым ассемблером с несколькими дополнительными функциями

.

ПРИМЕЧАНИЕ Если вы видите в Интернете ссылки на avrasm2 , вы должны знать, что эта часть программного обеспечения отличается от AVRASM32.exe и avra . И avra вряд ли сможет скомпилировать код, написанный для этого ассемблера.

При программировании AVR на ассемблере необходимо держать эти ссылки под рукой:

  • Набор инструкций для 8-битного AVR Atmel — корпорация Atmel
  • Руководство по сборке AVR

  1. Первоначально я начал с avr-as , но нашел полезные ответы stackoverflow указал на avra и как только я смог написать простую программу я не оглядывался назад. прыгать на ссылка
  2. Возможно, это имеет значение, откуда вы его скачали. Какой-нибудь подлый человек может предоставить это файл в измененном формате, где сопоставления были бы неправильными, и вы бы записывали в неправильные биты памяти и тратили часов/дней на отладку ассемблерного кода.
    перейти к ссылке

Несмотря на то, что в предыдущем документе упоминалось, что вы должны загрузить руководство по набору инструкций по сборке, для следующих примеров я хотел бы подробно описать инструкции, которые я буду использовать (чтобы вы могли следовать примерам кода).

  • метка jmp или метка rjmp — перейти к метке
  • sbi memory_location, bit_position — установить бит немедленно 1
  • cbi memory_location, bit_position — сразу очистить бит
  • очистка регистра — очистить регистр
  • sbis memory_location, bit_position — установить немедленную (битовую) ветвь пропуска 2
  • sbic memory_location, bit_position — пропустить ветвь немедленно (бит) очистить
  • tst register — тестовый регистр на нулевое или отрицательное число, если true, флаг Z установлен набор 3
  • brne label — ответвление не равно
  • регистр ldi, значение_байта — немедленная загрузка данных
  • reti — возврат из прерывания
  • out memory_location, register — записать регистр в ячейку памяти
  • lds register, data_space — загрузка из области данных (регистр, память ввода/вывода, SRAM) в регистр
  • регистр ori, byte_value — побитовое ИЛИ немедленное
  • регистр sts, data_space — сохранить в пространство данных из регистра
  • sei — разрешить прерывания
  • в регистре, memory_location — прочитать адрес памяти в регистр

  1. Немедленно здесь означает, что значение (bit_position/byte_value) может быть указано напрямую для операции. перейти к ссылке
  2. С инструкциями пропуска ветвления, когда сравнение оказывается верным, последующее инструкция пропускается. В большинстве случаев эта последующая инструкция будет jmp. перейти к ссылке
  3. Есть несколько инструкций, которые работают с неявными значениями в реестре SREG. За Например, флаг Z равен 1 биту в этом регистре. tst — одна из многих инструкций, устанавливающих это значение, в то время как инструкции brne / breq являются двумя примерами инструкций, в которых используется бит Z. ценить. перейти к ссылке

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

Взято из «Книги проектов Arduino», лицензия CreativeCommons BY-NC-SA 3.0


Если не указано иное, эта работа находится под лицензией Creative Commons Attribution 4. 0 International License.

Программирование Arduino Uno на языке ассемблера — micropi

Недавно я экспериментировал с программированием Arduino Uno на языке ассемблера. Здесь я объясню, как установить и настроить Microchip Studio для этого, покажу, как использовать последовательный интерфейс Arduino, и напишу пример программы для демонстрации.

Установка Microchip Studio

Microchip Studio — это IDE, которую мы собираемся использовать для программирования Arduino — она содержит ассемблер, необходимый для перевода языка ассемблера в машинный язык. Microchip — это компания, которая приобрела Atmel, производящую микроконтроллеры AVR, которые используются в Arduinos. Вы обнаружите, что во многих онлайн-учебниках рассказывается об Atmel Studio, которая стала частью Microchip Studio, когда Atmel была приобретена, и больше не доступна.

Вы можете скачать Microchip Studio с веб-сайта Microchip здесь. Установщик спрашивает, какие семейства плат вы хотите установить — я выбрал только AVR, так как это то, что использует Arduino, и отменил выбор двух других. Тем не менее, вы можете установить другие, если хотите. Я также решил не устанавливать расширенный фреймворк, но вы можете это сделать, если хотите.

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

После установки Microchip Studio вы можете открыть его и выбрать File > New > Project, чтобы создать свой первый проект. В открывшемся диалоговом окне выберите «Assembler» слева и выберите появившуюся опцию «AVR Assembler Project». Дайте ему имя и местоположение внизу и нажмите OK, чтобы создать проект.

Далее вас спросят, на каком устройстве вы хотите запустить проект. Arduino Uno содержит ATmega328P, поэтому выберите эту опцию — вы можете искать в правом верхнем углу. Убедитесь, что вы не выбрали ATmega328 или ATmega328PB, если только вы не думаете, что ваша плата использует один из них.

Настройка AVRDUDE

Microchip Studio может напрямую программировать микроконтроллеры, только если вы купите специальный программатор. Однако AVRDUDE — это утилита командной строки, которую можно использовать для программирования через USB, как обычно с Arduino. Arduino IDE фактически использует AVRDUDE для программирования Arduino под капотом.

Если у вас установлена ​​Arduino IDE, вам не нужно устанавливать AVRDUDE, вы можете использовать копию, поставляемую с IDE.

Мы собираемся настроить AVRDUDE в качестве внешнего инструмента в Microchip Studio. Это можно сделать, перейдя в Инструменты > Внешние инструменты. Дайте записи название, я назвал его «Вспышка». В команде должен быть путь к исполняемому файлу AVRDUDE, у меня это было

 C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude.exe 

И аргументы должны выглядеть следующим образом:

 -v -patmega328p -carduino -PCOM4 -b115200 -D - Uflash:w:"$(ProjectDir)Debug\$(TargetName).hex":i -C"C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf" 
  • — v: подробный вывод
  • -p: указывает, на какую микросхему мы хотим записывать программы
  • -c: указывает используемый метод программирования, в данном случае arduino
  • -P: порт, к которому подключен Arduino. Его можно найти в Windows, перейдя в Диспетчер устройств, выбрав «Порты (COM и LPT)» и найдя порт, соответствующий Arduino
  • -b: скорость передачи, используемая при программировании чипа
  • -D: отключает стирание флэш-память перед записью в нее
  • -U: указывает, что должен делать AVRDUDE. «flash» указывает на использование флэш-памяти чипа, «w» указывает на запись в нее, каталог — это файл машинного кода для записи, а «i» указывает, что файл находится в шестнадцатеричном формате Intel. «$(ProjectDir)» и «$(TargetName)» автоматически заменяются Microchip Studio для получения пути к собранному файлу.
  • -C: указывает путь к файлу конфигурации AVRDUDE — он зависит от того, где у вас установлена ​​среда разработки Arduino IDE.

Также стоит отметить опцию «Использовать окно вывода», чтобы вы могли легко видеть вывод при программировании Arduino.

Пример программы – инвертор строк

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

Запись на последовательный монитор

Следующие две подпрограммы могут использоваться для отправки данных на последовательный монитор на подключенном ПК.

serial_init настраивает соединение USART для использования скорости 9600 бод и ожидаемых настроек форматирования и четности, а serial_transmit ожидает, пока не будет передан последний символ, прежде чем передать символ, хранящийся в регистре 19, по последовательному соединению. Эти подпрограммы взяты из полезного репозитория GitHub Алана Пирсона здесь.

Чтение с последовательного монитора

Мы также можем считать данные с последовательного монитора с помощью этой подпрограммы:

Он ожидает установки бита завершения приема в регистре состояния USART (бит 7 в 0xc0), а затем сохраняет полученный байт в регистре данных ввода-вывода (0xc6) в регистре 19.

Использование stack to reverse strings

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

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

Он начинается с вызова serial_init для инициализации последовательного соединения.

На стартовой метке он помещает 0x0a в стек ( 0a — это ASCII-код символа новой строки в шестнадцатеричном формате) и печатает байт 0x3e (код символа ‘>’) — это приглашение пользователя ввести строку.

В цикле он вызывает serial_receive для загрузки следующего символа в регистр 19, затем немедленно вызывает serial_transmit для печати только что введенного пользователем символа. Затем он сравнивает символ с символом новой строки 0x0a . Если они равны, выполняется переход к метке input_finished . В противном случае он помещает символ в стек и снова зацикливается.

На метке input_finished он извлекает символ из стека и печатает его. Если символ был новой строкой (новая строка, которую мы нажали в начале), вся строка была напечатана, поэтому она возвращается к начало метки . В противном случае он возвращается к input_finished и продолжает извлекать и печатать символы, пока не встретит новую строку.

Вы можете посмотреть программу на GitHub здесь.

Запись программы на Arduino

Теперь, когда программа готова, нам нужно собрать ее в машинный код. Это можно сделать, нажав F7 или выбрав Build > Build Solution. Надеюсь, вы увидите вывод ассемблера с надписью «Сборка выполнена успешно». Однако, если есть ошибки, появится список ошибок и их номера строк.

После того, как программа собрана, ее можно прошить на Arduino. Перейдите в «Инструменты» и нажмите на то, что вы назвали AVRDUDE ранее (я назвал это «Flash»). Надеюсь, вы увидите содержимое флэш-памяти и проверяемых фьюзов в окне вывода, что свидетельствует об успешном завершении.

Если вы видите сообщение типа ser_open(): не удается открыть устройство "\\.\COM5": система не может найти указанный файл , убедитесь, что COM-порт, который вы указали ранее при настройке AVRDUDE в качестве внешнего инструмента по-прежнему правильно и что Arduino действительно подключен к ПК.

Теперь, когда программа записана на плату, вы можете попробовать ее. Откройте последовательный монитор (я использую тот, который включен в Arduino IDE) и убедитесь, что скорость передачи установлена ​​на 9600.

Когда вы отправляете текст в Arduino, вы должны обнаружить, что он отправляется обратно в обратном порядке. Та да!

Обратите внимание: если вы попытаетесь снова прошить Arduino сейчас, вы получите сообщение вроде ser_open(): не удается открыть устройство "\.\COM4": Доступ запрещен. Это связано с тем, что только одно приложение может одновременно получить доступ к COM-порту — вам необходимо закрыть последовательный монитор, прежде чем AVRDUDE сможет его использовать.

alexxlab

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

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