Близится Новый год, а гирлянда на ёлку не готова. В комоде уложена старая, её использовали уже пять раз и хочется чего-то нового. Предлагаю сделать свою, на популярной плате STM32 BluePIll в связке с адресными светодиодами. Это история с открытым концом. Если читателю идея покажется интересной, будет прошивка на git с реализацией интересных задумок; в противном случае, придётся купить готовую на маркетплейсе. Но мы же этого не допустим?
Предыстория
Волей случая довелось программировать приборную панель, в которой индикаторами режимов работы выступали адресные светодиоды WS2812B. На этапе прототипа нужно было регулировать цвет и яркость индикаторов для проверки оптических свойств световых фильтров. Так появилась удобная схема для экспериментов: терминал ПК – STM32 BluePIll – адресные светодиоды. Первоначальная отладка прошивки проводилась на матрице 8x8, для которой, забавы ради, были написаны простые сценарии: бегущий огонь, имитация тлеющих углей, случайный выбор цвета и яркости. И вот вместо приборной панели мы получаем макет светодиодной гирлянды.
Техническая составляющая
Протокол адресных светодиодов
Для светодиодов WS2812B сигнал сброса, логической единицы и нуля задаются временными таймаутами. Поэтому необходим «конвертер», который будет преобразовывать цифру во временной импульс. Время передачи одного бита составляет 1,25 мкс.
![Рисунок 2 - Протокол адресного светодиода WS2812B. Источник изображения [2]. Рисунок 2 - Протокол адресного светодиода WS2812B. Источник изображения [2].](https://habrastorage.org/r/w780/getpro/habr/upload_files/1fc/928/a10/1fc928a1050e63e8443dfd2145654808.png)
Для этой цели удобно использовать таймер, работающий в режиме широтной импульсной модуляции.
![Рисунок 3 - Схема работы таймера через DMA. Источник изображения [2]. Рисунок 3 - Схема работы таймера через DMA. Источник изображения [2].](https://habrastorage.org/r/w780/getpro/habr/upload_files/f31/cc6/3c0/f31cc63c00d606d29b0971177729e491.png)
При работе таймера в режиме ШИМ, единичный импульс формируется значением регистра CCR. Уровень логического нуля или единицы при значении CNT < CCR устанавливается программно. Соответственно необходимо:
1) Значение регистра ARR установить так, чтобы счет от 0 до ARR проходил за время передачи одного бита (1,25 мкс);
2) Записывать значение регистра CCR так, чтобы одно соответствовало либо значению «1» либо «0» по протоколу адресных светодиодов.
Для примера возьмем байт 0x05 (0000 0101). Младший бит равен 1, его необходимо отправить временной последовательностью «1». Для этого в регистр CCR необходимо записать число, соответствующее времени «1». Для нуля записываем в CCR число, соответствующее времени «0». И так далее. Регистра ARR при этом отсчитывает время периода 1,25 мкс.
Таким образом, для управления гирляндой необходимо сформировать массив, в котором байт каждого цвета разобран на биты, которые в свою очередь заменены магическими (рассчитанными в зависимости от тактовой частоты) числами, соответствующими временным интервалам протокола WS2812B. Этот массив передаем в таймер через DMA.
Линеаризация яркости
Управление яркостью свечения светодиодов требует отдельного внимания. Дело в том, что глаз воспринимает изменение яркости светодиода непропорционально изменению подаваемой на него мощности. Соотношение между световым стимулом – яркостью и уровнем вызываемого ощущения упрощенно можно выразить следующей формулой:
где:
B – яркость воспринимаемого ощущения;
N – значение яркости (мощности) светодиода.
Эта формула, определяющая зависимость уровня зрительного ощущения от яркости действующего излучения представляет собой психофизический закон Вебера-Фехнера. Чтобы получить линейное изменение яркости необходимо составить массив с логарифмами N, при этом по порядку возрастания индекса массива, значения данных логарифмов должны представлять линейную функцию. График такого расчета представлен на рисунке:

