Лёгкая библиотека для адресной ленты v3.5

ОБНОВЛЕНИЯ


  • v3.3 Исправлен критический баг с влиянием на другие пины

  • v3.4

    • Переработан ASM вывод, меньше весит, легче адаптируется под другие частоты / тайминги
    • Добавлена поддержка LGT8F328P с частотой 32/16/8 MHz
    • Переработан поллинг millis()/micros() — прямой вызов прерывания TIMER0_OVF, убран лишний код
  • v3.5 Исправлена ошибка компиляции в некоторых угодных компилятору случаях

ТЕОРИЯ


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

БИБЛИОТЕКА


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.

УСТАНОВКА


  • Библиотеку можно найти и установить через менеджер библиотек по названию microLED в:
    • Arduino IDE (Инструменты/Управлять библиотеками)
    • Arduino IDE v2 (вкладка «Library Manager»)
    • PlatformIO (PIO Home, вкладка «Libraries»)
  • Про ручную установку читай здесь

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


ОСОБЕННОСТИ


Данная библиотека нужна для проектов с лентой, в которых критичен объём занимаемой оперативной памяти: его можно уменьшить в 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-bit NeoPixel 24-bit WS2812 24-bit microLED 24-bit microLED 16-bit microLED 8-bit
8 400 1818 3260 4782 4420 4460
16 400 1264 1751 2663 2437 2462
50 333 554 589 923 840 848
100 220 301 298 472 428 432
500 60 65 61 96 87 88
Занимаемая память (байт) от количества диодов, где LED - количество светодиодов (сравнение с другими библиотеками)
Память FastLED 24-bit NeoPixel 24-bit WS2812 24-bit microLED 24-bit microLED 16-bit microLED 8-bit
Flash 2786 1984 946 306 346 324
SRAM 90+3*LED 40+3*LED 31+3*LED 20+3*LED 20+2*LED 20+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-бит цвет

ПРИМЕРЫ


Остальные примеры смотри в папке examples библиотеки, также примеры можно открыть из Arduino IDE/Файл/Примеры

// базовый пример работы с лентой, основные возможности
// библиотека 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, MLED_NO_CLOCK, LED_WS2811, ORDER_GBR> strip;
// microLED<NUMLEDS, STRIP_PIN, MLED_NO_CLOCK, LED_WS2812, ORDER_GRB> strip;
// microLED<NUMLEDS, STRIP_PIN, MLED_NO_CLOCK, LED_WS2813, ORDER_GRB> strip;
// microLED<NUMLEDS, STRIP_PIN, MLED_NO_CLOCK, LED_WS2815, ORDER_GRB> strip;
// microLED<NUMLEDS, STRIP_PIN, MLED_NO_CLOCK, LED_WS2818, ORDER_RGB> strip;
// microLED<NUMLEDS, STRIP_PIN, MLED_NO_CLOCK, 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, MLED_NO_CLOCK, LED_WS2818, ORDER_GRB, CLI_AVER, SAVE_MILLIS> strip;
// это НЕЗНАЧИТЕЛЬНО замедлит вывод на ленту, но позволит миллису считать без отставания!

// инициализирую ленту (выше был гайд!)
microLED<NUMLEDS, STRIP_PIN, MLED_NO_CLOCK, 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() {
}
// пример работы с матрицей 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++;
}
// При помощи CRGBtoData() можно конвертировать CRGB в mDATA!
// Используем быструю математику FastLED и компактный вывод microLED
// для достижения максимума каефа при минимуме занятой памяти
#define LEDPIN 2
#include <microLED.h>
#include <FastLEDsupport.h> // вкл поддержку
microLED<0, LEDPIN, MLED_NO_CLOCK, LED_WS2818, ORDER_GRB, CLI_AVER> strip;

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

void loop() {
  static byte count = 0;
  static int count2 = 0;
  count++;
  count2 += 10;
  strip.begin();
  for (int i = 0; i < 50; i++) {
    // движется палитра полосатая
    //strip.send(CRGBtoData(ColorFromPalette(RainbowStripeColors_p, count + i * 3, 255, LINEARBLEND)));

    // рандомный шум радугой
    strip.send(CRGBtoData(ColorFromPalette(RainbowColors_p, inoise8(i * 20, count2), 255, LINEARBLEND)));
  }
  strip.end();
  delay(40);
}

/*
  // =========== ТО ЖЕ САМОЕ ДЛЯ ТИНИЛЕД ==========
  #define TLED_PORT PORTD  // выводил на Нанку, портД (пин D3)
  #define TLED_DDR DDRD
  #include <tinyLED.h>
  #include <FastLEDsupport.h>
  tinyLED<3> strip;
  void setup() {
  strip.setBrightness(100);
  }
  void loop() {
  static byte count = 0;
  static int count2 = 0;
  count++;
  count2 += 10;
  for (int i = 0; i < 50; i++) {
    // движется палитра полосатая
    //strip.send(CRGBtoData(ColorFromPalette(RainbowStripeColors_p, count + i * 3, 255, LINEARBLEND)));

    // рандомный шум радугой
    strip.send(CRGBtoData(ColorFromPalette(RainbowColors_p, inoise8(i * 20, count2), 255, LINEARBLEND)));
  }
  delay(40);
  }
*/
// пример с 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);
}
// пример работы с лентой без буфера

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

#include <microLED.h>
// количество светодиодов указываем 0
microLED<0, STRIP_PIN, MLED_NO_CLOCK, LED_WS2818, ORDER_GRB, CLI_AVER> strip;

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

void setup() {
  strip.setBrightness(150);

  // алгоритм вывода такой:
  // strip.begin();
  // strip.send(цвет);
  // strip.send(цвет);
  // ..........
  // strip.end();

  // функция send(цвет) загружает следующий цвет в ленту
  // при каждом новом вызове цвет передаётся "паравозиком" по ленте,
  // таким образом можно выводить на ленту любой длины.
  // Между вызовами send() должно пройти МЕНЬШЕ 50 мкс (для 2812), иначе вывод будет прерван
  // Это усложняет генерацию эффектов "на лету", потому что для некоторых банально не хватит скорости вычисления

  strip.begin();
  for (int i = 0; i < NUMLEDS; i++) {
    strip.send(mWheel8(i * 255 / NUMLEDS)); // выводим радугу
  }
  strip.end();
  delay(2000);
}

void loop() {
  // а тут давайте запустим генерацию гармонического шума по палитре радуги с дополнительным смещением спектра
  static int counter = 0;
  static byte counter2 = 0;
  counter += 10;
  counter2++;
  strip.begin();
  for (int i = 0; i < NUMLEDS; i++) strip.send(mWheel8(counter2 + inoise8(i * 50, counter)));
  strip.end();
  delay(30);
  // скорости достаточно! Эффект работает
}

ПОДДЕРЖАТЬ


Вы можете поддержать меня за создание доступных проектов с открытым исходным кодом, полный список реквизитов есть вот здесь.

5 1 голос
Рейтинг статьи
Подписаться
Уведомить о
guest

77 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
Прокрутить вверх