АДРЕСНАЯ ЛЕНТА И ARDUINO

ВНИМАНИЕ! Вышла 3 версия библиотеки, всё было очень сильно переделано и улучшено, старые примеры и скетчи на базе старой версии будут несовместимы: переделана инициализация и изменены названия некоторых функций и констант. Старая версия будет доступна для скачивания, но рекомендуется использовать новую.
ВНИМАНИЕ! Вышла 3.1 версия библиотеки, инициализация чуточку изменилась (добавить один обязательный параметр). Также для обновления нужно удалить полностью папку с либой и заменить новой.
Вышла 3.2 версия библиотеки, исправлен критический баг с влиянием на другие пины!!!

Мы с вами уже обсуждали адресные светодиодные ленты, есть гайд по особенностям подключения и сравнение библиотек. Что объединяет все библиотеки для управления адресной светодиодной лентой? Правильно, проблемы с нехваткой памяти, потому что один светодиод требует 3 байта оперативной памяти, по байту на каждый базовый цвет: красный, зелёный и синий. Протокол передачи данных на ленту состоит из последовательных передач байта каждого цвета, примерно так: R1, G1, B1, R2, G2, B2… Rn, Gn, Bn. Именно поэтому микроконтроллер хранит в памяти байт каждого цвета каждого светодиода в ленте. Для одного светодиода это выглядит так: RRRRRRRR GGGGGGGG BBBBBBBB – по 8 бит на каждый цвет. А что если попробовать “сжать” цвет? Мы попробовали!

БОЛЬШОЕ ОБНОВЛЕНИЕ!

Версия 3.0
– Добавлены функции и цвета:
– Цветовая температура .setKelvin() и дата Kelvin
– getBlend(позиция, всего, цвет1, цвет2) и getBlend2(позиция, всего, цвет1, цвет2)
– .fill(от, до)
– .fillGradient(от, до, цвет1, цвет2)
– Добавлен шум Перлина (вытащил из FastLED)
– Добавлены градиенты
– Полностью переделан и оптимизирован вывод
– Возможность работать вообще без буфера
– Настройка ограничения тока для всех типов лент
– Настраиваемый запрет прерываний
– Сохранение работы миллиса на время отправки
– Поддержка лент 2811, 2812, 2813, 2815, 2818
– Поддержка 4х цветных лент: WS6812
– Инициализация переделана под шаблон, смотри примеры!
– Много изменений в названиях, всё переделано и упрощено, читай документацию!

Версия 3.1
– Поправлены ошибки компиляции для нестандартных ядер Ардуино и Аттини
– Добавлен класс tinyLED.h для вывода потоком с ATtiny и вообще любых AVR (см. пример)
– Вырезаны инструменты FastLED (рандом, шум), будем работать напрямую с фастлед
– Добавлена поддержка совместной работы с библиотекой FastLED и конвертация из её типов!
– Добавлена поддержка ленты APA102 (а также других SPI), программная и аппаратная SPI

БИБЛИОТЕКА microLED

microLED – ультра-лёгкая библиотека для работы с адресной лентой/матрицей

  • Основная фишка: сжатие цвета, код занимает в разы меньше места в SRAM по сравнению с аналогами (FastLED, NeoPixel и др.)
    • Использование 8 битного цвета занимает в 3 раза меньше SRAM чем у других библиотек
    • Использование 16 битного цвета занимает в 2/3 раза меньше SRAM чем у других библиотек
  • Работа с цветом:
    • RGB
    • HSV
    • HEX цвета
    • “Цветовое колесо”
    • Температура цвета
    • 17 встроенных цветов
    • Градиенты, фейды и другие инструменты
  • Возможность чтения сжатого цвета
  • Ограничение тока (автокоррекция макс. яркости)
  • Быстрейшая реализация протокола общения с лентой
  • Поддержка работы с адресными матрицами (см. пример)
  • Поддержка чипов: WS2811, WS2812, WS2813, WS2815, WS2818, WS6812, APA102 (программно и SPI)
  • Возможность работать без буфера (не занимая память в RAM)
  • Поддержка всех AVR в том числе мелких аттини
  • И многое другое!

Поддерживаемые платформы: ТОЛЬКО ДЛЯ АРХИТЕКТУРЫ AVR!!! тестировалось только на ATmega328 (Nano, UNO, Mini) и ATtiny85/ATtiny13. Должны поддерживаться и остальные МК этого поколения, тактовая частота только 8 и 16 МГц, а также 9.6 МГц для АТтини13.

ДОКУМЕНТАЦИЯ


ОСОБЕННОСТИ


Данная библиотека нужна для проектов с лентой, в которых критичен объём занимаемой оперативной памяти: его можно уменьшить в 1.5 и 3 раза по сравнению с обычными библиотеками, а также вообще отказаться от динамического буфера и управлять лентой любой длины даже с ATtiny!! Библиотека написана очень просто, используемые в ней алгоритмы и решения очень прозрачны и могут кому-нибудь пригодиться. Единственный минус: инструменты для генерации и изменения цвета работают медленнее, чем в FastLED, поэтому для быстрых красивых эффектов на большой ленте/матрице придётся подключать фастлед для быстрой математики.

ПОДДЕРЖКА FASTLED (NEW!)


В версии 3.1 появилась полноценная поддержка совместной работы с FastLED для быстрого вычисления эффектов. Это позволяет выводить всякие шумы по палитрам даже на АТтини!! Для этого подключаем в скетч #include < FastLEDsupport.h> (смотри примеры), саму FastLED подключать не нужно, она подключится автоматически. У нас появится функция CRGBtoData(), которая переводит тип данных фастледа в микролед (конвертирует CRGB в mData при любой глубине цвета). В качестве примера работы с  палитрой можно глянуть пример FIRE_with_FastLED.

ЦВЕТОВАЯ ГЛУБИНА


Цветовая глубина задаёт количество байт, которые занимает цвет одного светодиода и может быть от 1, 2 и 3 байта (8, 16 и 24 бита на один светодиод соответственно). Все остальные библиотеки используют 24-битную глубину цвета, в microLED её можно уменьшить для экономии памяти. При уменьшении цветовой глубины пропорционально уменьшается вес ленты в оперативной памяти, но в то же время ухудшается цвет: на эффектах с плавными переходами цвета будут заметны границы между оттенками. Настройка цветовой глубины задаёт работу всей библиотеки и делается при помощи дефайна COLOR_DEBTH до подключения библиотеки:

#define COLOR_DEBTH 2 
#include < microLED.h >

По умолчанию (если не указывать дефайн) глубина настроена на 24 бита (COLOR DEBTH 3). Понижать глубину рекомендуется только в целях экономии памяти.

ГАММА КОРРЕКЦИЯ


Ещё одна настройка, которая делается дефайном и влияет на всю библиотеку сразу. Гамма коррекция позволяет получать более естественные цвета и их смеси, а также более приятные глазу переходы яркости и реализована 4мя способами:

  • #define CRT_OFF – коррекция отключена для экономии памяти и ускорения вычислений.
  • #define CRT_PGM – коррекция по таблице. Добавляет 256 байт во Flash память, но работает быстрее и красивее всех остальных.
  • #define CRT_SQUARE – квадратная коррекция. Занимает мало памяти, выполняется гораздо дольше таблицы (около 7 мкс).
  • #define CRT_CUBIC – кубическая коррекция. Выглядит приятнее квадратной, но выполняется ещё дольше.

По умолчанию включена коррекция по таблице. Остальные режимы – для продвинутого пользователя и экспериментов.

