"Как Новый год встретишь - так его и проведешь" - давно ставшая крылатой фраза, в какой-то степени заставляющая заранее готовиться к самому любимому празднику. И если такие традиционные атрибуты, как оливье и мандарины, незаменимы, то выбор различных инсталляций и украшений ежегодно заставляет ломать голову, радиолюбителям и электронщикам - в особенности.
Просмотренные в Интернете видео с поделками на "умных" светодиодах WS2812B сразу породили множество идей их применения. В конце ноября мне наконец-то пришла долгожданная, заказанная на eBay лента из 200 диодов. Доставка бесплатна, стоимость одного диода - около шести рублей. И так как до Нового года оставался всего месяц, я решил совместить приятное с полезным - и с подключением диодов разобраться, и к празднику подготовиться.

WS2812B - трехцветный светодиод с интегрированным драйвером и схемой, реализующей протокол управления. Имеет 4 вывода, как и "обычный" RGB-диод, однако их назначение отличается: два вывода отведены под питание схемы, один вывод под вход данных, и один - под выход (диоды можно соединять последовательно). Нет необходимости придумывать сложные алгоритмы для регулировки яркости и цвета каждого диода - разработчику достаточно передать в цепочку диодов последовательность байт и выдержать необходимые временные интервалы - после чего цепочка будет гореть заданным цветом либо до подачи другой последовательности, либо до отключения питания. При этом расходуется всего один вывод МК или ПЛИС!
В даташите на диоды (прикреплен в конце статьи) подробно расписаны все характеристики, здесь же приведу наиболее важные параметры:
- размер одного диода 5х5 мм, корпус - для поверхностного монтажа;
- напряжение питания - 3,5...5,3В;
- максимальное количество диодов в одной цепочке - 1024, при частоте обновления 30 кадров в секунду. Стоит заметить, что подключить такое число диодов возможно при идеальном следовании таймингам протокола, что бывает проблематично;
- светодиоды реализуют RGB-модель: каждый цвет кодируется одним байтом - теоретически возможно получить более 16 млн цветов. Однако на глаз разница между даже не столь близкими цветами незаметна.
Схема подключения диодов выглядит следующим образом:

При подаче питания диоды не инициализированы и горят синим цветом. Для инициализации цепочки диодов требуется выполнить следующие действия:
- Передать 8 бит G7..G0 для установки зеленого цвета первого диода;
- Передать биты R7..R0 для установки красного цвета;
- Передать биты B7..B0 для установки синего цвета;
- Повторить пункты 1-3 для второго, третьего и др. диодов. То есть, после инициализации первого диода, данные начинают проходить через него на следующий диод;
- Установить на входе логический "0" как минимум на 50 мкс, после чего все инициализированные диоды примут заданный цвет.
Передача единиц и нулей осуществляется не непосредственно, но выдержкой определенных временных интервалов; суммарное время передачи одного бита - 1,25 мкс, настройки одного светодиода - 30 мкс. На практике требуется соблюсти лишь длительность высокого уровня, длительность низкого может выходить из пределов в большую сторону.