Точки линии «Эталон» вычислены математически (функция y = k*x), точки линии«Яркость» подобранные под такие (целые) значения, которые возможно записать в светодиод. Сценарии свечения, наподобие «градиент яркости» или «плавное затухание» на светодиодной гирлянде требуют корректировки данных согласно приведенному выше графику. Стоит отметить, что «цвета» светодиодов WS2812B также светят неодинаково (зеленый ярче остальных) и по идее, тоже требуют индивидуальной калибровки. Но мы не станем на текущем этапе так углубляться.
Генератор случайных чисел
Реализация сценария случайного свечения требует TRNG (генератор истинных случайных чисел). Но в микроконтроллере STM32F103 такого генератора нет. В качестве источника «шума» предлагаю использовать канал АЦП (без вывода на ножку), данные на котором считаем достаточно случайными (в младшем значащем разряде). Считанные с АЦП значения прогоняются через CRC полином. Для наших целей результат считаем достаточно случайным. Вот результат проверки:

Modbus RTU
STM32F103 помимо невысокой цены радует поддержкой интерфейса USB, который будем использовать для связи с ПК. Выбор протокола Modbus RTU обосновывается наличием готовых библиотек, существенно ускоряющих процесс разработки. Для ёлочный гирлянды такое решение кажется слегка тяжеловесным, оно вместе с тем оно универсально. Регистровая модель Modbus RTU в целом несложная, её легко расширять под новый функционал. В текущий момент в устройстве тринадцать регистров.
Регистр |
Описание |
По умолчанию |
|
0 |
DEVICE_TYPE |
Тип устройства |
3 |
1 |
PRG_HW_VERSION |
Версия прошивки и платы |
1 |
2 |
MODBUS_ADDRESS |
Modbus адрес устройства |
1 |
3 |
MODBUS_SPEED |
Скорость обмена через Modbus: 0 – 1200, 1 – 2400, 2 – 4800, 3 – 9600, 4 – 19200, 5 – 38400, 6 – 57600, 7 – 115200 |
3 |
4 |
DEVICE_ERRORS |
Ошибки устройства |
|
5 -9 |
Резерв |
|
|
10 |
LEDS_COUNT |
Число подключенных светодиодов |
|
11 |
LEDS_BRIGHTNESS |
Яркость свечения светодиодов, %: 0 – минимальная, 100 – максимальная |
|
12 |
LEDS_MODE |
0 – светодиоды выключены, 1 – красный, 2 – зеленый, 3 – синий, 4 – белый, 5 – желтый, 6 – бегущий огонь (синий на жёлтом), 7 – случайный выбор цвета и яркости, 8 – имитация раскаленных углей, 9 – градиент красного цвета, 10 – круговая смена цветов, 11 – режим «Арбуз». |
|
DFU загрузчик
DFU загрузчик нужен исключительно для удобства обновления прошивки. К счастью, писать самостоятельно его не нужно, уже есть готовый. Особенностью данного загрузчика является то, что он размещается в конце Flash памяти, а значит прошивку можно компилировать без смещения адресов. Для первоначальной записи загрузчика в BluePill нужен внешний программатор. Впоследствии, можно обновлять прошивку через STM32Cube Programmer, подключаясь к плате через USB.
Терминал на Python
Последний шаг подготовительных работ – небольшой терминал, написанный на Ptyhon, для управления гирляндой. Здесь мы можем задать число светодиодов, а также их цвет (выбрать сценарий) и яркость.
Вот примеры некоторых режимов работы гирлянды:

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

Обязательно используйте внешний сетевой адаптер с выходным напряжением 5 В, так как светодиоды WS2812B могут потреблять значительный ток.
Творческая составляющая
Рассмотрев технические особенности проекта, можно перейти к основной цели публикации – поиску творческой составляющей. Идея гирлянды на адресных светодиодах не нова, рынок завален всевозможными вариантами: Bluetooth, бесконечные вариации миганий, генерация изображений, мерцание под музыку, шторка с каплями, бахрома и т.д.
Что может предложить DIY проект? Озвучу возможные идеи:
1. Обучение с телевизионного пульта;
2. Радиоканал с секретным режимом;
3. Имитация неисправности;
4. Датчик освещенности;
5. Работа от АКБ;
….
А может вовсе не нужна гирлянда, когда в распоряжении светодиодная матрица?
Как было сказано в начале публикации – это история с открытым концом. Интересно, во что можно развить проект, который начался с индикаторов приборной панели. Хорошие идеи (реальные для реализации на BluePill) будут добавлены к текущей прошивке и терминалу, актуальные версии которых можно скачать в git. Скачивайте, заливайте на BluePill, пишите идеи в комментариях.
Ресурсы
1. Прошивка и терминал для STM32 BluePill;
2. Протокол WS2812B без пустых циклов и прерываний;