КАК РАБОТАЕТ БИБЛИОТЕКА?


Режим буфера

При инициализации указываем длину ленты, внутри библиотеки будет создан буфер типа mData, который занимает 1, 2 или 3 байта в зависимости от выбранной цветовой глубины и олицетворяет цвет в формате RGB. С данным массивом можно работать как с обычным массивом и присваивать его элементам цвет в формате mData (например, strip.leds[5] = mRed). Само собой, массив занимает место в оперативной памяти микроконтроллера пропорционально длине ленты. Забив буфер цветами, можно вызвать strip.show() и лента обновится с максимально возможной скоростью.

strip.leds[0] = mRGB(0, 230, 60);
strip.leds[5] = mRed;
strip.show();

Режим потока

В этом режиме буфер не создаётся (количество светодиодов указываем 0), оперативная память не занимается, а мы генерируем цвет пикселей “на лету”. Для начала передачи нужно вызвать .begin(), для передачи цвета – .send(mData цвет) нужное количество раз и завершить вывод вызовом .end().

Тут есть некоторые ограничения: между вызовами send() должно пройти не более 50-300 мкс (в зависимости от модели ленты), иначе вывод сбросится. Для экономии времени можно заранее посчитать цвет перед выводом, например зальём всю ленту:

mData data = mHSV(0, 255, 120);
strip.begin();
  for (int i = 0; i < num; i++) {
    strip.send(data);
  }
strip.end();

ИНИЦИАЛИЗАЦИЯ ЛЕНТЫ


В библиотеке версии 3 и выше лента объявляется через шаблон: microLED< amount, pin, clock, chip, order, cli, millis> объект:

  • amount – количество светодиодов в ленте. Для работы в режиме потока можно указать 0, так как длина ленты фактически ничем не ограничена.
  • pin –  пин, к которому подключен дата-вход ленты (D, Din, DI).
  • clock – пин, к которому подключен тактовый-вход ленты (C, CLK). Этот пин подключается только для SPI лент, например APA102.
    • Для работы с лентами серии WSxxxx нужно указать вместо этого пина параметр MLED_NO_CLOCK или минус 1 , т.е. -1
  • chip – модель ленты (светодиодов), в библиотеке поддерживаются LED_WS2811, LED_WS2812, LED_WS2813, LED_WS2815, LED_WS2818, LED_WS6812, APA102, APA102_SPI. Выбор модели ленты задаёт скорость протокола (она у них разная) и настройки тока потребления для режимов ограничения (о них читай дальше).
  • order – порядок цветов в ленте. В идеальном мире порядок цветов должен зависеть от модели чипа и эта настройка должна быть встроена в выбор чипа, но китайцы торгуют лентами, которые по протоколу совпадают с одним чипом, но имеют другой порядок цветов. Таким образом библиотека поддерживает больше типов лент, чем написано выше, но нужно угадать с выбором “клона” и порядок цветов. Порядок: ORDER_RGB, ORDER_RBG, ORDER_BRG, ORDER_BGR, ORDER_GRB, ORDER_GBR.

Оригинальные ленты на поддерживаемых библиотекой чипах имеют такой порядок цветов, также это готовая строка инициализации:

// microLED< NUMLEDS, STRIP_PIN, -1, LED_WS2811, ORDER_GBR> strip;
// microLED< NUMLEDS, STRIP_PIN, -1, LED_WS2812, ORDER_GRB> strip;
// microLED< NUMLEDS, STRIP_PIN, -1, LED_WS2813, ORDER_GRB> strip;
// microLED< NUMLEDS, STRIP_PIN, -1, LED_WS2815, ORDER_GRB> strip;
// microLED< NUMLEDS, STRIP_PIN, -1, LED_WS2818, ORDER_RGB> strip;
// microLED< NUMLEDS, STRIP_PIN, -1, LED_WS6812, ORDER_RGB> strip;
// microLED< NUMLEDS, STRIP_PIN, CLOCK_PIN, LED_APA102, ORDER_BGR> strip;
// microLED< NUMLEDS, MLED_NO_CLOCK, MLED_NO_CLOCK, LED_APA102_SPI, ORDER_BGR> strip;

Можно вставить прямо в свой код =) Оставшиеся две настройки не являются обязательными (можно не указывать):

  • cli – выбор настроек запрета прерываний для повышения надёжности вывода данных на ленту:
    • CLI_OFF – прерывания не отключаются (возможны сбои в работе ленты даже от прерываний системного таймера)
    • CLI_LOW – прерывания отключаются на время передачи одного цвета
    • CLI_AVER – прерывания отключаются на время передачи светодиода (3 цвета)
    • CLI_HIGH – прерывания отключаются на время передачи данных на всю ленту
  • millis – при отключении прерываний в режиме среднего и высокого приоритета (CLI_AVER и CLI_HIGH) неизбежно будут чуть отставать функции времени millis() и micros(). В библиотеке встроено обслуживание функций времени, для активации передаём SAVE_MILLIS 6-ым аргументом при инициализации: microLED< NUMLEDS, STRIP_PIN, LED_WS2818, ORDER_GRB, CLI_AVER, SAVE_MILLIS> strip;

ОСОБЕННОСТИ 2Х ПИНОВЫХ ЛЕНТ (NEW!)


Существует два вида лент, имеющих 2 пина для управления (помимо питания):

  • Ленты моделей WS2813, WS2815, WS2818 и их копии с буквами SK и такими же цифрами. У этих лент подключается только один пин из двух, тот который DI. Пин BI (B) не подключается. При инициализации указывается только DI пин, второй пишем -1 или “заглушку” MLED_NO_CLOCK.
  • Ленты моделей APA102 (она же SK9822) требуют подключения именно двух своих пинов, один из которых Data (D, DI, DAT), а второй – Clock (C, CLK, SCK). При инициализации указываем оба.

SPI ЛЕНТЫ (NEW!)


В библиотеке версии 3.1 добавлена поддержка SPI лент, в том числе аппаратная (на базе стандартной библиотеки SPI.h). Рассмотрим куски примеров.

При выборе LED_APA102 ленту можно подключить на любые два пина и указать их при инициализации. Всё

// пример работы с LED_APA102 программно
#define DATA_PIN 3      // пин дата
#define CLOCK_PIN 4     // пин клок
#define NUMLEDS 50      // кол-во светодиодов

#include    // подключаем библу
microLED< NUMLEDS, DATA_PIN, CLOCK_PIN, LED_APA102, ORDER_BGR, CLI_AVER> strip;

При выборе LED_APA102_SPI лента подключается к выводам аппаратной шины SPI микроконтроллера:

  • Data пин на MOSI (D11 на Arduino Nano)
  • Clock пин на SCK (D13 на Arduino Nano)

Что это даёт? Аппаратный SPI позволяет выводить данные на ленту чуть ли не в 10 раз быстрее, чем программный способ! В коде должно быть:

#define MLED_USE_SPI    // обязательный деф до библиотеки для поддержки SPI.h
//#define MLED_SPI_CLOCK 8000000 // частоту SPI можно менять из скетча

#include    // подключаем библу
microLED<NUMLEDS, -1, -1, LED_APA102_SPI, ORDER_BGR, CLI_AVER> strip;

Пины в этом случае не указываются! Ставим заглушку или -1. Это всё.

ГЕНЕРАЦИЯ ЦВЕТА