Далее я подробно прокомментирую программу, которая инициализирует диоды, отвечает за управление и смену эффектов. Программа написана на языке ассемблера, проект в среде ATmelStudio 6.2 прикреплен в конце статьи. Будет рассмотрена только логика загрузки и переключения эффектов; очевидные вещи, вроде инициализации стека и настройки прерываний и портов, опущены. Также подразумевается, что цепочка диодов подключена к порту PD7 контроллера, рабочая частота - 8 МГц.
Идея программы заключается в следующем. Имеется некий набор эффектов, которые поочередно требуется выводит на светодиоды. Эффект характеризуется:
- частотой кадров;
- временем работы;
- "интеллектуальностью". "Умным" называется эффект, который проще запрограммировать (например, плавные переливы цветов, одинаковые для многих эффектов); "глупый" же эффект описывается покадрово, массивом.
Перед объяснением логики работы следует пояснить, для чего нужны следующие регистры и константы:
1 2 3 4 5 6 7 8 9 10 11 | .def temp = r16 ;для всего, своего рода регистр-помойка.def counter = r17 ;регистр-счетчик светодиодов.def curFn = r18 ;счетчик кадров, прошедших с момента начала текущего эффекта.def curEf = r19 ;7..4 - число эффектов всего, 3..0 - номер текущего.equ LED_COUNT = 17 ;константа-общее число светодиодов.equ BUFFER_SIZE = LED_COUNT*12+1 ;размер буфера (будет пояснено позднее).equ XTAL = 8000000 ;тактовая частота.equ DIV = 256 ;значение предделителя таймера.equ TPS = XTAL / DIV ;число тиков таймера за секунду.equ END = 0xFE ;маркер конца |
Учитывая приведенные выше характеристики эффекта, он выглядит примерно следующим образом:
1 2 3 4 5 6 7 | EffectName:.db high(TPS/15),low(TPS/15), 15*16,1.db 7,7,9,7,7,9,7,7,9,7,7,9.db 7,7,9,7,7,9,7,7,9,7,7,9.db 7,7,9,7,7,9,7,7,9,7,7,9.db 7,7,9,7,7,9,7,7,9,7,7,9.db 7,7,9,END |
В первой строке находятся 4 байта характеристик:
- два байта настройки прерывания таймера, определяющие частоты смены кадров. В данном случае частота - 15 кадров/сек;
- байт длительности эффекта (в кадрах). Данный эффект продлится 16 секунд;
- байт "умности" эффекта. Так как данный эффект (перелив) проще запрограммировать, байт равен единице.
Далее в массиве следуют:
- 51 байт цветовых характеристик каждого диода (в случае покадрового описания их было бы на порядок больше);
- маркер конца массива.
Под хранение буфера и некоторых констант в ОЗУ выделено следующее количество места:
1 2 3 4 5 6 7 8 | .dsegBytesBuffer: .byte BUFFER_SIZE ;массив байт, который будет загружаться в диоды (пояснено ниже)ColorsTable: .byte LED_COUNT*3+1 ;3 - число цветоканалов(R,G,B), 1 байт под маркер концаMaxFrame: .byte 1 ;число кадров, которое необходимо проиграть, для конкретного эффектаCurEffectAddr: .byte 2 ;хранит в себе адрес текущего эффекта.equ CEA_H = CurEffectAddr + 1.equ CEA_L = CurEffectAddr + 0 |
Хочется подробнее пояснить "программируемость" эффектов. Дело в том, что в массиве должны быть перечислены интенсивности каждого цвета (от 0 до 16). В свою очередь, данные значения умножаются на значения следующий регистров (заодно приведены константы-помощники в реализации перелива):
1 2 3 4 5 6 7 8 9 10 11 12 13 | .def R = r20 ;динамическая интенсивность красного.def G = r21 ;зеленого.def B = r22 ;и синего.def F = r23 ;флаг для автомата переключения состояний;флаги состояний.equ G_HIGH = 1.equ R_DOWN = 2.equ B_HIGH = 3.equ G_DOWN = 4.equ R_HIGH = 5.equ B_DOWN = 6.equ MAX_FLAG = 7 |
Произведение констант из массива и соответствующих регистров формируют таблицу цветов (ColorsTable) для каждого из диодов. В случае, если эффект программируется, значения регистров R,G,B можно динамически менять. Описание всех кадров такого эффекта нецелесообразно (требует слишком много памяти контроллера).
В случае, если эффект не программируемый, все кадры перечислены в массиве, а интенсивности вместо значений регистров умножаются на 15.
После получения таблицы цветов необходимо получить последовательность байт, которая будет загружаться непосредственно в диоды. Это выполняет следующая функция:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ColorToBytes: ldi temp,0x88 sbrc R0,7 ;используется регистр R0 как стандартный аргумент команды lpm subi temp,-(1<<6) ;сложения в AVR нет, поэтому так извращенно sbrc R0,6 subi temp,-(1<<2) st Y+,temp ldi temp,0x88 sbrc R0,5 subi temp,-(1<<6) sbrc R0,4 subi temp,-(1<<2) st Y+,temp ldi temp,0x88 sbrc R0,3 subi temp,-(1<<6) sbrc R0,2 subi temp,-(1<<2) st Y+,temp ldi temp,0x88 sbrc R0,1 subi temp,-(1<<6) sbrc R0,0 subi temp,-(1<<2) st Y+,temp ret |
То есть, данная функция преобразует один байт в четыре, которые будут загружаться в диоды.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | LoadData:cli ;цикл загрузки битов в диоды. Очень быстрый, и дабы тут ничего не сломалось, на всякий случай запрещаю прер-ия.LoadData2:ld temp,Y+cpi temp,ENDbreq FromBegin ;все диоды инициализированы, прыгаем в бесконечный циклOut1:out PortD,templsl tempnopout PortD,templsl tempnopout PortD,templsl tempnopout PortD,templsl tempnopout PortD,templsl tempnopout PortD,templsl tempnopcbi PortD,7rjmp PC+1 ;выполняется 2 такта, но занимает 2 байта, в отличие от 2*nop, которые выполняются столько же,rjmp PC+1 ;но занимает 4 байтаrjmp PC+1rjmp PC+1rjmp PC+1rjmp PC+1rjmp LoadData2FromBegin:seicbi PortD,7Loop: ;пока что цикл абсолютно пуст, то есть можно разместить еще какие-либо действия/обработчикиrjmp Loop |
Откуда взялась волшебная константа 0х88? Нужная длительность низких и высоких уровней формируется путем выдерживания определенного значения на выходе порта. Команды lsl - nop - out выполняются за три такта, то есть за 375 нс, что укладывается в допустимую погрешность. Таким образом, передача нуля сводится к загрузке последовательности 1000, а единицы - 1100. То есть, в одном байте передаются два бита, а в двенадцати байтах - настройки одного диода (24 бита = 3 байта G,R,B), что сразу делает понятной данную строку:
.equ BUFFER_SIZE = LED_COUNT*12+1 ;размер буфера (будет пояснено позднее)
Именно поэтому в начале байт равен 0x88, функция ColorToBytes попросту выставляет единицы на позициях 6 и 2, если это необходимо, и загружает байт в выходной буфер.
В упомянутом выше прерывании таймера реализовано следующее:
- загрузка следующего кадра эффекта;
- если же эффект дошел "до конца", то следующим кадром будет являться начало эффекта;
- если эффект отыграл установленное время, следующим кадром будет начало следующего эффекта;
- если эффект "умный", будут изменены значения интенсивностей в регистрах.
Общий алгоритм работы представлен следующей блок-схемой:
Также в конце статьи прикреплен шаблон проекта, незначительная правка которого позволит очень быстро работать с WS2812B.
Осталось продемонстрировать готовое устройство на "умных" светодиодах - новогоднюю елку. Схема елки достаточно проста и приведена ниже:

