Шаг 4: Написание скетча для Arduino Uno — КиберПедия 

Индивидуальные очистные сооружения: К классу индивидуальных очистных сооружений относят сооружения, пропускная способность которых...

Общие условия выбора системы дренажа: Система дренажа выбирается в зависимости от характера защищаемого...

Шаг 4: Написание скетча для Arduino Uno

2020-11-19 196
Шаг 4: Написание скетча для Arduino Uno 0.00 из 5.00 0 оценок
Заказать работу

 

Для управления Arduino по протоколу Bluetooth нам нужна программа, которая будет выполнять функцию удаленной панели управления.

    В этом примере мы будем использовать в качестве такой программы Android-приложение.

    Такое приложение можно создать с помощью сервиса MIT App Inventor (https://appinventor.mit.edu/).

    Однако, следует помнить, что в качестве компонента, выполняющего в приложении функцию взаимодействия по протоколу Bluetooth, следует использовать компонент BluetoothClient.

    Для примера, описываемого в этой презентации было использовано одно из готовых приложений (https://cdn.instructables.com/ORIG/FCU/BDEA/IT22WRF4/FCUBDEAIT22WRF4.apk), изображенное на рисунке ниже.

 

 

Шаг 5: Настройка Bluetooth на ПК

 

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

    Таким образом, для взаимодействия по протоколу Bluetooth нужно в настройках Bluetooth на ПК связать Bluetooth адаптер с одним из виртуальных COM-портов и войдя в редактирование свойств платы Bluetooth в Proteus выбрать тот COM порт, к которому был подключен Bluetooth адаптер.

    О том, как подключить COM-порт к адаптеру Bluetooth можно прочитать в этой статье: https://www.instructables.com/id/Arduino-Serial-Monitor-for-Android-Apps/

 

 

Шаг 6: Запуск симуляции

 

Смотри видео по ссылке ниже

 

 

https://youtu.be/orjMmlqXcko

Микроконтроллер

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

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

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

Микроконтроллеры уже достаточно давно развиваются параллельно с микропроцессорами — так, до сих пор встречающаяся в промышленных изделиях архитектура Intel 8051 была разработана в 1980 году. В каких-то моментах линии их развития начинают пересекаться с микропроцессорами — так, старшие модели микроконтроллеров имеют интерфейсы для внешнего ОЗУ, а производители микропроцессоров интегрируют на кристалл всё больше периферийных устройств (достаточно вспомнить, что на заре «персоналок» даже кэш-память набиралась внешними микросхемами) — но в любом случае они остаются двумя существенно отличающимися ветвями развития.

Собственно, целью создания микроконтроллеров была возможность удешевления и миниатюризации различных устройств, требующих некоторой небольшой вычислительной мощности: использование одного чипа, на который для его работы достаточно просто подать питание, существенно упрощает разработку и производство печатной платы по сравнению с набором из 4-5 отдельных чипов.

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

· Рабочие частоты редко превышают 200 МГц, а чаще находятся в районе десятков мегагерц.

· Объём оперативной памяти — в пределах мегабайта, а чаще — в районе десятков килобайт.

· Объём памяти программ — в пределах мегабайта, а чаще — в районе десятков-сотен килобайт.

Мы в рамках курса будем работать с микроконтроллерами STM32L151CC, имеющими 32 КБ ОЗУ, 256 КБ ПЗУ и максимальную рабочую частоту 32 МГц (на платах Nucleo-L152RE стоят чуть более серьёзные чипы — 80 КБ ОЗУ и 512 КБ ПЗУ).

 

 

Память

В общем случае внутри микроконтроллера может быть четыре вида памяти:

1. Постоянная память (флэш-память) используется для хранения пользовательских программ и, иногда, некоторых настроек самого микроконтроллера. Если при указании на характеристики микроконтроллера пишут объём памяти, не указывая, какой именно — как правило, это про флэш. Содержимое флэша не сбрасывается при пропадании питания, срок хранения информации в нём в нормальных условиях обычно не менее 10 лет.

2. Оперативная память используется для выполнения пользовательской программы и хранения «сиюминутных» данных. ОЗУ всегда сбрасывается при перезагрузке или выключении питания, а также может не сохраняться при входе в некоторые режимы сна. В микроконтроллерах часто нет чёткого разделения на память программ и память данных — в результате можно встретить термин «выполнение из ОЗУ», означающий, что в ОЗУ находятся не только данные, но и сама программа; впрочем, это достаточно экзотические случаи.

3. EEPROM. Тоже относится к постоянной памяти, но существенно отличается от флэш-памяти своими характеристиками. У флэша есть два больших недостатка, делающие его очень неудобным для сохранения из программы каких-то текущих данных — во-первых, у флэша ограниченное число перезаписей одной и той же ячейки, во-вторых, с флэшом часто можно работать только целыми страницами, которые имеют размер в сотни байт, даже если вам надо перезаписать всего один байт. EEPROM этих недостатков лишён — срок его службы обычно вдесятеро больше (от 100 тыс. до 1 млн. перезаписей), и работать в нём можно с каждым байтом по отдельности. По этой причине EEPROM используют для постоянного хранения данных, генерируемых самой программой (архивы измерений, настройки программы и т.п.), его типовой объём составляет единицы килобайт, но есть он не во всех контроллерах.

4. Системная память. Области постоянной памяти, недоступные пользователю для записи, а записывающиеся при производстве микроконтроллера. Обычно в них находится исполняемый код загрузчика (о нём ниже), но могут также храниться какие-либо калибровочные константы, серийные номера или даже вспомогательные библиотеки для работы с периферийными устройствами

 

Посмотреть на организацию памяти конкретного контроллера можно в его даташите. Вот, например, даташит на STM32L151CC, на странице 51 которого представлена карта памяти этого семейства.

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

Регистры

Дело в том, что всё — вообще всё — общение со всеми периферийными устройствами микроконтроллера и всеми его настройками осуществляется с помощью всего двух операций:

· прочитать значение по заданному адресу

· записать значение по заданному адресу

Всё, что есть внутри микроконтроллера, обязательно отображено на какой-то адрес. Эти адреса называются регистрами (не путайте с регистрами процессора — в регистрах процессорах находятся данные, над которыми процессор производит операции; в регистрах, о которых мы говорим, находятся некие специальные данные, которые специфическим образом отображаются на состояние различных аппаратных блоков микроконтроллера).

Так, например, если мы хотим, чтобы на третьей ножке порта А микроконтроллера (PA2, нумерация идёт с нуля) появилась «1», нам надо записать «1» в третий бит регистра, расположенного по адресу 0x4002014. А если эта ножка настроена как вход и мы, наоборот, хотим узнать, какое на ней значение — нам надо прочитать третий бит регистра по адресу 0x40020010.

Да, чтобы указать контроллеру, входом или выходом является эта ножка — надо записать соответствующие значения в соответствующие биты по адресу 0x40020000.

Это — важный момент в понимании работы микроконтроллера: абсолютно всё, что не является вычислительными операциями, за которые отвечает само ядро процессора, осуществляется с помощью записи или чтения того или иного регистра. Какие бы библиотеки не были наворочены в вашей программе сверху — в конечном итоге всё сводится к регистрам.

Разумеется, работать с числовыми адресами довольно неудобно, поэтому для каждого микроконтроллера на ядре Cortex-M существует библиотека CMSIS (Cortex Microcontroller Software Interface Standard), самый важный компонент которой для нас — заголовочный файл, описывающий имеющиеся в конкретном контроллере регистры и дающий им относительно человекочитаемые имена.

С использованием CMSIS описанные выше операции с ножкой PA будут выглядеть так:

int pin_num = 2; /* PA2*/

GPIOA->MODER &= ~(0b11 << (pin_num*2)); /* сбросили биты настройки ножки PA2 на всякий случай */

GPIOA->MODER |= 0b01 << (pin_num*2); /* установили биты настройки ножки PA2 в 01 — выход */

GPIOA->ODR |= 1 << pin_num; /* установили ножку PA2 в 1 */

GPIOA->MODER &= ~(0b11 << (pin_num*2)); /* сбросили биты настройки ножки PA2, теперь это вход */

uint32_t pa2_value = GPIOA->IDR & (1 << pin_num); /* прочитали состояние ножки PA2 */

Все названия регистров и значения полей в них описаны в документе, который можно считать Библией программиста микроконтроллеров — Reference Manual (он, разумеется, свой для каждого семейства контроллеров, ссылка дана на RM0038, соответствующий семейству STM32L1). Отмечу, что более чем 900 страниц RM0038 — это не очень большой объём информации, легко можно встретить контроллеры с руководствами по 1500-2000 страниц. Вряд ли есть кто-то, помнящий хотя бы треть такого руководства наизусть, но умение быстро в нём ориентироваться — обязательное качество для хорошего программиста.

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

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

В случае с STM32 основная библиотека называется Standard Peripherals Library, она же StdPeriphLib, она же SPL. Помимо неё, существует выпускаемая ST библиотека LL, и ряд сторонних библиотек — например, LibOpenCM3. Сторонние библиотеки часто поддерживают и контроллеры других производителей, но в силу распространённости STM32 они обычно оказываются на первом месте.

Так, при использовании SPL обращения к регистрам, которые мы совершали, чтобы зажечь светодиод, превратятся в обращения к функциям GPIO_Init и GPIO_Write.

Впрочем, нельзя не заметить, что среди профессиональных разработчиков отношение к SPL — двойственное.

С одной стороны, SPL позволяет значительно быстрее набросать «скелет» проекта, особенно при использовании графических средств конфигурирования контроллера, таких как STM32 CubeMX. При этом код будет довольно хорошо (настолько, насколько у них совпадает набор периферийных устройств и возможностей, которыми вы пользуетесь) переноситься между разными контроллерами семейства STM32.

С другой стороны, как показывает практика, в сложном проекте нет вопроса «что делать, если что-то будет работать не так» — в нём есть вопрос «что делать, когда всё будет работать не так». В SPL, как и в любой библиотеке, могут быть ошибки, кроме того, логика разработчиков SPL может не совпадать с вашим представлением о том, что должно происходить с контроллером при тех или иных действиях — в результате при попадании в такую ситуацию вам всё равно придётся открывать исходники SPL и смотреть, что конкретно там происходит на уровне регистров. На практике это может иногда занять времени не меньше, чем написание нужной вам функциональности с нуля.

Кроме того, библиотеки, выпущенные конкретным производителем чипов, хоть и позволяют в каких-то пределах мигрировать между чипами этого производителя, но перескочить, например, с STM32L1 на ATSAMD21 с кодом, написанным для SPL, у вас не получится при всём желании.

Не всегда помогает SPL и читаемости кода — в программах, написанных с её использованием, нередко можно увидеть простыни размером в полстраницы, состоящие из одних только вызовов SPL.

Наконец, SPL решает лишь одну проблему — абстрагирования от «железа» и работы с регистрами. Однако по мере развития проекта вы столкнётесь ещё с несколькими, например:

· Виртуализация периферийных устройств. Например, в вашем контроллере есть всего один таймер часов реального времени (RTC), на который можно установить два независимых события — и в то же время в серьёзной программе запросто может оказаться пять-шесть функций, который используют таймер регулярно (для периодического выполнения заданий) или разово (например, для отсчёта задержки), причём другие таймеры им не подходят. В этой ситуации вам потребуется функция-менеджер, которая будет организовывать одновременную работу всех этих процедур с единственным имеющимся таймером.

· Многозадачность. Любая достаточно сложная система быстро обрастает большим количеством всевозможных процедур, которым надо срабатывать с различной периодичностью или по различным событиям. Знакомый многим по Arduino цикл loop() уже на полудесятке утрамбованных в него разношёрстных процедур начинает выглядеть уродливым монстром, а попытка организовать в его рамках ещё и приоритизацию задач вселяет ужас в сердца людей. В этот момент вы захотите вынести все задачи из loop() в независимые функции, оставив в цикле только планировщик, который будет к указанным задачам обращаться. Это будет первыми зачатками многозадачности (о полной её реализации, типах планировщиков и общении между разными задачами мы поговорим на следующей лекции).

· Разделение труда. Как только разработка системы выйдет на уровень, на котором её ведут несколько человек, перед вами встанет задача разделения обязанностей — помимо оптимизации разработки, имеющая ещё и чисто практический смысл: в мире довольно мало программистов-универсалов, которые могут с одинаковой эффективностью отлаживать и работу с процессором, и сетевой стек, и пользовательский интерфейс. Со значительно большей вероятностью каждый из членов вашей команды будет лучше других разбираться в какой-то одной области — поэтому вам быстро захочется разделить эти области на уровне кода, чтобы, например, специалист по пользовательскому интерфейсу не был вынужден через строчку сталкиваться с обращением к регистрам контроллера, и наоборот. Это приведёт к разбиению вашего кода на отдельные модули, общающиеся друг с другом через стандартизированные API.

· Все эти задачи — и попутно ещё много других — решает операционная система.

· Несмотря на то, что ОС требует для своего существования дефицитных ресурсов контроллера (обычно 5-20 КБ постоянной памяти и ещё столько же оперативной).

Строго говоря, на нижнем уровне ОС может использовать вендорские библиотеки, подобные SPL. Однако в рамках нашего курса мы будем работать с RIOT OS, нижнеуровневый код которой для семейства STM32 написан на регистрах — работу с SPL же мы затрагивать не будем вообще.

Причина этого проста: хотя в целом мы будем изучать работу ОС и контроллера на верхнем уровне, но в тех случаях, когда мы захотим углубиться в детали их функционирования, нам всё равно придётся спускаться на уровень регистров, и прослойка в виде SPL довольно сильно бы этому мешала. Освоив же общие принципы работы с контроллерами, при желании с функционированием SPL вы сможете разобраться самостоятельно, тем более, что абсолютное большинство учебников по STM32, доступных онлайн, построены на её базе.

Операционная система

В виде максимально упрощённой схемы ОС можно представить как набор компонентов, выстроенных в определённую иерархию:

· нижний уровень — код, непосредственно работающий с микроконтроллером;

· средний уровень — компоненты, входящие в саму ОС, но уже не зависящие от конкретного контроллера: драйверы различных внешних устройств, планировщик задач, различные вспомогательные службы;

· верхний уровень — собственно пользовательское приложение.

Одна из причине, почему мы будем работать с RIOT OS и без использования каких-либо средств разработки (IDE) — в получающем в последнее время всё большее распространение магическом мышлении, согласно которому, многие функции реализуются нажатием соответствующих кнопок в IDE, и без этих кнопок невозможны (так, я встречал утверждение, что достоинство Arduino IDE — в возможности собрать один и тот же код под разные аппаратные платформы путём выбора нужной платформы в меню; по мнению рассказчика, другие системы таким функционалом не обладали, так как не имели соответствующего меню).

Точнее, если вспоминать фразу Артура Кларка про технологии, неотличимые от магии, то это мышлении можно скорее назвать псевдомагическим, переформулировав афоризм как «любая технология, достаточно хорошо спрятанная от пользователя, становится неотличима от магии».

На самом деле, разумеется, никакой особенной функции меню в Arduino IDE, как и в любой другой IDE, не несёт — это лишь графическая оболочка для доступа к некоторым совершенно стандартным функциям и особенностям современных программных систем

Если мы посмотрим на то, как выглядит RIOT OS в виде набора файлов на диске, то без труда опознаем разложенные по папочкам компоненты системы: HAL лежит в папке cpu (и если мы её откроем, то увидим описания для десятков различных микроконтроллеров, от AVR до PIC32), описания построенных на этих контроллерах плат — boards, драйверы внешних устройств — drivers, ядро ОС — core, системные и вспомогательные сервисы ОС — sys, пользовательские приложения — examples.

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

Исходные коды ОС

Мы будем работать с исходными кодами в версии https://github.com/unwireddevices/RIOT/tree/mirea — это ответвление от основной разработки RIOT OS, в котором силами Unwired Devices улучшена поддержка микроконтроллеров STM32L1, а также добавлены некоторые полезные сервисы, например, таймеры на базе часов реального времени, включая миллисекундный таймер.

Исходные коды можно загрузить с Github, выбрав кнопку «Clone/Download» и «Download ZIP», но лучшим вариантом будет создание собственного репозитория. Для этого зарегистрируйтесь на GitHub, после чего вернитесь в указанный выше репозиторий и нажмите кнопку «Fork» — исходные коды будут скопированы в ваш аккаунт, откуда вы сможете уже без проблем работать с ними.

Я не буду описывать здесь детали работы с GitHub и Git — в интернете есть масса отличных пошаговых руководств, повторять которые нет смысла.


Поделиться с друзьями:

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

История развития хранилищ для нефти: Первые склады нефти появились в XVII веке. Они представляли собой землянные ямы-амбара глубиной 4…5 м...

Эмиссия газов от очистных сооружений канализации: В последние годы внимание мирового сообщества сосредоточено на экологических проблемах...

Историки об Елизавете Петровне: Елизавета попала между двумя встречными культурными течениями, воспитывалась среди новых европейских веяний и преданий...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.053 с.