Для работы с цветом в библиотеке есть несколько инструментов, возвращающих тип данных mData для отправки на ленту или в буфер. mData – тип данных, который олицетворяет цвет светодиода в формате RGB. В зависимости от выбранной цветовой глубины является:

  • 8 бит – uint8_t
  • 16 бит – uint16_t
  • 24 бита – struct {byte r, g, b}

Собственно инструменты и функции:

  • mRGB(r, g, b) – итоговый цвет будет замешан из красного, зелёного и синего, все параметры задаются в диапазоне 0-255
  • mHSV(h, s, v) – цвет из пространства hsv: цвет, насыщенность, яркость. Все параметры задаются в диапазоне 0-255. Цвет в диапазоне 0-255 совершает круг от красного к зелёному, от зелёного к синему и от синего снова к красному. Функция “тяжёлая”, поэтому для генерирования “радуги” рекомендуется использовать mWheel() и mWheel8()
  • mHSVfast(h, s, v) – то же самое, но выполняется быстрее и даёт менее приятные глазу цветовые переходы
  • mWheel(val) – принимает значение от 0 до 1530 и возвращает цвет из цветового круга, как и hsv. Выполняется очень быстро
  • mWheel(val, bright) – то же самое, но с яркостью (0-255)
  • mWheel8(val) – то же самое что предыдущий, но принимает 0-255 и делает цвет постоянной яркости.
  • mWheel8(val, bright) – то же самое, но с яркостью (0-255)
  • mHEX(val) – принимает цвет в формате RGB888 (обычный web-формат). Например 0xFF0000 это красный
  • mKelvin(temp) – выдает цвет, соответствующий цветовой температуре temp в кельвинах
  • 16 предустановленных цветов: mWhite, mSilver, mGray, mBlack, mRed, mMaroon, mOrange, mYellow, mOlive, mLime, mGreen, mAqua, mTeal, mBlue, mNavy, mMagenta, mPurple
  • getBlend(val, max, color1, color2) – выдает цвет в указанном месте градиента двух цветов: val – искомая точка (от 0 до max), max – размер градиента, color1 и color2 – цвета, соответствующие 0 и max позиции градиента. Например getBlend(30, 100, mRed, mBlack) вернёт красный, смешанный с черным на 30/100, то есть чуть темнее красного.
  • getFade(mData data, uint8_t val) – вернёт цвет data, яркость которого понижена на val (0-255).
  • uint32_t getHEX(mData data) – вернёт HEX RGB888 вне зависимости от выбранной цветовой глубины (функция распакует и вернёт в привычном представлении)
  • RGB888to565(x), RGB888to323(x), RGB565to888(x), RGB323to888(x) – макросы конвертации цвета из одной кодировки в другую (принимает численное значение).
  • getR(mData x) – извлечь красный канал из цвета
  • getG(mData x) – извлечь зелёный канал из цвета
  • getB(mData x) – извлечь синий канал из цвета
  • mergeRGB(r,g,b) – объединить три цвета (0-255 каждый) в mData с учётом выбранной модели CRT гамма-коррекции
  • mergeRGBraw(r,g,b) – объединить три цвета (0-255 каждый) в mData
  • fade8(byte x, byte b) – уменьшить яркость x (0-255) на b (0-255)
  • fade8R(mData x, byte b) – уменьшить яркость красного канала цвета x на b (0-255)
  • fade8G(mData x, byte b) – уменьшить яркость зелёного канала цвета x на b (0-255)
  • fade8B(mData x, byte b) – уменьшить яркость синего канала цвета x на b (0-255)
  • getCRT(byte x) – получить скорректированное значение яркости x с учётом выбранной модели CRT гамма-коррекции
  • getCRT_PGM(byte x) – получить CRT из прогмем (работает только если выбрана PGM модель)
  • getCRT_SQUARE(byte x) – получить CRT по квадратной модели
  • getCRT_QUBIC(byte x) – получить CRT по кубической модели
  • RGB24to16(x) – конвертация 24-бит цвета в 16-бит
  • RGB24to8(x) – конвертация 24-бит цвета в 8-бит
  • RGB16to24(x) – конвертация 16-бит цвета в 24-бит
  • RGB8to24(x) – конвертация 8-бит цвета в 24-бит
  • RGB24toR(x) – вытащить байт R из 24-бит цвета
  • RGB24toG(x) – вытащить байт G из 24-бит цвета
  • RGB24toB(x) – вытащить байт B из 24-бит цвета
  • RGBto24(r,g,b) – склеить 24-бит цвет
  • RGBto16(r,g,b) – склеить 16-бит цвет
  • RGBto8(r,g,b) – склеить 8-бит цвет

ГРАДИЕНТЫ


В библиотеке реализован инструмент для создания градиентов любого размера (количество цветных сегментов) и длины:

mGradient< 4 > myGrad;  // создать градиент с именем myGrad на 4 точки
// указываем цвет каждой точки
myGrad.colors[0] = mBlack;
myGrad.colors[1] = mRed;
myGrad.colors[2] = mYellow;
myGrad.colors[3] = mWhite;
// создали градиент чёрный-красный-жёлтый-белый с одинаковым расстоянием между точками

// при помощи .get(позиция, размер) можно получить цвет в заданном месте градиента при указанной длине

// заливаем всю ленту
for (int i = 0; i < NUMLEDS; i++) {
  strip.set(i, myGrad.get(i, NUMLEDS)); // получаем последовательно все цвета
}
strip.show();

РАБОТА С ЛЕНТОЙ ПОПИКСЕЛЬНО


Можно присвоить цвет в формате mData напрямую в буфер: strip.leds[0] = mRed. Есть функция set, которая делает то же самое:

set(num, color) – установить светодиоду под номером num цвет color. Например strip.set(0, mWheel(120));

fade(int num, byte val) – уменьшить яркость светодиода num на величину val

get(num) – вернёт цвет в формате mData. Равносильно чтению элемента массива буфера strip.leds[num]. Полученный цвет можно фейдить и применять к нему другие описанные выше модификаторы.

ЗАЛИВКА УЧАСТКОВ


  • clear() – очистить все цвета в буфере (погасить светодиоды)
  • fill(color) – залить всю ленту цветом color. Например fill(mRGB(120, 50 96))
  • fill(from, to, color) залить цветом color, со светодиода from до to
  • fillGradient(from, to, color1, color2) – залить градиентом от color1 до color2 между светодиодами from и to

Примечание: это функции для работы с буфером. Для применения нужно вызвать show(). Для потокового вывода эти функции не работают!

ЯРКОСТЬ


Яркость задаётся в setBrightness(val) в диапазоне 0-255. Установка яркости занимается дополнительным уменьшением яркости, то есть если поставить цвет mRed и максимальную яркость – это будет 255 по красному каналу цвета (максимум). Если поставить яркость 128, красный канал пропорционально уменьшится, остальные каналы останутся нулями.

РАБОТА С МАТРИЦЕЙ


Для работы с матрицей при инициализации, помимо настроек шаблона ленты, нужно указать параметры матрицы: (width, height, type, conn, dir). Где width и height – ширина и высота матрицы, type, conn и dir – тип соединения матрицы, угол и направление подключения (см. картинки к документации).