Основной компонент схемы - микроконтроллер ATmega8A в TQFP-корпусе. Также я оставил две кнопки для будущей доработки елки. Остальные компоненты почти полностью представлены резисторами и конденсаторами типоразмера 0805. Питается елка от 5 Вольт через разъем micro-USB, что позволяет разместить елку где угодно при подключении к внешнему ЗУ типа PowerBank. Файл с ПП елки находится в архиве (плата двусторонняя).
Фото вырезанной на ЧПУ-станке платы (одна сторона):

Впервые в жизни попробовал вырезать плату из тонкого (0.3мм) текстолита, так как планировал закрепить елку на листе бумаги формата А3. Для больших плат механическая прочность такого текстолита низка; советую брать текстолит от 1 мм толщиной. На фото даже видно просвечивающие дорожки другой стороны!
Пайка и прошивка схемы трудностей вызвать не должны, все необходимые файлы прикреплены в конце статьи. Фото елки в работе (эффект северного сияния, фрагменты гирлянд):


Далее осталось закрепить (или не закреплять) елку на какой-либо поверхности либо опоре, задекорировать мишурой... В общем, здесь простор для творчества еще больше.
Небольшое видео работы (пример эффекта перелива):
В конце статьи прикреплен архив, где находятся:
- исходный проект новогодней елки в AtmelStudio 6.2;
- шаблон проекта в этой же среде;
- файл печатной платы елки;
- файл схемы елки;
- прошивка елки;
- FUSE-биты контроллера;
- схема подключения диодов;
- даташит на WS2812B.
Теперь у Вас есть почти 9 месяцев, чтобы подготовиться к следующему Новому году! А также поделиться предложениями, идеями и замечаниями в комментариях и на форуме.
Прикрепленные файлы:
- ProjectFiles.zip (539 Кб)
0 Комментарии