Каталог
|
Arduino Leonardo и Micro для управления WS2812B2015-09-11 Все статьи →Распространение малогабаритных, корпусированных в SMD5050 сверхъярких RGB-светодиодов вместе с трехканальными восьмиразрядными контроллерами, управляющими их яркостью, дает возможность построить интересные и разнообразные конструкции подсветки и освещения. В Сети можно найти немало готовых решений, ориентированных либо на последовательности, собранные из модулей WS2812B, либо на уже готовые светодиодные ленты, совместимые с ними по алгоритмам управления. Немалая часть этих решений опирается на контроллеры Arduino (например, https://www.tweaking4all.com/hardware/arduino/arduino-ws2812-led/). В Сети также доступны библиотеки, призванные облегчить управление светодиодами в таких проектах (например, Adafruit NeoPixel). Желающих использовать готовые решения, однако, могут поджидать неприятные сюрпризы, если ваш выбор модификации (версии) Arduino не совпадает с предпочтениями автора библиотеки (а чаще всего библиотеки ориентированы на Arduino Uno). Arduino Leonardo и Micro, тем не менее, могут быть желанными прежде всего из-за физических размеров контроллера (Arduino Pro Micro имеет размер всего 18х33 мм), да и цена немаловажна. А управление цепочкой WS2812B вполне может быть реализовано на этой модификации Arduino. Более того, мы даже обойдемся без создания библиотеки. WS2812BПрежде, чем описать программу управления несколько слов о том, что такое модуль WS2812B (http://www.world-semi.com/uploads/soft/150522/1-150522091P5.pdf). Те, кто уже знаком с работой этих модулей или лент на основе драйверов WS2811 и RGB-светодиодов, могут смело пропустить этот раздел. Модуль WS2812B (см. фото) имеет всего четыре контакта, причем два из них — земля и питание (+3,5..5 В). Из двух оставшихся контактов один — вход данных, другой — выход данных (для следующего в цепочке модуля — см. рис. 1).
Рис. 1. Соединение модулей WS2812B в цепочку
Поступающие на вход модуля данные принимаются встроенным в модуль WS2812B чипом контроллера/драйвера светодиодов (между источником данных и входом модуля рекомендуют ставить небольшой резистор (пару сотен ом), чтобы защитить вход микросхемы). Поток данных (о его структуре чуть ниже) должен содержать в последовательном коде управляющие значения для всех микросхем в цепочке. Первый чип принимает весь поток, но использует только три первых байта (по байту для управления зеленым, красным и синим светодиодами), а все, что следует за этими тремя байтами, выдает на выход. Таким образом, каждый чип принимает все данные для себя и всех расположенных за ним в цепочке чипов. Если в цепочке, например, 30 модулей, то на первый модуль поступает 3*30=90 байт, на выходе первого модуля появляются 90-3=87 байт (кроме первых трех из последовательности в 90 байт), на выходе второго — 87-3=84 байта и т.д. До входа последнего модуля дойдет три байта, которые определяют яркость свечения его светодиодов. Данные для управления цветом передаются, начиная со старшего разряда, в порядке зеленый-красный-синий (см. рис. 2). Данные для второго модуля в цепочке передаются сразу же после первого без пауз.
Рис. 2. Структура данных, управляющих цветом одного модуля
В WS2812B не предусмотрена внешняя синхронизация передаваемых данных (вообще-то есть варианты модулей, в которых присутствует отдельная линия синхронизации, но это ведь дополнительный провод — лучше «помучаться» с управляющей программой, и сэкономить лишний провод). А поскольку нет внешней синхронизации, то передача каждого бита происходит с самосинхронизацией. Каждый бит начинается с формирования нарастающего фронта (переход от низкого уровня к высокому). Чип контроллера, обнаруживая фронт, начинает отсчет времени и опрашивает, примерно через 625 наносекунд уровень данных. Если обнаруживает высокий уровень — оценивает бит как равный "1", если уровень низкий — "0". Следующие 625 нс нужны чипу для сохранения полученного бита и переходу к ожиданию следующего фронта. Разумеется, и при формировании данных, и при их считывании возможны погрешности, поэтому справочный листок на WS2812B задает довольно широкие допуски на формирование передаваемых данных (см. рис. 3). При тактовой частоте 16 МГц используемого в Arduino Leonardo и Arduino Micro процессора ATmega32u4, один цикл процессора занимает 62,5 нс, следовательно, для формирования номинальной длительности «короткого» импульса ("0") — 400 нс — в нашем распоряжении 6 циклов. Этого вполне достаточно, если не использовать сложные высокоуровневые функции (маленький секрет: если интервал до следующего нарастающего фронта будет чуть больше 1250 нс — скорее всего, это никак не скажется на приеме данных. Хотя лучше, конечно, не злоупотреблять «терпением» чипа).
Рис. 3. Передача бита (временные параметры)
Чтобы не возвращаться к алгоритмам работы WS2812B заметим, что признаком начала передачи управляющей последовательности байтов служит интервал не менее 50 мкс перед нарастающим фронтом на линии входных данных. Вот это условие как раз легко выполняется стандартными средствами среды Arduino. В завершение описания корпусированного в SMD5050 модуля WS2812B, отметим, что он, как и следует из названия этого конструктива (surface mounted device — модули для поверхностного монтажа), не предназначен для проводного макетирования (зато отлично монтируются на ленты!) Поэтому на практике часто используют микро-платы, на которых монтируют сам элемент WS2812B и его развязку по питанию. На фото вы видите как раз такую плату, на которой сразу смонтированы конденсатор развязки по питанию и резистор защиты входа — очень удобно. Формирование импульсов данныхДля формирования коротких импульсов нам придется работать с портом ATmega32u4 напрямую. И первое, что необходимо сделать, определить каким разрядом какого порта мы будем управлять. Автору заметок было удобно выбрать для передачи данных pin8 в Arduino Leonardo, но, разумеется, для читателя не составит труда выбрать любой другой выход. Открыв схему своей платы (в нашем случае это https://www.arduino.cc/en/uploads/Main/arduino-leonardo-schematic_3b.pdf) видим, что pin8 соответствует четвертому разряду порта B. Таким образом, команды быстрой установки высокого и низкого уровня на выходе pin8 (и, соответственно, на входе первого в цепочке модуля WS2812B) будут такими:
PORTB |= _BV(PB4); // установить высокий уровень на pin8
Используем «пустую» команду (nop\n\t), чтобы сформировать необходимую продолжительность импульса в соответствии со значением передаваемого разряда (полагаем, что это старший разряд байта D_in): PORTB |= _BV(PB4); // включили высокий уровень на D(in) Хотя в приведенном фрагменте всегда исполняется лишь 12 формирующих задержки команд NOP (их общая длительность только 750), но время расходуют и другие команды: проверки условий и записи в порт. А когда мы организуем циклы, чтобы передавать все биты всех байтов для всех модулей, то в длительность формирования бита добавятся еще и команды управления циклами и выбора значения передаваемого разряда — так и сформируется полная длительность бита. Поскольку модулей может быть очень много, то память, которую занимают выгружаемые данные, стоит экономить. Поэтому разместим эти данные в массивах байт: #define defNoDiods 2
Эксперименты автор проводил с двумя модулями (поэтому, во избежание переусердствования со стороны оптимизатора среды Arduino, указано volatile), но памяти в Arduino Leonardo достаточно для размещения данных на 500 модулей. Теперь мы готовы сделать подпрограмму, которая будет загружать данные в цепочку светодиодных модулей. Надо только не забыть перед началом генерации сигнала для входа цепочки запретить прерывания, чтобы они не помешали выработке интервалов между переключениями порта, и разрешить их по окончании генерации. Оператор setup () в нашем случае тривиален: настраиваем выход и устанавливаем его в ноль. Чтобы быть уверенным, что первая же последовательность, которую мы загрузим, будет воспринята правильно делаем задержку заведомо большую, чем требуется для опознавания начала загрузки данных. Содержимое оператора loop () определяется теми задачами, ради которых используются светодиодные модули. Ну а для примера (или, например, проверки цепочки) можно при каждом проходе в петле loop наращивать элементы массива. В примере для двух светодиодов это выглядит так, как на скриншоте (свечение двух источников изменяется, но не совпадает более 1700 часов, так как инкремент компонентов задан простыми числами). Впрочем, для проверки возможны и любые другие комбинации — широкие возможности управления практически не ограничивают полет фантазии.
Борис Оболикшто
Благодарим Вас за обращение! Ваш отзыв появится после модерации администратором.
Пока нет отзывов на эту статью.
|