Так как матрица – это все ещё лента, у каждого пикселя помимо двух координат есть номер в ленте. Получить его можно при помощи getPixNumber(x, y). Система координат – первая четверть декартовой СК: начало (0, 0) – левый нижний угол. Вверх растёт y, вправо – x.

  • set(x, y, color) – включит указанный пиксель указанным цветом в формате mData
  • get(x, y) – прочитает цвет пикселя
  • drawBitmap8(int X, int Y, const uint8_t *frame, int width, int height) – вывод битмапа (битмап 1мерный PROGMEM)
  • drawBitmap16(int X, int Y, const uint16_t *frame, int width, int height) – вывод битмапа (битмап 1мерный PROGMEM)
  • drawBitmap32(int X, int Y, const uint32_t *frame, int width, int height) – вывод битмапа (битмап 1мерный PROGMEM)

ОГРАНИЧЕНИЕ ТОКА (ЯРКОСТИ)


В библиотеке есть возможность автоматически ограничить яркость ленты по установленному току потребления при помощи setMaxCurrent(cur), где cur – ток в миллиамперах. В самой библиотеке ток каждого типа ленты уже задан, но я измерял его для своих лент, и он может отличаться от лент, купленных в другом магазине. Для наиболее точной работы ограничения нужно настроить ток ленты для своей ленты, задав в oneLedMax максимальный (белый, 255) ток одного светодиода в миллиамперах и oneLedIdle – холостой ток (светодиод выключен) в мкА.

oneLedMax = (ток ленты с одним горящим) - (ток выключенной ленты)
oneLedIdle = (ток выключенной ленты) / длина ленты * 1000

Берём кусок ленты, например WS2818, 180 диодов (3 в каждом секторе, 60 секторов):

  • 160 мА когда горит один сектор из 60
  • 114 мА когда лента не горит

Так как активный ток равен холостому + активному, 160-114 = 46 чистых мА на сектор имеем 114 / 60 = 1.9 мА холостых на сектор

strip.oneLedIdle = 1900; // задаём в мка
strip.oneLedMax = 46; // задаём в ма

Берём бухту ленты, например WS2812, 60*5м = 300 диодов

  • 102 мА когда горит один диод
  • 74 мА когда лента не горит

Так как активный ток равен холостому + активному, 102-74 = 28 чистых мА на диод имеем 74 / 300 = 0.24 мА холостых на диод

strip.oneLedIdle = 240; // задаём в мка
strip.oneLedMax = 28; // задаём в ма

ТИНИЛЕД!


В версии 3.1 появилась новая мощная штука: tinyLED.h – библиотека для вывода данных на ленту, написанная на ассемблере и использующая минимально возможный объём памяти! Библиотека задумана для генерации и вывода эффектов “на лету”, когда программный буфер не используется. Это позволяет выводить ту же плывущую радугу на ленту неограниченной длины, занимая всего 300 байт Flash памяти и ноль оперативной!!! Тини 13 рада такому обновлению. Для обеспечения максимальной вариативности библиотека настраивается дефайнами перед подключением, их много, поэтому рассмотрим все.

НАСТРОЙКИ


Чип ленты выбирается дефайном TLED_CHIP. Доступны:

#define TLED_CHIP LED_WS2811
#define TLED_CHIP LED_WS2812
#define TLED_CHIP LED_WS2813
#define TLED_CHIP LED_WS2815
#define TLED_CHIP LED_WS2818
#define TLED_CHIP LED_WS6812
#define TLED_CHIP LED_APA102
#define TLED_CHIP LED_APA102_SPI

Порядок цветов выбирается дефайном TLED_ORDER:

#define TLED_ORDER ORDER_RGB
#define TLED_ORDER ORDER_RBG
#define TLED_ORDER ORDER_BRG
#define TLED_ORDER ORDER_BGR
#define TLED_ORDER ORDER_GRB
#define TLED_ORDER ORDER_GBR

В большинстве случаев порядок цветов совпадает с указанным в документации, но можно нарваться на подделку (если покупать не по моим ссылкам, а искать самую дешёвую ленту). Вот стандартная “расцветовка”:

  • LED_WS2811 – ORDER_GBR
  • LED_WS2812 – ORDER_GRB
  • LED_WS2813 – ORDER_GRB
  • LED_WS2815 – ORDER_GRB
  • LED_WS2818 – ORDER_RGB
  • LED_WS6812 – ORDER_RGB
  • LED_APA102 – ORDER_BGR
  • LED_APA102_SPI – ORDER_BGR

Запрет прерываний здесь имеет такой же смысл, как в основной либе, настраивается дефайном TLED_CLI, по умолчанию стоит LOW:

// #define TLED_CLI CLI_OFF  // прерывания не запрещаются
// #define TLED_CLI CLI_LOW  // запрещаются на время передачи байта (стоит по умолчанию)
// #define TLED_CLI CLI_AVER // запрещаются на время передачи светодиода (3 байта)
// #define TLED_CLI CLI_HIGH // запрещаются на время передачи всей ленты

Управление яркостью можно отключить целях уменьшения веса кода (экономия около 60 байт). Делаем одинокий дефайн TLED_STATIC_BRIGHT и setBrightness() перестаёт работать. В то же время яркость светодиодов спокойно регулируется при генерации эффектов, общая яркость она и не нужна особо.

// #define TLED_STATIC_BRIGHT

С пинами и подключением тут всё немного труднее: мы работаем напрямую с портом, поэтому должны его указать.

1 пин ленты

// по умолчанию задефайнен PORTB (для ATtiny)
// можно указать свой порт, если у тиньки больше 8 ног или это вообще атмега
// #define TLED_PORT PORTB
// #define TLED_DDR DDRB

Сам пин указывается при инициализации объекта:

#include "tinyLED.h"
tinyLED< 3> strip;  // например пин 3

2 пин ленты, софт SPI

// программный SPI, например LED_APA102
// по умолчанию PORTB
// можно указать свой порт, если у тиньки больше 8 ног или это вообще атмега
// #define TLED_CLK_PORT PORTB
// #define TLED_CLK_DDR DDRB
// #define TLED_DAT_PORT PORTB
// #define TLED_DAT_DDR DDRB

Сами пины указываются при инициализации объекта:

#include "tinyLED.h"
tinyLED< 3, 4> strip; // < DATA, CLOCK > для 2-пин лент

2 пин ленты, аппаратный SPI

При выборе в качестве модели ленты LED_APA102_SPI в код автоматически подключается библиотека SPI.h. Она есть не для всех МК, так что не везде будет работать! Лента подключается к аппаратным выводам SPI микроконтроллера, например на Nano это D13 (CLK) и D11 (DATA). Дефайны пинов указывать не нужно, как и номера пинов при инициализации:

tinyLED strip;

Но добавляется настройка скорости SPI: TLED_SPI_CLOCK

// #define TLED_SPI_CLOCK 8000000

По умолчанию стоит 8000000, можно менять как надо. Это всё.

ПРОГРАММИРОВАНИЕ


Тинилед автоматически подцепляет файл с моей реализацией цветовых инструментов и может их использовать. Данные выводятся “потоком”, перед началом и после отправки нужно вызвать begin() и end(), если это SPI лента или используется высокий приоритет прерываний. Сам вывод делается при помощи sendRGB(r,g,b) или просто send(data), где data – тип данных моей библиотеки. Например можно покрасить ленту в один из стандартных цветов:

// залить 50 ледов жёлтым цветом
strip.begin();
for (byte i = 0; i < 50; i++) strip.send(mYellow);
strip.end();

Или вывести радугу:

const int numleds = 100;
strip.begin();
for (int i = 0; i < numleds; i++) strip.send(mWheel8(i * 255 / numleds)); // выводим радугу  
strip.end();

