- Arduino для начинающих. Часть 1
- Предисловие
- Введение
- Начало
- Первая программа
- Прошивка Arduino
- Прототипирование/макетирование
- Как программируют Arduino
- Язык Arduino
- Подготовка и бесконечность
- Что можно и чего нельзя
- И всё же
- Какие ещё языки используют для Arduino
- Структура программы на языке C++ для Arduino
- Из чего состоит программа
- Классика жанра: мигающий светодиод
- Что делают выражения
- Подключение и программирование Ардуино для начинающих
- Как написать скетч?
- Послесловие к базовым урокам
- Структура программы
- “Многозадачность” с yield()
- “Многозадачность” с millis()
- “Многозадачность” с прерываниями таймера
- Переключение задач
- Флаги
- Избавляемся от циклов и задержек
- Как соединить несколько скетчей?
- Пример “Метеостанция”
Arduino для начинающих. Часть 1
Предисловие
Доброго времени суток, Хабр. Запускаю цикл статей, которые помогут Вам в знакомстве с Arduino. Но это не значит, что, если Вы не новичок в этом деле – Вы не найдёте ничего для себя интересного.
Введение
Было бы не плохо начать со знакомства с Arduino. Arduino – аппаратно-программные средства для построения систем автоматики и робототехники. Главным достоинством есть то, что платформа ориентирована на непрофессиональных пользователей. То есть любой может создать своего робота вне зависимости от знаний программирования и собственных навыков.
Начало
Создание проекта на Arduino состоит из 3 главных этапов: написание кода, прототипирование (макетирование) и прошивка. Для того, чтоб написать код а потом прошить плату нам необходима среда разработки. На самом деле их есть немало, но мы будем программировать в оригинальной среде – Arduino IDE. Сам код будем писать на С++, адаптированным под Arduino. Скачать можно на официальном сайте. Скетч (набросок) – программа, написанная на Arduino. Давайте посмотрим на структуру кода:
Важно заметить, что обязательную в С++ функцию main() процессор Arduino создаёт сам. И результатом того, что видит программист есть:
Давайте разберёмся с двумя обязательными функциями. Функция setup() вызывается только один раз при старте микроконтроллера. Именно она выставляет все базовые настройки. Функция loop() — циклическая. Она вызывается в бесконечном цикле на протяжении всего времени работы микроконтроллера.
Первая программа
Для того, чтоб лучше понять принцип работы платформы, давайте напишем первую программу. Эту простейшую программу (Blink) мы выполним в двух вариантах. Разница между ними только в сборке.
Принцип работы этой программы достаточно простой: светодиод загорается на 1 секунду и тухнет на 1 секунду. Для первого варианта нам не понадобиться собирать макет. Так как в платформе Arduino к 13 пину подключён встроенный светодиод.
Прошивка Arduino
Для того, чтоб залить скетч на Arduino нам необходимо сначала просто сохранить его. Далее, во избежание проблем при загрузке, необходимо проверить настройки программатора. Для этого на верхней панели выбираем вкладку «Инструменты». В разделе «Плата», выберете Вашу плату. Это может быть Arduino Uno, Arduino Nano, Arduino Mega, Arduino Leonardo или другие. Также в разделе «Порт» необходимо выбрать Ваш порт подключения (тот порт, к которому вы подключили Вашу платформу). После этих действий, можете загружать скетч. Для этого нажмите на стрелочку или во вкладке «Скетч» выберете «Загрузка» (также можно воспользоваться сочетанием клавиш “Ctrl + U”). Прошивка платы завершена успешно.
Прототипирование/макетирование
Для сборки макета нам необходимы следующие элементы: светодиод, резистор, проводки (перемычки), макетная плата(Breadboard). Для того, чтоб ничего не спалить, и для того, чтоб всё успешно работало, надо разобраться со светодиодом. У него есть две «лапки». Короткая – минус, длинная – плюс. На короткую мы будем подключать «землю» (GND) и резистор (для того, чтоб уменьшить силу тока, которая поступает на светодиод, чтоб не спалить его), а на длинную мы будем подавать питание (подключим к 13 пину). После подключения, загрузите на плату скетч, если вы ранее этого не сделали. Код остаётся тот же самый.
На этом у нас конец первой части. Спасибо за внимание.
Источник
Как программируют Arduino
Многие думают, что на языке Wiring, но на самом деле…
Arduino — это программируемый микроконтроллер, который можно использовать в робототехнике, умном доме и вообще запрограммировать его как угодно: чтобы он кормил кота, поливал растения, предупреждал вас о приближении врагов или открывал двери с помощью магнитного ключа. У нас есть подборка 10 интересных вещей, которые можно сделать на этой платформе. Теперь время разобраться, как программисты с ней работают.
Язык Arduino
Если опытный программист посмотрит на код для Arduino, он скажет, что это код на C++. Это недалеко от истины: основная логика Ардуино реализована на C++, а сверху на неё надет фреймворк Wiring, который отвечает за общение с железом.
На это есть несколько причин:
Подготовка и бесконечность
В любой программе для Arduino есть две принципиальные части: подготовительная часть и основной цикл.
В подготовительной части вы говорите железу, чего от вас ожидать: какие порты настроить на вход, какие на выход, что у вас как называется. Например, если у вас датчик подключён ко входу 10, а лампочка к выходу 3, то вы можете обозвать эти входы и выходы как вам удобно, а дальше в коде обращаться не к десятому входу и третьему выходу, а по-человечески: к датчику или лампочке. Вся часть с подготовкой выполняется один раз при старте контроллера. Контроллер всё запоминает и переходит в основной цикл.
Основной цикл — это то, что происходит в функции loop(). Ардуино берёт оттуда команды и выполняет их подряд. Как только команды закончились, он возвращается в начало цикла и повторяет всё. И так до бесконечности.
В основном цикле мы описываем все полезные вещи, которые должен делать контроллер: считывать данные, мигать лампами, включать-выключать моторы, кормить кота и т. д.
Что можно и чего нельзя
Ардуино работает на одноядерном и не шибко шустром процессоре. Его тактовая частота — 16 мегагерц, то есть 16 миллионов процессорных операций в секунду. Это не очень быстро, плюс ядро только одно, и оно исполняет одну команду за другой.
Вот какие ограничения это на нас накладывает.
Нет настоящей многозадачности. Можно симулировать многозадачность с помощью приёма Protothreading, но это скорее костыль. Нельзя, например, сказать: «Когда нажмётся такая-то кнопка — сделай так». Вместо этого придётся в основном цикле писать проверку: «А эта кнопка нажата? Если да, то. »
Нет понятия файлов (без дополнительных примочек, библиотек и железа). На контроллер нельзя ничего сохранить, кроме управляющей им программы. К счастью, есть платы расширения, которые позволяют немножко работать с файлами на SD-карточках.
Аналогично с сетью: без дополнительных плат и библиотек Ардуино не может ни с чем общаться (кроме как включать-выключать электричество на своих выходах).
Полегче со сложной математикой: если вам нужно что-то сложное типа тригонометрических функций, будьте готовы к тому, что Ардуино будет считать их довольно медленно. Для вас это одна строчка кода, а для Ардуино это тысячи операций под капотом. Пощадите.
Отчёты? Ошибки? Только при компиляции. У Ардуино нет встроенных средств сообщить вам, что ему нехорошо. Если он завис, он не покажет окно ошибки: во-первых, у него нет графического интерфейса, во-вторых — экрана. Если хотите систему ошибок или отчётность, пишите её 🙂
Если серьёзно, то перед заливом программы на контроллер компилятор проверит код и найдёт в нём опечатки или проблемы с типами данных. Но на этом всё: если у вас случайно получилась бесконечная петля в коде или при каких-то обстоятельствах вы повесите процессор делением на ноль — жмите перезагрузку и исправляйте код.
И всё же
Ардуино — это кайф: вы с помощью кода можете управлять физическим миром, моторами, лампами и электродеталями. Можно создать умную розетку; можно собрать умный замок для сейфа; можно сделать детектор влажности почвы, который будет включать автоматический полив. И всё это — на довольно понятном, читаемом и компактном языке C++, на который сверху ещё надета удобная библиотека для железа. Прекрасный способ провести выходные.
Какие ещё языки используют для Arduino
Но чу! Под Arduino можно писать и на других языках!
С. Как и С++, Си легко можно использовать для программирования микроконтроллеров Arduino. Только если С++ не требует никаких дополнительных программ, то для С вам понадобится WinAVR, чтобы правильно перевести код в язык, понятный контроллерам AVR.
Python. Было бы странно, если бы такому универсальному языку не нашлось применения в робототехнике. Берёте библиотеки PySerial и vPython, прикручиваете их к Python и готово!
Java. Принцип такой же, как в Python: берёте библиотеки для работы с портами и контроллерами и можно начинать программировать.
А вообще Arduino работает на контроллерах AVR, и прошить их можно любым кодом, который скомпилирован под это железо. Всё, что вам нужно — найти библиотеку для вашего любимого языка, которая преобразует нужные команды в машинный код для AVR.
Источник
Структура программы на языке C++ для Arduino
Рассмотрим пример минимально возможной программы на C++ для Arduino, которая ничего не делает:
Разберёмся что здесь написано и почему это обязательно: почему нельзя обойтись просто пустым файлом.
Из чего состоит программа
Блоки бывают разных видов и какой из них когда будет исполняться зависит от внешних условий. В примере минимальной программы вы можете видеть 2 блока. В этом примере блоки называются определением функции. Функция — это просто блок кода с заданным именем, которым кто-то затем может пользоваться из-вне.
Классика жанра: мигающий светодиод
Давайте теперь дополним нашу программу так, чтобы происходило хоть что-то. На Arduino, к 13-му пину подключён светодиод. Им можно управлять, чем мы и займёмся.
Скомпилируйте, загрузите программу. Вы увидите, что каждую секунду светодиод на плате помигивает. Разберёмся почему этот код приводит к ежесекундному миганию.
Каждое выражение — это приказ процессору сделать нечто. Выражения в рамках одного блока исполняются одно за другим, строго по порядку без всяких пауз и переключений. То есть, если мы говорим об одном конкретном блоке кода, его можно читать сверху вниз, чтобы понять что делается.
Если пронумеровать выражения по порядку, как они исполняются, получится:
Результат от этого не изменится ни на йоту: после компиляции вы получите абсолютно эквивалентный бинарный файл.
Что делают выражения
Теперь давайте попробуем понять почему написанная программа приводит в итоге к миганию светодиода.
Как известно, пины Arduino могут работать и как выходы и как входы. Когда мы хотим чем-то управлять, то есть выдавать сигнал, нам нужно перевести управляющий пин в состояние работы на выход. В нашем примере мы управляем светодиодом на 13-м пине, поэтому 13-й пин перед использованием нужно сделать выходом.
Это делается выражением в функции setup :
Уточняющие значения, такие как 13 и OUTPUT называются аргументами функции. Совершенно не обязательно, что у всех функций должно быть по 2 аргумента. Сколько у функции аргументов зависит от сути функции, от того как её написал автор. Могут быть функции с одним аргументом, тремя, двадцатью; функции могут быть без аргументов вовсе. Тогда для их вызова круглые скобка открывается и тут же закрывается:
На самом деле, вы могли заметить, наши функции setup и loop также не принимают никакие аргументы. И загадочное «нечто» точно так же вызывает их с пустыми скобками в нужный момент.
Вернёмся к нашему коду. Итак, поскольку мы планируем вечно мигать светодиодом, управляющий пин должен один раз быть сделан выходом и затем мы не хотим вспоминать об этом. Для этого идеологически и предназначена функция setup : настроить плату как нужно, чтобы затем с ней работать.
Перейдём к функции loop :
Как только сон окончен, функция loop завершается. По факту завершения «нечто» тут же вызывает её ещё раз и всё происходит снова: светодиод поджигается, горит, гаснет, ждёт и т.д.
Если перевести написанное на русский, получится следующий алгоритм:
Источник
Подключение и программирование Ардуино для начинающих
Изучение микроконтроллеров кажется чем-то сложным и непонятным? До появления Арудино – это было действительно не легко и требовало определенный набор программаторов и прочего оборудования.
Что такое Arduino?
Это своего рода электронный конструктор. Изначальная задача проекта – это позволить людям легко обучаться программированию электронных устройств, при этом уделяя минимальное время электронной части.
Сборка сложнейших схем и соединение плат может осуществляться без паяльника, а с помощью перемычек с разъёмными соединениями «папа» и «мама». Так могут подключаться как навесные элементы, так и платы расширения, которые на лексиконе ардуинщиков зовут просто «Шилды» (shield).
Какую первую плату Arduino купить новичку?
Базовой и самой популярной платой считается Arduino Uno. Эта плата размером напоминает кредитную карту. Довольно крупная. Большинство шилдов которые есть в продаже идеально подходят к ней. На плате для подключения внешних устройств расположены гнезда.
В отечественных магазинах на 2017 год её цена порядка 4-5 долларов. На современных моделях её сердцем является Atmega328.
Изображение платы ардуино и расшифровка функций каждого вывода, Arduino UNO pinout
Микроконтроллер на данной плате это длинна микросхема в корпусе DIP28, что говорит о том, что у него 28 ножек.
Следующая по популярности плата, стоит почти в двое дешевле предыдущей – 2-3 доллара. Это плата Arduino Nano. Актуальные платы построены том же Atmega328, функционально они аналогичны с UNO, различия в размерах и решении согласования с USB, об этом позже подробнее. Еще одним отличием является то, что для подключения к плате устройств предусмотрены штекера, в виде иголок.
Количество пинов (ножек) этой платы совпадает, но вы можете наблюдать что микроконтроллер выполнен в более компактном корпусе TQFP32, в корпусе добавлены ADC6 и ADC7, другие две «лишних» ножки дублируют шину питания. Её размеры довольно компактные – примерно, как большой палец вашей руки.
Третья по популярности плата – это Arduino Pro Mini, на ней нет USB порта для подключения к компьютеру, как осуществляется связь я расскажу немного позже.
Сравнение размеров Arduino Nano и Pro Mini
Это самая маленькая плата из всех рассмотренных, в остальном она аналогична предыдущим двум, а её сердцем является по-прежнему Atmega328. Другие платы рассматривать не будем, так как это статья для начинающих, да и сравнение плат – это тема отдельной статьи.
Если UNO удобна для макетирования, то Nano и Pro Mini удобны для финальных версий вашего проекта, потому что занимают мало места.
Как подключить Arduino к компьютеру?
Arduino Uno и Nano подключаются к компьютеру по USB. При этом нет аппаратной поддержки USB порта, здесь применено схемное решение преобразования уровней, обычно называемое USB-to-Serial или USB-UART (rs-232). При этом в микроконтроллер прошит специальный Arduino загрузчик, который позволяет прошиваться по этим шинам.
В Arduino Uno реализована эта вязь на микроконтроллере с поддержкой USB – ATmega16U2 (AT16U2). Получается такая ситуация, что дополнительный микроконтроллер на плате нужен для прошивки основного микроконтроллера.
В Arduino Nano это реализовано микросхемой FT232R, или её аналогом CH340. Это не микроконтроллер — это преобразователь уровней, этот факт облегчает сборку Arduino Nano с нуля своими руками.
Обычно драйвера устанавливаются автоматически при подключении платы Arduino. Однако, когда я купил китайскую копию Arduino Nano, устройство было опознано, но оно не работало, на преобразователе была наклеена круглая наклейка с данными о дате выпуска, не знаю нарочно ли это было сделано, но отклеив её я увидел маркировку CH340.
До этого я не сталкивался с таким и думал, что все USB-UART преобразователи собраны на FT232, пришлось скачать драйвера, их очень легко найти по запросу «Arduino ch340 драйвера». После простой установки – всё заработало!
Через этот же USB порт может и питаться микроконтроллер, т.е. если вы подключите его к адаптеру от мобильного телефона – ваша система будет работать.
Что делать если на моей плате нет USB?
Плата Arduino Pro Mini имеет меньшие габариты. Это достигли тем что убрали USB разъём для прошивки и тот самый USB-UART преобразователь. Поэтому его нужно докупить отдельно. Простейший преобразователь на CH340 (самый дешевый), CPL2102 и FT232R, продаётся стоит от 1 доллара.
При покупке обратите внимание на какое напряжение рассчитан этот переходник. Pro mini бывает в версиях 3.3 и 5 В, на преобразователях часто расположен джампер для переключения напряжения питания.
При прошивке Pro Mini, непосредственно перед её началом необходимо нажимать на RESET, однако в преобразователях с DTR это делать не нужно, схема подключения на рисунке ниже.
Стыкуются они специальными клеммами «Мама-Мама» (female-female).
Собственно, все соединения можно сделать с помощью таких клемм (Dupont), они бывают как с двух сторон с гнездами, так и со штекерами, так и с одной стороны гнездо, а с другой штекер.
Как писать программы для Arduino?
Для работы со скетчами (название прошивки на языке ардуинщиков), есть специальная интегрированная среда для разработки Arduino IDE, скачать бесплатно её можно с официального сайта или с любого тематического ресурса, с установкой проблем обычно не возникает.
Так выглядит интерфейс программы. Писать программы можно на специально разработанном для ардуино упрощенном языке C AVR, по сути это набор библиотек, который называют Wiring, а также на чистом C AVR. Использование которого облегчает код и ускоряет его работу.
В верхней части окна присутствует привычное меню, где можно открыть файл, настройки, выбрать плату, с которой вы работаете (Uno, Nano и много-много других) а также открыть проекты с готовыми примерами кода. Ниже расположен набор кнопок для работы с прошивкой, назначение клавиш вы увидите на рисунке ниже.
В нижней части окна – область для вывода информации о проекте, о состоянии кода, прошивки и наличии ошибок.
Основы программирования в Arduino IDE
В начале кода нужно объявить переменные и подключить дополнительные библиотеки, если они имеются, делается это следующим образом:
#include biblioteka.h; // подключаем библиотеку с названием “Biblioteka.h”
#define peremennaya 1234; // Объявляем переменную со значением 1234
Команда Define дают компилятору самому выбрать тип переменной, но вы можете его задать вручную, например, целочисленный int, или с плавающей точкой float.
int led = 13; // создали переменную “led” и присвоили ей значение «13»
Программа может определять состояние пина, как 1 или 0. 1 –это логическая единица, если пин 13 равен 1, то напряжение на его физической ножке будет равняться напряжению питания микроконтроллера (для ардуино UNO и Nano – 5 В)
Запись цифрового сигнала осуществляется командой digitalWrite (пин, значение), например:
digitalWrite(led, high); //запись единицы в пин 13(мы его объявили выше) лог. Единицы.
Как вы могли понять обращение к портам идёт по нумерации на плате, соответствующей цифрой. Вот пример аналогичного предыдущему коду:
digitalWrite (13, high); // устанавливаем вывод 13 в едиицу
Часто востребованная функция задержки времени вызывается командой delay(), значение которой задаётся в миллисекундах, микросекунды достигаются с помощью
delayMicroseconds() Delay (1000); //микроконтроллер будет ждать 1000 мс (1 секунду)
Настройки портов на вход и выход задаются в функции void setup<>, командой:
pinMode(NOMERPORTA, OUTPUT/INPUT); // аргументы – название переменной или номер порта, вход или выход на выбор
Понимаем первую программу «Blink»
В качестве своеобразного «Hello, world» для микроконтроллеров является программа мигания светодиодом, давайте разберем её код:
В начале командой pinMode мы сказали микроконтроллеру назначить порт со светодиодом на выход. Вы уже заметили, что в коде нет объявления переменной “LED_BUILTIN”, дело в том, что в платах Uno, Nano и других с завода к 13 выводу подключен встроенный светодиод и он распаян на плате. Он может быть использован вами для индикации в ваших проектах или для простейшей проверки ваших программ-мигалок.
Далее мы установили вывод к которому подпаян светодиод в единицу (5 В), следующая строка заставляет МК подождать 1 секунду, а затем устанавливает пин LED_BUILTIN в значение нуля, ждет секунду и программа повторяется по кругу, таким образом, когда LED_BUILTIN равен 1 – светодиод(да и любая другая нагрузка подключенная к порту) включен, когда в 0 – выключен.
Всё работает и всё понятно? Тогда идём дальше!
Читаем значение с аналогового порта и используем прочитанные данные
Микроконтроллер AVR Atmega328 имеет встроенный 10 битный аналогово цифровой преобразователь. 10 битный АЦП позволяет считывать значение напряжение от 0 до 5 вольт, с шагом в 1/1024 от всего размаха амплитуды сигнала (5 В).
Чтобы было понятнее рассмотрим ситуацию, допустим значение напряжения на аналоговом входе 2.5 В, значит микроконтроллер прочитает значение с пина «512», если напряжение равно 0 – «0», а если 5 В – (1023). 1023 – потому что счёт идёт с 0, т.е. 0, 1, 2, 3 и т.д. до 1023 – всего 1024 значения.
Вот как это выглядит в коде, на примере стандартного скетча «analogInput»
Источник
Как написать скетч?
Послесловие к базовым урокам
Вот и закончился базовый курс уроков программирования Arduino. Мы с вами изучили самые базовые понятия, вспомнили (или изучили) часть школьной программы по информатике, изучили большую часть синтаксиса и инструментов языка C++, и вроде бы весь набор Ардуино-функций, который предлагает нам платформа. Подчеркну – мы изучили C++ и функции Ардуино, потому что никакого “языка Arduino” нет, это ложное понятие. Arduino программируется на C или ассемблере, а платформа предоставляет нам всего лишь несколько десятков удобных функций для работы с микроконтроллером, именно функций, а не язык. Теперь перед нами чистый лист блокнота Arduino IDE и желание творить и программировать, давайте попробуем!
Структура программы
Прежде, чем переходить к реальным задачам, нужно поговорить о некоторых фундаментальных вещах. Микроконтроллер, как мы обсуждали в самом начале пути, это комплексное устройство, состоящее из вычислительного ядра, постоянной и оперативной памяти и различных периферийных устройств (таймеры/счётчики, АЦП и проч.). Обработкой нашего с вами кода занимается именно ядро микроконтроллера, оно раздаёт команды остальным “железкам”, которые в дальнейшем могут работать самостоятельно. Ядро выполняет различные команды, подгоняемое тактовым генератором: на большинстве плат Arduino стоит генератор с частотой 16 МГц. Каждый толчок тактового генератора заставляет вычислительное ядро выполнить следующую команду, таким образом Ардуино выполняет 16 миллионов операций в секунду. Много ли это? Для большинства задач более чем достаточно, главное использовать эту скорость с умом. Зачем я об этом рассказываю: микроконтроллер может выполнить только одну задачу в один момент времени, так как у него только одно вычислительное ядро, поэтому реальной “многозадачности” нет и быть не может, но за счёт большой скорости выполнения ядро может выполнять задачи по очереди, и для человека это будет казаться многозадачностью, ведь что для нас “раз Миссисипи“, для микроконтроллера – 16 миллионов действий! Есть всего два варианта организации кода:
“Многозадачность” с yield()
Таким же образом можно опрашивать энкодер или другие датчики, которые требуют максимально частого опроса. Не менее жизненным будет пример со сценарием движения шагового мотора или плавного движения сервопривода, которые требуют максимально частого вызова функций опроса. Рассмотрим абстрактный пример движения мотора по нескольким заданным точкам, функция вращения мотора должна вызываться как можно чаще (так сделано почти во всех библиотеках для шаговых моторов):
Таким образом мы быстро и просто расписали “траекторию” движения для шагового мотора по времени, не используя какие-то таймеры или библиотеки таймеров. Для более сложных программ, например с движением двух моторов, такой фокус уже может не пройти и проще работать с таймером.
“Многозадачность” с millis()
Первым делом внесём такую оптимизацию: сократим код вдвое и избавимся от одной задержки, используя флаг:
Хитрый ход, запомните его! Такой алгоритм позволяет переключать состояние при каждом вызове. Сейчас наш код всё ещё заторможен задержкой в 1 секунду, давайте от неё избавимся:
Что здесь происходит: цикл loop() выполняется несколько сотен тысяч раз в секунду, как ему и положено, потому что мы убрали задержку. Каждую свою итерацию мы проверяем, не настало ли время переключить светодиод, не прошла ли секунда? При помощи этой конструкции и создаётся нужная многозадачность, которой хватит для 99% всех мыслимых проектов, ведь таких “таймеров” можно создать очень много!
Данный код всё ещё мигает светодиодом раз в секунду, но помимо этого он с разными промежутками времени отправляет сообщения в последовательный порт. Если открыть его, можно увидеть следующий текст:
Это означает, что у нас спокойно работают 4 таймера с разным периодом срабатывания, работают “параллельно”, обеспечивая нам многозадачность: мы можем выводить данные на дисплей раз в секунду, и заодно опрашивать датчик 10 раз в секунду и усреднять его показания. Хороший пример для первого проекта! Обязательно вернитесь к уроку о функциях времени, там мы разобрали несколько конструкций на таймере аптайма!
“Многозадачность” с прерываниями таймера
Для критичных по времени задач можно использовать выполнение по прерыванию таймера. Какие это могут быть задачи:
Настройка таймера на нужную частоту и режим работы – непосильная для новичка задача, хоть и решается в 2-3 строчки кода, поэтому предлагаю использовать библиотеки. Для настройки прерываний по таймеру 1 и 2 есть библиотеки TimerOne и TimerTwo. Мы сделали свою библиотеку, GyverTimers, в которой есть также таймер 0 (для программирования без использования Arduino.h), а также все таймеры на Arduino MEGA, а их там целых 6 штук. Ознакомиться с документацией и примерами можно на странице библиотеки. Сейчас рассмотрим простой пример, в котором “параллельно” выполняющемуся Blink будут отправляться данные в порт. Пример оторван от реальности, так делать нельзя, но он важен для понимания самой сути: код в прерывании выполнится в любом случае, ему безразличны задержки и мёртвые циклы в основном коде.
Переключение задач
Важнейшим инструментом по организации логики работы программы является так называемый конечный автомат (англ. State Machine) – значение, которое имеет заранее известный набор состояний. Звучит сложно, но на самом деле речь идёт об операторе swith и переменной, которая переключается кнопкой или по таймеру. Например:
Таким образом организуется выбор и выполнение выбранных участков кода. Переключение переменной mode тоже должно быть сделано не просто так, как в примере выше, тут есть варианты:
Ограничить диапазон при увеличении можно несколькими способами. Способы абсолютно одинаковые по своей сути, но записать можно по разному:
Аналогично при уменьшении:
Переключение с первой на последнюю и обратно делается точно так же:
Рассмотрим несколько готовых примеров на базе библиотеки GyverButton:
Флаги
Логические переменные, или флаги, являются очень важным инструментом организации логики работы программы. В глобальном флаге можно хранить “состояние” составляющих программы, и они будут известны во всей программе, и во всей же программе могут быть изменены. Немного утрированный пример:
Состояние глобального флага может быть прочитано в любых других функциях и местах программы, таким образом можно сильно упростить код и избавиться от лишних вызовов. При помощи флага можно организовать однократное выполнение блока кода по какому-то событию:
Также флаг можно инвертировать, что позволяет генерировать последовательность 10101010 для переключения каких-то двух состояний:
Флаги – очень мощный инструмент, не забывайте о них!
Избавляемся от циклов и задержек
Как мигать светодиодом без задержки мы обсуждали выше. А как избавиться от цикла? Очень просто – цикл заменяется на счётчик и условие. Пусть у нас есть цикл for, выводящий значение счётчика:
Для избавления от цикла нам нужно сделать свою переменную-счётчик, поместить всё это дело в другой цикл (например, в loop) и самостоятельно увеличивать переменную и проверять условие:
И всё. А как быть, если в цикле была задержка? Вот пример
Как соединить несколько скетчей?
Чтобы соединить несколько проектов в один, нужно разобраться со всеми возможными конфликтами:
Можно внести все правки в схемы и программы объединяемых проектов, чтобы они не конфликтовали. Далее приступаем к сборке общей программы:
Раньше у нас было два (или больше) отдельно работающих проекта. Теперь наша задача как программиста – продумать и запрограммировать работу этих нескольких проектов в одном, и тут ситуаций уже бесконечное множество:
В большинстве случаев нельзя просто так взять и объединить содержимое loop() из разных программ, я надеюсь все это понимают. Даже мигалку и пищалку таким образом объединить не получится, если изначально код был написан с задержками или замкнутыми циклами.
Пример “Метеостанция”
Сила Arduino как конструктора заключается в том, что абсолютно по любой железке вы сможете найти в Гугле подробное описание, библиотеку, схему подключения и пример работы: полностью готовый набор для интеграции в свой проект! Вернёмся к нашим метео-часам и попробуем “собрать” такой проект из скетчей-примеров, ведь именно для этого примеры и нужны! Нам понадобится:
Начинаем гуглить информацию по подключению и примеру для каждой железки:
Из уроков из Гугла мы узнаём такую важную информацию, как схемы подключения: дисплей и часы подключаются к шине i2c, а датчик ds18b20 можно подключить в любой другой пин. Схема нашего проекта: Качаем библиотеки для наших модулей и устанавливаем. Библиотеку дисплея нам дают прямо в статье: https://iarduino.ru/file/134.html, библиотеку для часов по своему опыту советую RTClib (та, что в статье – не очень удобная). В статье про датчик температуры нам рассказали про библиотеку DallasTemperature.h, ссылку – не дали. Ну чтож, поищем сами “DallasTemperature.h”, найдём по первой ссылке. Для неё нужна ещё библиотека OneWire, ссылку на неё дали в статье про термометр. Итого у нас должны быть установлены 4 библиотеки. Сейчас наша цель – найти рабочие примеры для каждой железки, убедиться в их работоспособности и выделить для себя минимальный набор кода для управления модулем, это бывает непросто – в статьях бывают ошибки и просто нерабочий код: эти статьи чаще всего являются копипастой от людей, далёких от темы. Я взял пример работы с дисплеем из статьи, а вот часы и термометр пришлось смотреть в примерах библиотеки. Немного причешем примеры, оставим только нужные нам функции получения значений или вывода, я оставил всё что мне нужно в setup() :
Источник