Часы на стене гаража я собрал из полосы ленты WS2812, разрезанной на восемь кусков по восемь пикселей, — и первый же эффект уехал: вместо ровных диагоналей по кругу пошла лесенка, на каждой второй строке картинка отражалась зеркально. Я переписывал эффекты трижды, пока не понял, что код не при чём: лента-то уложена змейкой, а адресация у меня была линейная, как у прямой полосы. Двенадцать строк с функцией XY закрыли вопрос навсегда — с тех пор любая матрица из ленты у меня начинается с неё.
Соседние сюжеты уже разобраны: змейка 16x16 с черепашкой и своя функция XY в общем виде — в уроке про матрицу XY, старт с лентой и первый fill_solid — в уроке про начало с WS2812. Здесь мой угол — компактная матрица 8x8 из одной ленты: механика зигзага, формула разворота нечётных строк и один эффект поверх неё, диагональная волна, на котором видно каждую складку раскладки.
Зигзаг: почему строки едут в противоход
Лента — это одна длинная очередь пикселей с номерами 0-63, и уложить её в квадрат можно двумя способами. Прогрессом — все строки слева направо: тогда после конца первой строки провод пересекает всю матрицу, чтобы начать вторую слева. Змейкой — чётные строки слева направо, нечётные справа налево: переход с строки на строку короткий, поворот в один сантиметр, и именно так режут полосы для матриц. Плата за это не платит ни байтом: раскладка живёт не в железе, а в вашей функции XY, которая переводит координаты в номер пикселя.
Формула разворота занимает одну строку: на нечётной строке y колонка x превращается в W-1-x. Дальше номер пикселя — y умножить на 8 плюс x. Диагональный эффект собирается из суммы координат: (x+y) даёт уровень по диагонали, множитель задаёт ширину полосы, сдвиг во времени крутит картинку. До первого эффекта я всегда гоняю тест-пиксель: одна белая точка в XY(0, 0) — если она светится не в верхнем левом углу, строки у вас развёрнуты наоборот, и лучше узнать это сейчас, а не после часа правки эффектов.
#include <FastLED.h>#define LED_PIN 6#define W 8#define H 8CRGB leds[W * H]; // Зигзаг: чётные строки слева направо, нечётные - справа налевоint XY(int x, int y) { if (y % 2 == 1) x = W - 1 - x; // нечётную строку развернули return y * W + x;} int hueShift = 0; void setup() { FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, W * H); FastLED.setBrightness(120);} void loop() { for (int y = 0; y < H; y++) { for (int x = 0; x < W; x++) { // сумма координат = уровень по диагонали leds[XY(x, y)] = CHSV((x + y) * 16 + hueShift, 255, 255); } } FastLED.show(); EVERY_N_MILLISECONDS(45) { hueShift++; } // темп волны}Разбор по косточкам. XY(3, 5): строка 5 нечётная, колонка превращается в 7-3=4, номер пикселя 5*8+4=44 — на прямой ленте это сорок четвёртый светодиод, в матрице — пятая строка, четвёртое место от левого края. Множитель 16 у (x+y) делит колесо оттенков на диагонали по шестнадцать единиц: на квадрате 8x8 их выходит пятнадцать — от синего угла через зелёный к красному по встречной диагонали. Поменяйте на 32 — диагоналей станет восемь и они станут шире; на 8 — волна распадётся на мелкую рябь.
Кадр стоит 64 пикселя на show() — около двух миллисекунд на 800 кГц, так что темп легко держать до сотни кадров в секунду. W и H вынесены в константы: тот же код без правок едет на 16x16 из четырёх метров ленты, изменится только бюджет тока — 64 пикселя на белом тянут до 3,8 ампера, про потолок яркости и провод я уже писал в уроке про ток ленты.
| Раскладка | Формула | Симптом на экране |
|---|---|---|
| Прогресс (все строки слева направо) | idx = y * W + x | Диагонали едут лесенкой, каждый второй ряд отражён |
| Змейка (serpentine) | if (y % 2 == 1) x = W - 1 - x; idx = y * W + x | Непрерывные диагонали, круги и волны |
| По колонкам (лента вертикально) | if (x % 2 == 1) y = H - 1 - y; idx = x * H + y | Та же змейка, повёрнутая на 90° |
- 1. Лента уложена змейкой, но в коде все строки читаются слева направо. Как выглядит эффект?
- 2. Матрица 8x8 змейкой. Какой номер пикселя у ячейки (x=3, y=5)?
- 64 пикселя = 8 полос по 8, уложенных змейкой: чётные строки слева, нечётные справа
- Функция XY разворачивает нечётные строки одной строкой: if (y % 2 == 1) x = W - 1 - x
- Диагональ — это сумма координат: CHSV((x + y) * k + сдвиг), множитель задаёт ширину полос
- Тест-пиксель в XY(0, 0) ловит ориентацию до первого эффекта
- 64 WS2812 на белом — до 3,8 А: потолок яркости и питание из урока про бюджет тока
Частые вопросы по теме урока
- Лента уложена змейкой, но в коде все строки читаются слева направо. Как выглядит эффект?
- Железо адресует пиксели по порядку ленты, а у зигзага нечётные строки физически идут в противоход. Без разворота в XY каждая вторая строка зеркалит. Каждая нечётная строка отражается зеркально
- Матрица 8x8 змейкой. Какой номер пикселя у ячейки (x=3, y=5)?
- Строка 5 нечётная, разворачиваем: x = 7-3 = 4, номер = 5*8+4 = 44. Без разворота вышло бы 43 — соседняя ячейка. 44