Из дополнительных инструментов есть:

  • setBrightness(0-255) – установка яркости всего вывода (отключается дефайном)
  • sendRGBW(r,g,b,w) – для RGBW ленты (например WS6812)
  • sendBuffer(buf, size) – выводит буфер типа mData длиной size. Смотри пример tinyled_buffer
  • clear(size) – гасит указанное количество ледов (там внутри бегин-цикл-енд и всё, просто для удобства сделал)

В  принципе это всё. Для примера совместим тинилед для вывода и фастлед для генерации эффекта пламени (используем палитру и шум Перлина – одни из самых жирных инструментов):

#include < FastLEDsupport.h> // вкл поддержку FL
DEFINE_GRADIENT_PALETTE( heatmap_gp ) {   // делаем палитру огня
  0,     0,  0,  0,     // black
  128,   255,  0,  0,   // red
  224,   255, 255,  0,  // bright yellow
  255,   255, 255, 255  // full white
};
CRGBPalette16 fire_p = heatmap_gp;

#define TLED_CHIP LED_WS2812
#define TLED_ORDER ORDER_GRB
#define numleds 100
#include < tinyLED.h>
tinyLED< 3> strip;

void setup() {
  strip.setBrightness(100);
}

void loop() {
  static int count = 0;
  count += 10;
  for (int i = 0; i < numleds; i++)
    strip.send(CRGBtoData(ColorFromPalette(fire_p, inoise8(i * 25, count), 255, LINEARBLEND)));
  delay(30);
}

Скетч компилил для тини85, занимает 2 кб Flash (25%) и 73 б (14%) оперативной памяти. Аналогичный скетч с выводом FastLED занимает 4.2 кб Flash (51%) и 450 б (51%) оперативки. Более того, с микроледом длина ленты не влияет на размер кода, вот такие пироги!

Сначала сжали цвет до 2-х байт (16 бит), цвет хранится вот таким образом: RRRRRGGG GGGBBBBB. “Запаковка” трёх байт r, g и b в два выглядит вот так:

