Добрый день, уважаемый читатель!
Казалось бы – зачем нужна какая-то библиотека для мигания светодиодом на ESP? Мигание светодиодом сложности особой не представляет. Делов-то – “дергай” соответствующий вывод микроконтроллера, вот светодиод и мигает. Мало того – все “демки” для микроконтроллеров с этого начинаются, своеобразный “Hello, world” для ардуинщиков.
Однако всё меняется, когда хочется “выжать” из единственного светодиода максимум полезной информации. Видели когда-нибудь как работает светодиод на автосигнализации? Когда все “спокойно” – мигнет кратенько один раз в несколько секунд и всё. Если была тревога – по количеству вспышек уже при подходе к автомобилю можно определить, что случилось. Этот же метод обозначения событий и неисправностей используется и на множестве других устройств – смарткассах, принтерах и т.д.
Да еще при всем при программировании желательно не особо отвлекаться от основной задачи. Конечно, описанный выше алгоритм можно реализовать на циклах и задержках, но это муторно и долго. И нужно постоянно помнить о светодиодах и текущих режимах мигания. Вот бы сделать так, что бы “отправил светодиоду команду, как мигать – и забыл“.
Описанная в данной статье библиотека как раз и решает обе задачи.
Важно! Данная версия библиотеки предназначена для работы на ESP32, то есть под FreeRTOS. Написана и отлажена на PlatformIO, но на Arduino IDE так же будет работать (опять же только для ESP32). Примеры скетчей прикреплены к архиву. Версию для Arduino можно найти здесь, она немного отличается по принципам работы, но результат получается тот же самый.
Возможности и описание работы:
- Асинхронное управление светодиодами по принципу “отправил команду и забыл”. Для управления каждым отдельным светодиодом создается отдельная задача FreeRTOS с минимально возможным стеком. При этом потребление ресурсов процессора происходит в основном только в момент переключения светодиода или обработки команды, в остальное время задача игнорируется менеджером задач FreeRTOS. То есть нагрузка на процессор для десятка светодиодов не намного отличается от одного
- Возможные режимы работы:
- lmOff – светодиод выключен постоянно
- lmOn – светодиод включен постоянно
- lmFlash (quantity, duration, interval) – мигнуть заданное количество раз с заданными длительностью и периодом, а затем выключить
- lmBlinkOn (quantity, duration, period) – мигать постоянно с заданными длительностью и периодом. Если указано количество quantity > 1, то светодиод будет мигать сериями вспышек. Для равномерного мигания (меандром) необходимо указать длительность равной периоду и quantity = 1
- lmBlinkOff – отключить мигание
- Имеется возможность принудительно подавить вспышки светодиода на какое-то время. Например, можно гасить светодиоды на устройствах в ночное время, дабы не мешать сну.
- Возможно включение светодиода как с помощью установки высокого уровня, так и низкого (в зависимости от схемы подключения светодиода). Кроме того, поддерживается работа не только с GPIO микроконтроллера, но и управление светодиодами через I2C платы расширения типа PCF8574 с помощью пользовательской функции обратного вызова.
- “Системный” светодиод для отображения состояния устройства. Системный светодиод удобен тем, что “о нем заранее известно” другим библиотекам, и можно отправлять команды из библиотеки подключения к WiFi, MQTT, Telegram и т.д. Управление светодиодом можно как по аналогии с “обычными” светодиодами, так и с помощью установки специальных статусов (заранее предустановленные режимы мигания):
- SYSLED_ERROR – “общая” ошибка
- SYSLED_WARNING – предупреждение
- SYSLED_WIFI_CONNECTED – подключение к WiFi точке доступа установлено
- SYSLED_WIFI_INET_AVAILABLE – интернет доступен (можно определить с помощью ping-а)
- SYSLED_WIFI_ERROR – ошибка подключения к WiFi (точка доступа не доступна или авторизация не проходит)
- SYSLED_MQTT_ERROR – не удается подключиться к MQTT-брокеру или отправить данные
- SYSLED_TELEGRAM_ERROR – не удается отправить данные в telegram-канал
- SYSLED_OTHER_PUB_ERROR – не удается отправить данные на другие ресурсы (ThingSpeak и т.д.)
Режим мигания является “запоминаемым”. Достаточно отправить светодиоду команду lmBlinkOn, и этот режим мигания будет автоматически восстанавливаться после любых lmOn+lmOff и (или) lmFlash автоматически. Это позволяет не задумываться о том, какой режим мигания был установлен, если возникает необходимость срочно помигать светодиодиком для индикации каких либо событий. Чтобы отключить мигание совсем – необходимо отправить команду lmBlinkOff. Например, у меня “нормальный” режим работы обозначается редкими одиночными вспышками один раз в 3 секунды. В случае какого-либо сбоя в работе (нет wifi, например) – режим мигания меняется. Если необходимо “обозначить” отправку данных на mqtt-брокер я просто отправляю lmOn в начале передачи пакета, и lmOff в конце. Можно также использовать команду на серию вспышек lmFlash для большей заметности. Когда задача получит команду lmOff (либо серия будет завершена), она автоматически восстановит последний режим мигания, если он был активирован.
Пример:
lmOn(); // светодиод включен lmOff(); // светодиод выключен lmFlash(3, 100, 500); // светодиод мигнет три раза с длительностью 100 мс и паузой между вспышками 500 мс, после чего погаснет lmBlinkOn(2, 100, 5000); // светодиод начинает мигать сериями по 2 вспышки с периодом 100 мс и паузой между сериями 5000 мс lmOn(); // светодиод включен, мигание временно приостановлено lmOff(); // возвращаемся к последнему режиму мигания (серия по 2 вспышки 100 мс через 5 секунд) lmFlash(30, 100, 500); // светодиод мигнет 30 раз с длительностью 100 мс и паузой между вспышками 500 мс // после чего опять возвращаемся к последнему режиму мигания (серия по 2 вспышки 100 мс через 5 секунд) lmOff(); // ничего не измениться ;-) lmBlinkOn(1, 500, 500); // изменение режима мигания - непрерывное мигание 0,5 с включен / 0,5 с выключен lmBlinkOff(); // отключаем режим мигания, светодиод выключен
Разумеется, между командами должны быть какие-нибудь промежутки времени, чтобы светодиод успел отработать команды. Без этих пауз светодиод сразу выполнит их все и выключится (последняя команда).
Для демонстрации работы я собрал несложный пример на макетной плате. Схема не приведена, так как она элементарная – просто подключил четыре светодиода через токоограничительные резисторы к выводам контроллера.
Видео, демонстрирующее работу библиотеки:
- Красный светодиод на видео – “системный”. Он отображает “общее” состояние устройства. При включении имитирует подключение к WiFi (равномерное мигание). После соединения с WiFi (через 10 секунд) переходит в режим “проверка интернета / нет интернета” (две вспышки – пауза, две вспышки – пауза и т.д.). Еще через 5 секунд переходит в нормальный режим (редкие вспышки). Еще через некоторое время светодиод мигнет однократной серией для отображения передачи данных в эфир и вернется в “нормальный” режим.
- Синий светодиод просто мигает с частотой 1 Гц (0,5 секунды вспышка + 0,5 секунды пауза)
- Желтый светодиод тоже мигает постоянно, но уже длительность паузы в 4 раза больше длительности вспышки.
- Зеленый светодиод мигает сериями по 3 коротких (100 мс) вспышки через каждые 2 секунды.
Демонстрационный проект для платформы Arduino32
Пример программы для платформы Arduino32: (скачать архив вместе с вложенной библиотекой можно в конце статьи), использовать можно как в ArduinоIDE, так и в PlatformIO.
#include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "rLed32.h" #include "rLedSys32.h" void setup() { // Инициализация светодиодов // На GPIO 17 пусть будет "системный" светодиод, отображающий якобы подключение к WiFi ledSysInit(17, true, NULL); QueueHandle_t ledBlue = ledTaskCreate(16, true, "ledBlue", NULL); QueueHandle_t ledGreen = ledTaskCreate(19, true, "ledGreen", NULL); QueueHandle_t ledYellow = ledTaskCreate(18, true, "ledYellow", NULL); // Задаем параметры мигания для светодиодов ledTaskSend(ledBlue, lmBlinkOn, 1, 500, 500); ledTaskSend(ledGreen, lmBlinkOn, 3, 100, 2000); ledTaskSend(ledYellow, lmBlinkOn, 1, 250, 1000); // Ждем 10 секунд vTaskDelay(10000 / portTICK_PERIOD_MS); // "Подключились" к WiFi ledSysStateSet(SYSLED_WIFI_CONNECTED); vTaskDelay(5000 / portTICK_PERIOD_MS); ledSysStateSet(SYSLED_WIFI_INET_AVAILABLE); // Ждем 20 секунд vTaskDelay(20000 / portTICK_PERIOD_MS); // Разовые вспышки, после чего возвращаемся на предыдущий режим ledSysFlashOn(5, 100, 250); } void loop() { // Ничего }
Скомпилированный скетч занимает в памяти устройства около 215 Kb
Демонстрационный проект для платформы ESP-IDF
Пример программы для платформы PlatformIO: (скачать архив вместе с вложенной библиотекой можно в конце статьи)
#include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "rLed32.h" #include "rLedSys32.h" void app_main() { // Инициализация светодиодов // На GPIO 17 пусть будет "системный" светодиод, отображающий якобы подключение к WiFi ledSysInit(17, true, NULL); QueueHandle_t ledBlue = ledTaskCreate(16, true, "ledBlue", NULL); QueueHandle_t ledGreen = ledTaskCreate(19, true, "ledGreen", NULL); QueueHandle_t ledYellow = ledTaskCreate(18, true, "ledYellow", NULL); // Задаем параметры мигания для светодиодов ledTaskSend(ledBlue, lmBlinkOn, 1, 500, 500); ledTaskSend(ledGreen, lmBlinkOn, 3, 100, 2000); ledTaskSend(ledYellow, lmBlinkOn, 1, 250, 1000); // Ждем 10 секунд vTaskDelay(10000 / portTICK_PERIOD_MS); // "Подключились" к WiFi ledSysStateSet(SYSLED_WIFI_CONNECTED); vTaskDelay(5000 / portTICK_PERIOD_MS); ledSysStateSet(SYSLED_WIFI_INET_AVAILABLE); // Ждем 20 секунд vTaskDelay(20000 / portTICK_PERIOD_MS); // Разовые вспышки, после чего возвращаемся на предыдущий режим ledSysFlashOn(5, 100, 250); }
Скомпилированная программа без Arduino (только ESP-IDF) занимает в памяти практически столько же, как и в случае Arduino IDE (с точностью до округления)
Описание функций
Для создания задачи управления светодиодом используйте функцию ledTaskCreate:
ledQueue_t ledTaskCreate(const int8_t ledGPIO, const bool ledHigh, const char* taskName, ledCustomControl_t customControl);
где:
- ledGPIO – номер вывода, к которому подключен светодиод.
- ledHigh – true = включение с помощью установки на GPIO высокого уровня, false = с помощью установки на GPIO низкого уровня.
- taskName – имя задачи, например “ledRed” или “ledAlarm”.
- customControl – функция обратного вызова для управления адресными светодиодами или платами расширения (например PCF8574). Если не требуется, укажите NULL.
- Возвращаемое значение – указатель на экземпляр очереди, связанной с запущенной задачей (не задачи!).
После этого, можно отправлять команды на переключение режима работы в созданную очередь, используя следующую функцию:
bool ledTaskSend(ledQueue_t ledQueue, ledMode_t msgMode, uint16_t msgValue1, uint16_t msgValue2, uint16_t msgValue3);
где:
- ledQueue – указатель на очередь, созданную в ledTaskCreate(…).
- msgMode – устанавливаемый режим работы (или команда) lmXXXXX
- msgValue1, msgValue2, msgValue3 – передаваемые значения. Для некоторых команд значения не требуется, укажите 0 или любое другое число.
Инициализация встроенных GPIO микроконтроллера будет выполнена автоматически при создании задачи. Но при использовании customControl инициализация внешнего порта не производится, Вы должны сделать это самостоятельно.
Изменение режимов мигания для системного светодиода может быть осуществлено с помощью макросов предпроцессора, определенных в файле project_config.h. Файл project_config.h может отсутствовать, в этом случае будут использованы значения по умолчанию. Необходимо, чтобы этот файл при компиляции был доступен не только из главного скетча, но и из библиотек.
В PlatformIO можно указать компилятору, где искать файл project_config.h, с помощью опции build_flags = -Iкаталог в platformio.ini. Например, я поместил project_config.h в подкаталог src (там же, где и основной файл проекта). В этом случае я добавлю в platformio.ini следующие строки:
[env] build_flags = -Isrc
В Arduino IDE я пока не нашел другого способа, кроме как скопировать исходники библиотек и project_config.h в тот же каталог, где и располагается сам скетч. Это не очень удобно, но Arduino IDE и сама по себе не самый удобный инструмент.
Скачать библиотеку можно с помощью кнопки:
В архиве Вы также найдете примеры скетча для Arduino IDE и программы для PlatformIO – загляните в папку examples
Библиотека асинхронного управления светодиодами для ESP32 + демонстрационные проекты для PlatformIO и ArduinoIDE.
Версия для других контроллеров (с фреймворком Arduino):
То же самое, но реализовано на таймаутах с импользованием millis(). Требуется регулярное выполнение ledLoop() для каждого светодиода!Читать здесь.
Библиотека асинхронного управления светодиодами + демонстрационные проекты для PlatformIO и ArduinoIDE.
✳️ Другие мои библиотеки для PlatformIO и ArduinoIDE
Благодарю за внимание.
Пожалуйста, оцените статью: