Новогодняя елка на умных светодиодах

“Как Новый год встретишь – так его и проведешь” – давно ставшая крылатой фраза, в какой-то степени заставляющая заранее готовиться к самому любимому празднику. И если такие традиционные атрибуты, как оливье и мандарины, незаменимы, то выбор различных инсталляций и украшений ежегодно заставляет ломать голову, радиолюбителям и электронщикам – в особенности.

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

WS2812B – трехцветный светодиод с интегрированным драйвером и схемой, реализующей протокол управления. Имеет 4 вывода, как и “обычный” RGB-диод, однако их назначение отличается: два вывода отведены под питание схемы, один вывод под вход данных, и один – под выход (диоды можно соединять последовательно). Нет необходимости придумывать сложные алгоритмы для регулировки яркости и цвета каждого диода – разработчику достаточно передать в цепочку диодов последовательность байт и выдержать необходимые временные интервалы – после чего цепочка будет гореть заданным цветом либо до подачи другой последовательности, либо до отключения питания. При этом расходуется всего один вывод МК или ПЛИС!

В даташите на диоды (прикреплен в конце статьи) подробно расписаны все характеристики, здесь же приведу наиболее важные параметры:

Схема подключения диодов выглядит следующим образом:

При подаче питания диоды не инициализированы и горят синим цветом. Для инициализации цепочки диодов требуется выполнить следующие действия:

  1. Передать 8 бит G7..G0 для установки зеленого цвета первого диода;
  2. Передать биты R7..R0 для установки красного цвета;
  3. Передать биты B7..B0 для установки синего цвета;
  4. Повторить пункты 1-3 для второго, третьего и др. диодов. То есть, после инициализации первого диода, данные начинают проходить через него на следующий диод;
  5. Установить на входе логический “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 байта характеристик:

Далее в массиве следуют:

Под хранение буфера и некоторых констант в ОЗУ выделено следующее количество места:

1
2
3
4
5
6
7
8
.dseg
BytesBuffer:    .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,END
breq FromBegin ;все диоды инициализированы, прыгаем в бесконечный цикл
Out1:
out PortD,temp
lsl temp
nop
out PortD,temp
lsl temp
nop
out PortD,temp
lsl temp
nop
out PortD,temp
lsl temp
nop
out PortD,temp
lsl temp
nop
out PortD,temp
lsl temp
nop
cbi PortD,7
rjmp PC+1      ;выполняется 2 такта, но занимает 2 байта, в отличие от 2*nop, которые выполняются столько же,
rjmp PC+1      ;но занимает 4 байта
rjmp PC+1
rjmp PC+1
rjmp PC+1
rjmp PC+1
rjmp LoadData2
FromBegin:
sei
cbi PortD,7
Loop:
              ;пока что цикл абсолютно пуст, то есть можно разместить еще какие-либо действия/обработчики
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 мм толщиной. На фото даже видно просвечивающие дорожки другой стороны!

Пайка и прошивка схемы трудностей вызвать не должны, все необходимые файлы прикреплены в конце статьи. Фото елки в работе (эффект северного сияния, фрагменты гирлянд):

Далее осталось закрепить (или не закреплять) елку на какой-либо поверхности либо опоре, задекорировать мишурой… В общем, здесь простор для творчества еще больше.

Небольшое видео работы (пример эффекта перелива):

В конце статьи прикреплен архив, где находятся:

Теперь у Вас есть почти 9 месяцев, чтобы подготовиться к следующему Новому году! А также поделиться предложениями, идеями и замечаниями в комментариях и на форуме.

Список радиоэлементов

Обозначение Тип Номинал Количество Примечание
U1 МК AVR 8-бит
ATmega8A-AU
1 TQFP32
D1-D17 Светодиод WS2812B 17
C1 Конденсатор 47 мкФ 1 TANT_A
C2 Конденсатор 100 нФ 1 0805
R1-R3 Резистор
10 кОм
3 0805
R4 Резистор
0.27 Ом
1 0805
S1-S2 Кнопка 2 Без фикс.
J1 Разъем 1 micro USB

Скачать список элементов (PDF)

Прикрепленные файлы:

Источник: http://cxem.net/sound/light/light122.php


Категория: Микроконтроллеры, С других сайтов
Метки: ,

Написать коментарий

*
= 4 + 1

Добавить изображение

Последние статьи