((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | ((b & 0b11111000) >> 3)

Распаковка для отправки данных на ленту делается так:

loopData[0] = (data & 0b1111100000000000) >> 8;
loopData[1] = (data & 0b0000011111100000) >> 3;
loopData[2] = (data & 0b0000000000011111) << 3;

Далее сжали цвет до одного байта, хранится как RRGGGBBB. “Запаковка” трёх байт r, g и b в один выглядит вот так:

( (r & 0b11000000) | ((g & 0b11100000) >> 2) | (b & 0b11100000) >> 5)

Распаковка для отправки данных на ленту делается так:

loopData[0] = data & 0b11000000;
loopData[1] = (data & 0b00111000) << 2;
loopData[2] = (data & 0b00000111) << 5;

Вот и всё! Получилась очень сильная экономия памяти, которая позволяет, например, впихнуть в Arduino Nano почти 2 тысячи светодиодов при разрешении 8 бит, или 1 тысячу при разрешении 16 бит. Круто! =) Алгоритм вывода данных на ленту разработан Egor ‘Nich1con’ Zaharov и обгоняет все существующие библиотеки для работы с лентами, а я в свою очередь дописал лёгкую оболочку по работе с цветовыми пространствами и светодиодными матрицами. Сравнения по весу и скорости с другими библиотеками:

Частота обновления (Гц) от количества светодиодов (сравнение с другими библиотеками), включая минимальное время между отправками (40 мкс). microLED работает в режиме MAX_DATA_SPEED – разогнанном протоколе связи (не работает на WS2811!)

Кол-во диодовFastLED 24-bitNeoPixel 24-bitWS2812 24-bitmicroLED 24-bitmicroLED 16-bitmicroLED 8-bit
840018183260478244204460
1640012641751266324372462
50333554589923840848
100220301298472428432
500606561968788

Занимаемая память (байт) от количества диодов, где LED – количество светодиодов (сравнение с другими библиотеками)

ПамятьFastLED 24-bitNeoPixel 24-bitWS2812 24-bitmicroLED 24-bitmicroLED 16-bitmicroLED 8-bit
Flash27861984946306346324
SRAM90+3*LED40+3*LED31+3*LED20+3*LED20+2*LED20+1*LED

Скачать саму библиотеку можно ниже, там ещё примеры и документация.

// шаблон: < количество, пин, чип, порядок, прерывания, миллис>
// инициализация ЛЕНТА: нет аргументов
microLED;
// инициализация МАТРИЦА: ширина матрицы, высота матрицы, тип матрицы, угол подключения, направление (см. ПОДКЛЮЧЕНИЕ МАТРИЦЫ)
microLED(uint8_t width, uint8_t height, M_type type, M_connection conn, M_dir dir);
// лента и матрица
void set(int n, mData color);  // ставим цвет светодиода mData (равносильно leds[n] = color)  
mData get(int num);// получить цвет диода в mData (равносильно leds[n])
void fill(mData color);  // заливка цветом mData
void fill(int from, int to, mData color);// заливка цветом mData
void fillGradient(int from, int to, mData color1, mData color2);  // залить градиентом двух цветов
void fade(int num, byte val);  // уменьшить яркость
// матрица
uint16_t getPixNumber(int x, int y);  // получить номер пикселя в ленте по координатам
void set(int x, int y, mData color);  // ставим цвет пикселя x y в mData
mData get(int x, int y);// получить цвет пикселя в mData
void fade(int x, int y, byte val);// уменьшить яркость
void drawBitmap8(int X, int Y, const uint8_t *frame, int width, int height);  // вывод битмапа (битмап 1мерный PROGMEM)
void drawBitmap16(int X, int Y, const uint16_t *frame, int width, int height);  // вывод битмапа (битмап 1мерный PROGMEM)
void drawBitmap32(int X, int Y, const uint32_t *frame, int width, int height);  // вывод битмапа (битмап 1мерный PROGMEM)
// общее
void setMaxCurrent(int ma);// установить максимальный ток (автокоррекция яркости). 0 - выключено
void setBrightness(uint8_t newBright);  // яркость 0-255
void clear();  // очистка
// вывод буфера
void show();  // вывести весь буфер
// вывод потока
void begin();  // начать вывод потоком
void send(mData data);  // отправить один светодиод
void end();// закончить вывод потоком

// цвет
uint32_t getHEX(mData data);            // перепаковать в 24 бит HEX
mData getFade(mData data, uint8_t val);        // уменьшить яркость на val
mData getBlend(int x, int amount, mData c0, mData c1);  // получить промежуточный цвет
mData mRGB(uint8_t r, uint8_t g, uint8_t b);    // RGB 255, 255, 255
mData mWheel(int color, uint8_t bright=255);    // цвета 0-1530 + яркость 
mData mWheel8(uint8_t color, uint8_t bright=255);  // цвета 0-255 + яркость
mData mHEX(uint32_t color);              // mHEX цвет
mData mHSV(uint8_t h, uint8_t s, uint8_t v);    // HSV 255, 255, 255
mData mHSVfast(uint8_t h, uint8_t s, uint8_t v);  // HSV 255, 255, 255
mData mKelvin(int kelvin);              // температура

// макросы уменьшения яркости
fade8(x, b)
fade8R(x, b)
fade8G(x, b)
fade8B(x, b) 

// упаковка-распаковка
getR(x)
getG(x)
getB(x)
mergeRGB(r,g,b)
mergeRGBraw(r,g,b)
getCRT(byte x) - получить скорректированное значение яркости x с учётом выбранной модели CRT гамма-коррекции
getCRT_PGM(byte x) - получить CRT из прогмем (работает только если выбрана PGM модель)
getCRT_SQUARE(byte x) - получить CRT по квадратной модели
getCRT_QUBIC(byte x) - получить CRT по кубической модели
RGB24to16(x) - конвертация 24-бит цвета в 16-бит
RGB24to8(x) - конвертация 24-бит цвета в 8-бит
RGB16to24(x) - конвертация 16-бит цвета в 24-бит
RGB8to24(x) - конвертация 8-бит цвета в 24-бит
RGB24toR(x) - вытащить байт R из 24-бит цвета
RGB24toG(x) - вытащить байт G из 24-бит цвета
RGB24toB(x) - вытащить байт B из 24-бит цвета
RGBto24(r,g,b) - склеить 24-бит цвет
RGBto16(r,g,b) - склеить 16-бит цвет
RGBto8(r,g,b) - склеить 8-бит цвет

ПРИМЕРЫ


Примеров очень много, тут выложу самые основные. Остальные прошу на гитхаб или просто качаем либу.
// базовый пример работы с лентой, основные возможности
// библиотека microLED версии 3.0+
// для более подробной информации читай документацию

// константы для удобства
#define STRIP_PIN 2     // пин ленты
#define NUMLEDS 20      // кол-во светодиодов

// ===== ЦВЕТОВАЯ ГЛУБИНА =====
// 1, 2, 3 (байт на цвет)
// на меньшем цветовом разрешении скетч будет занимать в разы меньше места,
// но уменьшится и количество оттенков и уровней яркости!
// дефайн делается ДО ПОДКЛЮЧЕНИЯ БИБЛИОТЕКИ
// без него будет 3 байта по умолчанию
#define COLOR_DEBTH 3

#include < microLED.h>   // подключаем библу

// ======= ИНИЦИАЛИЗАЦИЯ =======
// <колво-ледов, пин, клок пин, чип, порядок>
// microLED<NUMLEDS, DATA_PIN, CLOCK_PIN, LED_WS2818, ORDER_GRB> strip;
// CLOCK пин нужен только для SPI лент (например APA102)
// для обычных WS лент указываем MLED_NO_CLOCK
// по APA102 смотри отдельный гайд в примерах

// различные китайские подделки могут иметь совместимость
// с одним чипом, но другой порядок цветов!
// поддерживаемые чипы лент и их официальный порядок цветов:
// microLED< NUMLEDS, STRIP_PIN, -1, LED_WS2811, ORDER_GBR> strip;
// microLED< NUMLEDS, STRIP_PIN, -1, LED_WS2812, ORDER_GRB> strip;
// microLED< NUMLEDS, STRIP_PIN, -1, LED_WS2813, ORDER_GRB> strip;
// microLED< NUMLEDS, STRIP_PIN, -1, LED_WS2815, ORDER_GRB> strip;
// microLED< NUMLEDS, STRIP_PIN, -1, LED_WS2818, ORDER_RGB> strip;
// microLED< NUMLEDS, STRIP_PIN, -1, LED_WS6812, ORDER_RGB> strip;
// microLED< NUMLEDS, STRIP_PIN, CLOCK_PIN, LED_APA102, ORDER_BGR> strip;
// microLED< NUMLEDS, MLED_NO_CLOCK, MLED_NO_CLOCK, LED_APA102_SPI, ORDER_BGR> strip;	// для аппаратного SPI


// ======= ПРЕРЫВАНИЯ =======
// для повышения надёжности передачи данных на ленту можно отключать прерывания.
// В библиотеке есть 4 режима:
// CLI_OFF - прерывания не отключаются (возможны сбои в работе ленты)
// CLI_LOW - прерывания отключаются на время передачи одного цвета
// CLI_AVER - прерывания отключаются на время передачи одного светодиода (3 цвета)
// CLI_HIGH - прерывания отключаются на время передачи даных на всю ленту

// По умолчанию отключение прерываний стоит на CLI_OFF (не отключаются)
// Параметр передаётся 5ым при инициализации:
// microLED< NUMLEDS, STRIP_PIN, LED_WS2818, ORDER_GRB, CLI_AVER> strip;

// ======= СПАСИТЕ МИЛЛИС =======
// При отключении прерываний в режиме среднего и высокого проритета (CLI_AVER и CLI_HIGH)
// неизбежно будут чуть отставать функции времени millis() и micros()
// В библиотеке встроено обслуживание функций времени, для активации передаём SAVE_MILLIS
// 6-ым аргументом при инициализации:
// microLED< NUMLEDS, STRIP_PIN, -1, LED_WS2818, ORDER_GRB, CLI_AVER, SAVE_MILLIS> strip;
// это НЕЗНАЧИТЕЛЬНО замедлит вывод на ленту, но позволит миллису считать без отставания!

// инициализирую ленту (выше был гайд!)
microLED< NUMLEDS, STRIP_PIN, -1, LED_WS2818, ORDER_GRB, CLI_AVER> strip;

void setup() {
  // ===================== БАЗОВЫЕ ШТУКИ =====================
  // яркость (0-255)
  strip.setBrightness(60);
  // яркость применяется по CRT гамме
  // применяется при выводе .show() !

  // очистка буфера (выключить диоды, чёрный цвет)
  strip.clear();
  // применяется при выводе .show() !

  strip.show(); // вывод изменений на ленту
  delay(1);     // между вызовами show должна быть пауза минимум 40 мкс !!!!

  // ===================== УСТАНОВКА ЦВЕТА =====================
  // Библиотека поддерживает два варианта работы с лентой:
  // изменение цвета конкретного диода при помощи функции set(диод, цвет)
  // или работа с массивом .leds[] "вручную"

  // запись strip.set(диод, цвет); равносильна strip.leds[диод] = цвет;

  // ------------- ОСНОВНЫЕ ФУНКЦИИ РАБОТЫ С ЦВЕТОМ ------------
  // указанные ниже функции врзвращают тип данных mData - сжатое представление цвета

  // mRGB(uint8_t r, uint8_t g, uint8_t b);   // цвет RGB, 0-255 каждый канал
  strip.set(0, mRGB(255, 0, 0));              // диод 0, цвет RGB (255 0 0) (красный)

  // mHSV(uint8_t h, uint8_t s, uint8_t v);   // цвет HSV, 0-255 каждый канал
  strip.leds[1] = mHSV(30, 255, 255);         // диод 1, (цвет 30, яркость и насыщенность максимум)

  // mHSVfast(uint8_t h, uint8_t s, uint8_t v); // цвет HSV, 0-255 каждый канал
  // расчёт выполняется чуть быстрее, но цвета не такие плавные
  strip.set(2, mHSVfast(90, 255, 255));         // диод 2, цвет 90, яркость и насыщенность максимум

  // mHEX(uint32_t color);        // WEB цвета (0xRRGGBB)
  strip.set(3, mHEX(0x30B210));   // диод 3, цвет HEX 0x30B210

  // в библиотеке есть 17 предустановленных цветов (макс. яркость)
  strip.leds[4] = mAqua;          // диод 4, цвет aqua

  // mWheel(int color);                   // цвета радуги 0-1530
  // mWheel(int color, uint8_t bright);   // цвета радуги 0-1530 + яркость 0-255
  strip.set(5, mWheel(1200));             // диод 5, цвет 1200

  // mWheel8(int color);                  // цвета радуги 0-255
  // mWheel8(int color, uint8_t bright);  // цвета радуги 0-255 + яркость 0-255
  //strip.set(6, mWheel8(100));     // диод 6, цвет 100 (диапазон 0-255 вдоль радуги)
  strip.set(6, mWheel8(100, 50));   // вторым параметром можно передать яркость

  // mKelvin(int kelvin);           // цветовая температура 1'000-40'000 Кельвин
  strip.set(7, mKelvin(3500));      // диод 7, цветовая температура 3500К

  strip.show();                     // выводим все изменения на ленту
  delay(2000);                      // задержка показа

  // ===================== ЗАЛИВКА =====================
  // Есть готовая функция для заливки всей ленты цветом - .fill()
  // принимает конвертированный цвет, например от функций цвета или констант выше
  strip.fill(mYellow);  // заливаем жёлтым
  strip.show();         // выводим изменения
  delay(2000);

  // также можно указать начало и конец заливки
  strip.fill(3, 7, mWheel8(100));   // заливаем ~зелёным с 3 по 6: счёт идёт с 0, заливается до указанного -1
  strip.show();                     // выводим изменения
  delay(2000);

  // ------------- РУЧНАЯ ЗАЛИВКА В ЦИКЛЕ ------------
  // Например покрасим половину ленты в один, половину в другой
  for (int i = 0; i < NUMLEDS / 2; i++) strip.leds[i] = mHSV(0, 255, 255);  	  // красный
  for (int i = NUMLEDS / 2; i < NUMLEDS; i++) strip.leds[i] = mHSV(80, 255, 255); // примерно зелёный
  strip.show(); // выводим изменения
  delay(2000);

  // ------------------------------------------
  // Для ускорения ручных заливок (ускорения расчёта цвета) можно создать переменную типа mData
  mData value1, value2;
  value1 = mHSV(60, 100, 255);
  value2 = mHSV(190, 255, 190);
  for (int i = 0; i < NUMLEDS; i++) {
    if (i < NUMLEDS / 2) strip.leds[i] = value1;  // первая половина ленты
    else strip.leds[i] = value2;                  // вторая половина ленты
  }
  strip.show(); // выводим изменения
  delay(2000);

  // ------------------------------------------
  // в цикле можно менять параметры генерации цвета. Например, сделаем радугу
  for (int i = 0; i < NUMLEDS; i++) strip.set(i, mWheel8(i * 255 / NUMLEDS)); // полный круг от 0 до 255
  strip.show(); // выводим изменения
  delay(2000);

  // или градиент от красного к чёрному (последовательно меняя яркость)
  for (int i = 0; i < NUMLEDS; i++) strip.set(i, mWheel8(0, i * 255 / NUMLEDS)); // полный круг от 0 до 255
  strip.show(); // выводим изменения
}

void loop() {
}
// простейшие динамические эффекты
// сначала ознакомься с примером microLED_guide !!!

#define STRIP_PIN 2     // пин ленты
#define NUMLEDS 20      // кол-во светодиодов

#define COLOR_DEBTH 3
#include < microLED.h>   // подключаем библу
microLED<NUMLEDS, STRIP_PIN, -1, LED_WS2818, ORDER_GRB, CLI_AVER> strip;

void setup() {
  strip.setBrightness(60);
}

void loop() {
  // раскомментируй нужный эффект
  
  rainbow();      // бегущая радуга во всю ленту
  //filler();       // плавное заполнение
  //colorCycle();   // плавная смена цвета
  //runningDots();  // бегущие точки

  // вывод
  breathing();    // "дыхание" яркости, применяется ко всем эффектам
  strip.show();   // вывод
  delay(30);      // 30 кадров в секунду
}

void rainbow() {
  static byte counter = 0;
  for (int i = 0; i < NUMLEDS; i++) { strip.set(i, mWheel8(counter + i * 255 / NUMLEDS)); // counter смещает цвет } counter += 3; // counter имеет тип byte и при достижении 255 сбросится в 0 } void filler() { static int counter = 0; strip.clear(); strip.fill(0, counter, mRed); counter++; if (counter >= NUMLEDS) counter = 0;
}

void colorCycle() {
  static byte counter = 0;
  strip.fill(mWheel8(counter));
  counter += 3;
}

void runningDots() {
  static byte counter = 0;
  // перемотка буфера со сдвигом (иллюзия движения пикселей)
  for (int i = 0; i < NUMLEDS - 1; i++) strip.leds[i] = strip.leds[i + 1]; // каждый третий вызов - последний пиксель красным, иначе чёрным if (counter % 3 == 0) strip.leds[NUMLEDS - 1] = mRed; else strip.leds[NUMLEDS - 1] = mBlack; counter++; delay(100); // дополнительная задержка } void breathing() { static int dir = 1; static int bright = 0; bright += dir * 5; // 5 - множитель скорости изменения if (bright > 255) {
    bright = 255;
    dir = -1;
  }
  if (bright < 0) {
    bright = 0;
    dir = 1;
  }
  strip.setBrightness(bright);
}
// пример с tinyLED, должно работать на всех тиньках и мегах

// дефайны настроек, прописываются перед подключением либы
#define TLED_ORDER ORDER_GRB   // порядок цветов
#define TLED_CHIP LED_WS2812   // чип светодиода ленты

/*
  Доступные модели лент и их порядок цветов
  Китайцы могут продавать копию с другим порядком =)
  LED_WS2811 // ORDER_GBR
  LED_WS2812 // ORDER_GRB
  LED_WS2813 // ORDER_GRB
  LED_WS2815 // ORDER_GRB
  LED_WS2818 // ORDER_RGB
  LED_WS6812 // ORDER_RGB + W
  LED_APA102 // ORDER_BGR
  LED_APA102_SPI // ORDER_BGR
*/

// ===== 1 пин ленты =====
// по умолч. PORTB
// можно указать свой порт, если у тиньки больше 8 ног или это вообще атмега
// пин указывается при создании
// #define TLED_PORT PORTB
// #define TLED_DDR DDRB

// ===== 2 пин SPI ленты =====
// программный SPI, например LED_APA102
// по умолч. PORTB
// можно указать свой порт, если у тиньки больше 8 ног или это вообще атмега
// пин указывается при создании
// #define TLED_CLK_PORT PORTB
// #define TLED_CLK_DDR DDRB
// #define TLED_DAT_PORT PORTB
// #define TLED_DAT_DDR DDRB

// ===== Запрет прерываний =====
// можно указать приоритет прерываний (умолч CLI_LOW):
// #define TLED_CLI CLI_OFF  // прерывания не запрещаются
// #define TLED_CLI CLI_LOW  // запрещаются на время передачи байта
// #define TLED_CLI CLI_AVER // запрещаются на время передачи светодиода (3 байта)
// #define TLED_CLI CLI_HIGH // запрещаются на время передачи всей ленты

// ===== Яркость =====
// #define TLED_STATIC_BRIGHT  // отключает изменение общей яркости вывода и экономит 60 байт флэш

// ===== SPI лента =====
// только при выборе LED_APA102_SPI
// пины не указываются в скетче
// #define TLED_SPI_CLOCK 8000000	// скорость аппаратного SPI для ленты LED_APA102_SPI

// либа
#include "tinyLED.h"
tinyLED< 3> strip;       // указываем пин (в порядке порта)
// tinyLED<3, 4> strip; // <DATA, CLOCK> для 2-пин лент (APA102)
// tinyLED strip;       // для LED_APA102_SPI не указываем пины ВООБЩЕ!

#define NUMLEDS 50 // количество светодиодов (для циклов)

void setup() {
  // begin() - начать отправку (НУЖНО ТОЛЬКО ДЛЯ SPI ЛЕНТ ИЛИ CLI_HIGH)
  // end() - закончить отправку (НУЖНО ТОЛЬКО ДЛЯ SPI ЛЕНТ ИЛИ CLI_HIGH)
  // write() - отправить один байт
  // sendRGB(r,g,b) - отправить цвет на 1 диод
  // sendRGBW(r,g,b,w) - отправить на rgbw ленту (например WS6812)
  // send(mData) - отправить цвет в формате mData
  // sendBuffer(mData буфер, размер) - отправить внешний буфер на ленту
  // clear(размер) - очистить на длину
  // setBrightness(0-255) - яркость для всего вывода

  // каждый вывод "задвигает" указанный цвет
  // чтобы остановить вывод - перестаём вызывать функцию на 50-300 мкс (зависит от чипа)
  // =================================================
  //strip.begin();
  strip.sendRGB(255, 255, 255); // отправить r,g,b на первый лед
  strip.send(mOrange);      // отправить оранжевый
  strip.send(mAqua);        // голубой
  strip.send(mPurple);      // и розовый
  //strip.end();
  // леды загорятся вот так:
  // начало--розовый--аква--оранж--белый
  delay(5000);              // пауза

  // =================================================
  // зальём 50 ледов белым. Вывод начнётся с начала!!
  //strip.begin();
  for (byte i = 0; i < 10; i++) strip.send(mYellow);
  //strip.end();
  delay(5000);              // пауза

  // =================================================
  // зальём 50 ледов с чередованием жёлтый-чёрный
  //strip.begin();
  for (byte i = 0; i < 50; i++) {
    strip.send(i % 2 == 0 ? mYellow : mBlack);
  }
  //strip.end();
  delay(5000);              // пауза
}

void loop() {
  // =================================================
  // иииии бегущая радуга!
  static byte count;
  count++;
  //strip.begin();
  for (int i = 0; i < NUMLEDS; i++) {
    strip.send(mWheel8(count + i * 255 / NUMLEDS)); // выводим радугу
  }
  //strip.end();
  delay(30);
}
// пример работы с матрицей 32x8
#define M_PIN 8       // пин матрицы
#define M_WIDTH 32    // ширина матрицы
#define M_HEIGHT 8    // высота матрицы
#define NUM_LEDS (M_WIDTH * M_HEIGHT) // для удобства запомним и количство ледов

#include < microLED.h>
#include < FastLEDsupport.h>    // нужна для шума

// инициализация у матрицы такая же, как у ленты, но добавляются параметры в (скобках)
microLED< NUM_LEDS, M_PIN, MLED_NO_CLOCK, LED_WS2812, ORDER_GRB, CLI_AVER> matrix(M_WIDTH, M_HEIGHT, ZIGZAG, LEFT_TOP, DIR_DOWN);
// тип матрицы: ZIGZAG - зигзаг, PARALLEL - параллельная
// угол подключения: LEFT_BOTTOM - левый нижний, LEFT_TOP - левый верхний, RIGHT_TOP - правый верхний, RIGHT_BOTTOM - правый нижний
// направление ленты из угла подключения: DIR_RIGHT - вправо, DIR_UP - вверх, DIR_LEFT - влево, DIR_DOWN - вниз
// шпаргалка по настройке матрицы в папке docs в библиотеке

void setup() {
  matrix.setBrightness(100);  // яркость (0-255)

  // Проверка ориентации матрицы
  // Система координат - декартовая первая четверть (левый нижний угол - 0)
  // Левый нижний угол - жёлтый
  // Левый верхний - пурпурный
  // Правый нижний - голубой

  // для установки пикселя используем set(x, y, цвет)
  // всё остальное - так же как у ленты!!!

  matrix.set(0, 0, mYellow);
  matrix.set(0, 7, mPurple);
  matrix.set(7, 0, mTeal);
  matrix.show();
  delay(3000);
  matrix.clear();
}

void loop() {
  // примеры эффектов

  rainbow2D();
  //fire2D();
  //fire2D();
  //rainbow();    // горизонтальная радуга
  //balls();      // шарики
  //confetti();

  matrix.show();
  delay(30);
}

// =========== РАДУГА ===========
void rainbow() {
  static byte hue = 0;
  hue += 5;
  for (int i = 0; i < M_WIDTH; i++) {
    for (int j = 0; j < M_HEIGHT; j++)
      matrix.set(i, j, mWheel8(hue + i * 255 / M_WIDTH));
  }
}

// =========== ШАРИКИ ===========
#define BALLS_AMOUNT 5
boolean loadingFlag = true;
int coord[BALLS_AMOUNT][2];
int8_t vector[BALLS_AMOUNT][2];
mData ballColors[BALLS_AMOUNT];

void balls() {
  if (loadingFlag) {
    loadingFlag = false;
    for (byte j = 0; j < BALLS_AMOUNT; j++) {
      int sign;
      // забиваем случайными данными
      coord[j][0] = M_WIDTH / 2 * 10;
      random8(0, 2) ? sign = 1 : sign = -1;
      vector[j][0] = random8(4, 15) * sign;
      coord[j][1] = M_HEIGHT / 2 * 10;
      random8(0, 2) ? sign = 1 : sign = -1;
      vector[j][1] = random8(4, 15) * sign;
      ballColors[j] = mWheel8(random8(0, 9) * 28);
    }
  }

  matrix.clear();  // очистить

  // движение шариков
  for (byte j = 0; j < BALLS_AMOUNT; j++) {
    for (byte i = 0; i < 2; i++) {
      coord[j][i] += vector[j][i];
      if (coord[j][i] < 0) { coord[j][i] = 0; vector[j][i] = -vector[j][i]; } } if (coord[j][0] > (M_WIDTH - 1) * 10) {
      coord[j][0] = (M_WIDTH - 1) * 10;
      vector[j][0] = -vector[j][0];
    }
    if (coord[j][1] > (M_HEIGHT - 1) * 10) {
      coord[j][1] = (M_HEIGHT - 1) * 10;
      vector[j][1] = -vector[j][1];
    }
    matrix.set(coord[j][0] / 10, coord[j][1] / 10, ballColors[j]);
  }
}

// =========== КОНФЕТТИ ===========
void confetti() {
  for (int i = 0; i < NUM_LEDS; i++) {
    if (matrix.get(i) == 0)
      if (random8(0, 100) == 0) matrix.set(i, mWheel8(random8()));
    matrix.fade(i, 30);
  }
}

// =========== ОГОНЬ ===========
mGradient<4> myGrad;
boolean loadingFlag2 = true;
void fire2D() {
  static int count = 0;
  if (loadingFlag2) {
    loadingFlag2 = false;
    // заполняем палитру
    myGrad.colors[0] = mBlack;
    myGrad.colors[1] = mRed;
    myGrad.colors[2] = mYellow;
    myGrad.colors[3] = mWhite;
  }
  for (int i = 0; i < M_WIDTH; i++)
    for (int j = 0; j < M_HEIGHT; j++)
      matrix.set(i, j, myGrad.get(inoise8(i * 50, j * 50, count), 255));
  count += 20;
}

// =========== РАДУЖНЫЕ ШТУКИ ===========
void rainbow2D() {
  static int count = 0;
  static byte count2 = 0;
  for (int i = 0; i < M_WIDTH; i++)
    for (int j = 0; j < M_HEIGHT; j++)
      matrix.set(i, j, mWheel8(count2 + inoise8(i * 50, j * 50, count), 255));
  count += 20;
  count2++;
}