LED Middle — мигание без delay()
Управление несколькими светодиодами одновременно без delay() — так, чтобы
мигание одного не мешало другому и не блокировало остальную программу
(например, чтение датчика или работу по Wi-Fi).
Components/2. LED_middle — управление светодиодами (мигание, бегущий огонь)
Модуль учит управлять несколькими светодиодами одновременно без delay() —
то есть так, чтобы мигание одного светодиода не мешало миганию другого и не
блокировало остальную программу (например, чтение показаний с датчика или
работу по Wi-Fi).
Это компонент-актуатор (микроконтроллер только включает/выключает пины),
а не датчик: здесь нет обмена данными по шине (I2C/UART), поэтому нет и
классического “показания датчика”. Диагностика в этом модуле отвечает на
другой вопрос: “не забыл ли я вызывать код обновления в loop()?” — подробнее
в THEORY.md.
Структура
Components/2. LED_middle/
├── include/LedController.h ← продвинутый слой: класс (ООП)
├── src/LedController.cpp ← продвинутый слой: реализация на millis()
├── include/simple_api.h ← педагогический слой: фасад из функций
├── src/simple_api.cpp ← педагогический слой: прячет указатели/массивы
├── src/main.cpp ← тестовый стенд продвинутого слоя (диагностика)
├── example_sketch.ino ← пример для ученика (использует simple_api)
├── README.md ← этот файл
├── THEORY.md ← физика светодиода, math резистора, разбор ошибок
├── WIRING.md ← какие пины безопасны на каких платах, схема
└── PREZ.md ← краткая презентация модуля (5 слайдов-тезисов)Два слоя API — и почему их два
| Слой | Кто использует | Что видно |
|---|---|---|
LedController (класс) | продвинутые ученики, Combined-Projects | конструкторы, указатели, .update() вызывается вручную на каждом объекте |
simple_api (фасад из функций) | новички, 5 класс | только процедурные вызовы вроде blinkSingle(13, 200, 200), без единого указателя на виду |
Общее архитектурное правило репозитория — один класс-драйвер без второго
слоя-фасада (см. firmware/COMPONENT_STANDARD.md). Здесь это правило нарушено
осознанно: simple_api — не техническая надстройка “на всякий случай”, а часть
учебной программы для самых начинающих учеников, которые ещё не проходили
классы и указатели. Внутри фасада по-прежнему работает единственный класс
LedController — второй реализации логики мигания нет.
Быстрый старт (педагогический слой)
#include "simple_api.h"
void setup() {
initLed(2);
blinkSingle(2, 200, 200); // мигает каждые 200 мс
}
void loop() {
updateLeds(); // обязательно один раз за итерацию loop()
}Полный разбор построчно — в example_sketch.ino и THEORY.md.
API фасада (simple_api.h)
| Функция | Что делает | Пример вызова |
|---|---|---|
initLed(pin) | подготовить один светодиод | initLed(2); |
blinkSingle(pin, onMs, offMs) | мигание одного светодиода | blinkSingle(2, 200, 200); |
stopLed(pin) | выключить и остановить мигание | stopLed(2); |
isLedAlive(pin) | вызывается ли updateLeds() достаточно часто для этого пина | isLedAlive(2); |
initLedGroup(groupId, pins[], count) | создать группу из нескольких светодиодов | initLedGroup(0, pins, 5); |
blinkArray(groupId, onMs, offMs) | одновременное мигание всей группой | blinkArray(0, 300, 300); |
runningLights(groupId, stepMs) | эффект “бегущий огонь” | runningLights(0, 100); |
stopGroup(groupId) | остановить группу | stopGroup(0); |
isGroupAlive(groupId) | вызывается ли updateLeds() достаточно часто для группы | isGroupAlive(0); |
updateLeds() | обязательно вызывать 1 раз в loop() | updateLeds(); |
Лимиты (можно менять в simple_api.cpp)
MAX_SINGLE = 6— сколько разных одиночных пинов можно завести одновременно.MAX_GROUPS = 4— сколько разных групп (бегущих огней) можно завести одновременно.
Это не аппаратное ограничение платы, а разумный потолок для учебного стенда (столько отдельных светодиодов реально развести на одной макетке на занятии).
Подключение и сборка
Схема подключения, конкретные номера пинов и обоснование их выбора — в WIRING.md. Проект собирается PlatformIO под три окружения:
cd "Components/2. LED_middle"
pio run -e esp32dev -e esp32s3 -e esp32c6