Пять метров ленты, триста пикселей, и от платы к ней идёт один тонкий провод данных. Я долго не мог уложить это в голове: по опыту обычных связей ждал тактовый сигнал и линию адресации, как у сдвиговых регистров, — а тут ни того, ни другого. Более того, у Arduino нет ни одной свободной ноги, чтобы «обслуживать» каждый пиксель отдельно. Разгадка пряталась не в плате, а в самих светодиодах: в каждом спрятан крошечный чип, который сам разбирает поток битов. Этот урок — про то, как физически устроен такой поток и какие числа из него вытекают.
План такой: посмотрим на сигнал в проводе — из чего состоит бит и почему у протокола нет тактового провода, поймём роль чипа внутри каждого пикселя и посчитаем честную цену обновления: сколько микросекунд уходит на кадр и где упирается в потолок частота анимации. Это не теория ради теории: от этих цифр зависит выбор пина, длина ленты и то, почему show() иногда дёргает серво.
Сразу оговорка про симулятор: он рисует итоговую картинку, а не микроскопические импульсы, — но и на ней видна суть эстафеты, а все числа в этом уроке можно проверить руками: монитором порта, мультиметром и скетчем из середины текста, который меряет длительность show() прямо на плате.
Бит длиной 1,25 микросекунды
Протокол WS2812 работает на скорости 800 килобит в секунду, то есть каждый бит живёт ровно 1,25 микросекунды. Тактового провода нет — а значит, смысл зашит в саму форму сигнала. Такое кодирование называют NRZ, без возврата к нулю: линия либо прижата к земле, либо поднята к пяти вольтам, и единица от нуля отличается только длительностью импульса. «Единица» — высокий уровень примерно на 0,7 микросекунды, затем спад до конца бита. «Ноль» — высокий уровень покороче, около 0,35 микросекунды. Приёмник внутри пикселя измеряет длину каждого импульса: заметно длиннее половины бита — единица, короче — ноль.
Допуск при этом жёсткий, около ±150 наносекунд на фронт. Отсюда два важных следствия. Первое: во время передачи линия не должна дёргаться ни на микросекунду — поэтому библиотеки на время show() запрещают прерывания, о чём ниже отдельно. Второе: к пину подключения особых требований нет, обычный цифровой выход Uno выдаёт импульсы с запасом по точности. Порядок байтов внутри кадра — 24 бита на пиксель, зелёный, красный, синий, старший бит вперёд; это тот самый GRB, из-за которого мы полтора часа гонялись за «зелёным красным» в уроке про первые пиксели.
И третье лицо этого протокола — пауза. Когда передача кадра кончилась, линия обязана простоять в низком уровне больше 50 микросекунд. Для чипа это команда «защёлкнуть»: применить принятый цвет и приготовиться к новому кадру. Без такой тишины он решит, что кадр ещё едет, и ничего не покажет.
Как выглядит целая передача, если в неё вглядываться: двадцать четыре импульса на пиксель, сотни импульсов на ленту, все подряд без единой паузы, кроме финальной защёлки. Глазу это недоступно — кадр на шестнадцать пикселей успевает пролететь за полмиллисекунды, а лента в ответ просто меняет цвет разом. Если в этот поток вклинится любой посторонний сигнал — наводка от реле рядом, вывод в тот же пин, обработчик прерывания, — счёт импульсов сбивается, и весь хвост кадра сдвигается на один пиксель: знакомая картина, когда цвета «уехали» на позицию. Именно поэтому провод данных держат коротким, отдельным и не делят его ни с чем.
| Событие на линии | Длительность | Что это значит |
|---|---|---|
| Один бит | 1,25 мкс | Такт зашит в форму сигнала, тактового провода нет |
| Бит «1» | ≈0,7 мкс высокий, дальше низко | Длинный импульс приёмник читает как единицу |
| Бит «0» | ≈0,35 мкс высокий, дальше низко | Короткий импульс читается как ноль |
| Пауза-защёлка | больше 50 мкс низкого уровня | Цвет применяется, чип ждёт следующий кадр |
| Кадр на 16 пикселей | ≈480 мкс + защёлка | 24 бита на пиксель при 800 кГц |
Теперь ключевая деталь, из-за которой один провод тянет сотни пикселей. Чип в каждом светодиоде устроен как вахтёр на входе: он принимает поток битов, первые 24 бита забирает себе как свой цвет, а всё остальное не просто пробрасывает дальше — он перечитывает принятые биты и выдаёт их заново, с полным размахом пять вольт и свежими таймингами. Каждый пиксель — ретранслятор. Сигнал не затухает по длине ленты, не накапливает искажения, поэтому триста пикселей честно слушают один пин.
У ретранслятора есть направление. Вход называется DI, data in, выход — DO, data out, и перепутать их стоит один раз, чтобы запомнить навсегда. Я свой раз запомнил так: подключил данные к дальнему концу ленты, где разъём показался мне «главнее». Лента молчала. Я сорок минут проверял скетч, менял пины, перезаливал прошивку, успел заподозрить брак — потому что «ну что тут можно перепутать, три провода». Оказалось, что можно: я подавал данные на выход. Стрелки на подложке ленты — не украшение, а единственная инструкция по направлению, и данные всегда входят со стороны стрелки.
Из ретрансляторной схемы следует и удобный способ поиска неисправностей. Лента ломается цепочкой: если один чип перестал передавать, всё, что за ним, молчит, а всё, что до него, продолжает гореть. Граница «горит — не горит» и есть место обрыва: лопнувшая пайка, разрезанная по ошибке дорожка, окислившийся контакт в разъёме. Мне однажды хватило перепайки одного разъёма на втором метре, чтобы «весь хвост» ленты ожил. И наоборот: если сдох сам чип, а не связь, пиксель может показывать мусор, но продолжать ретранслировать — тогда граница проходит дальше, и это тоже диагностический признак, а не случайность.
Арифметика show(): где упирается частота обновления
Считать цену кадра просто: пиксель стоит 24 бита по 1,25 микросекунды, то есть 30 микросекунд. Шестнадцать пикселей — полмиллисекунды, вы этого не заметите вообще. Сто пикселей — 3 мс. Триста — 9 мс. Пятьсот — уже 15 мс, и это половина кадра при анимации 33 кадра в секунду, того самого каркаса на millis() из урока про эффекты. Дальше хуже: тысяча пикселей требует 30 мкс × 1000 = 30 мс только на передачу, и потолок в 25–30 кадров в секунду перестаёт зависеть от вашего кода. Никакая оптимизация не ускорит провод — это физика протокола при 800 кГц.
Пример планирования, который я делаю каждый раз перед покупкой. Праздничная гирлянда на окно: пятьсот пикселей, хочется бегущую волну. Считаем: кадр — 15 мс чистой передачи, плюс защёлка и плюс время расчёта эффектов; при каркасе на 30 мс выходит честных 20 кадров в секунду, и для медленной волны этого достаточно. Тот же эффект на ленте в сто пикселей покажет все 30 кадров и оставит запас на опрос кнопок. Отсюда моё рабочее правило с границей: анимированные сцены — до сотни-двух пикселей на один пин; всё, что длиннее, — либо медленные смены состояний, либо деление на секции с отдельным addLeds на каждом пине. Второй путь не такой страшный, как звучит: каркас кадра не меняется вовсе, меняется только число адресуемых пикселей в паспорте.
На практике это значит следующее. До сотни пикселей вы никаких границ не почувствуете: кадр рисуется за миллисекунды, а между кадрами остаётся всё время мира. Планировщик задач из урока про millis-планировщик крутится без встрясок, кнопки опрашиваются мгновенно. Ленты от полутысячи пикселей — уже компромисс: либо смириться с 20 кадрами в секунду, либо резать ленту на секции и подключать их к разным пинам — FastLED позволяет повесить на одну плату несколько addLeds и обновлять их независимо. И помните про delay(): пока show() гонит кадр, программа занята им одним, и все наши успехи по уходу от delay из урока про millis вместо delay во время передачи просто не действуют.
#include <FastLED.h> #define LED_PIN 6#define NUM_LEDS 16 CRGB leds[NUM_LEDS]; void setup() { Serial.begin(9600); FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS); fill_solid(leds, NUM_LEDS, CRGB::White);} void loop() { unsigned long t0 = micros(); FastLED.show(); unsigned long dt = micros() - t0; Serial.print("us="); Serial.println(dt); delay(1000);}Загрузите этот скетч на плату с лентой на 16 пикселей — монитор порта покажет примерно 500–560 микросекунд: 480 микросекунд чистой передачи плюс защёлка. Увеличьте NUM_LEDS до 300 — увидите около 9000. Это самый честный способ узнать цену кадра для своей длины: мультиметром её не измерить, а микросекундный таймер — измеряет.
- Один провод без такта: смысл бита — в длительности импульса, бит живёт 1,25 мкс, допуск ±150 нс
- Кадр = 24 бита на пиксель в порядке G-R-B, старший бит вперёд; пауза больше 50 мкс — защёлка кадра
- Чип в каждом пикселе перечитывает и заново выдаёт остаток пакета: лента — цепочка ретрансляторов, вход DI, выход DO
- Цена show() = 30 мкс × пиксели: 16 пикселей — 0,5 мс, 500 — 15 мс, тысяча — 30 мс и потолок 25–30 fps
- Во время show() прерывания запрещены: длинная лента дёргает серво и рвёт приём ИК-команд
- 1. Сколько времени уходит на передачу цвета одному пикселю?
- 2. Что делает чип внутри пикселя с остатком пакета?
- 3. Какой должна быть пауза низкого уровня, чтобы кадр применился?
- 4. Почему FastLED запрещает прерывания на время show()?
- 5. Время show() для ленты из 1000 пикселей примерно равно...
Теперь вы знаете, что именно летит по тому единственному проводу: биты без такта, эстафету ретрансляторов и цену кадра в микросекундах. Чужие эффекты из интернета читаются уже не как магия: за каждой строкой show() стоит конкретная цена, и вы умеете её считать. Осталось сделать так, чтобы эти биты кто-то упаковывал за вас. В следующем уроке ставим библиотеку FastLED с нуля и собираем первый скетч — от менеджера библиотек до мигающего пикселя и чек-листа на случай, когда лента молчит.
Частые вопросы по теме урока
- Сколько времени уходит на передачу цвета одному пикселю?
- 24 бита по 1,25 микросекунды — это 30 микросекунд на пиксель. Сам бит длится 1,25 мкс, но битов в пикселе 24. 30 мкс
- Что делает чип внутри пикселя с остатком пакета?
- Пиксель — ретранслятор: он не пробрасывает сигнал как есть, а регенерирует его. Поэтому сигнал не затухает по длине ленты. Перечитывает биты и выдаёт заново с полным размахом и свежими таймингами
- Какой должна быть пауза низкого уровня, чтобы кадр применился?
- Пауза больше 50 микросекунд — команда защёлкнуть цвет. Без неё чип решит, что кадр ещё передаётся. Больше 50 мкс
- Почему FastLED запрещает прерывания на время show()?
- Любая задержка внутри импульса ломает тайминги: бит «0» прочитается как «1». Тишина на время передачи — условие протокола. Обработчик прерывания удлинил бы импульс за пределы допуска ±150 нс
- Время show() для ленты из 1000 пикселей примерно равно...
- 1000 пикселей по 30 микросекунд — 30 миллисекунд. Отсюда потолок в 25–30 кадров в секунду для метровых лент. 30 мс