#

Как сделать светодиодную матрицу RGB для цветовых эффектов

Давно интересовали цвето-световые эффекты, которые можно создать на основе RGB-светодиодов. Например, одну реализацию вы могли видеть в проекте Алкотестер RGB.

Содержание статьи:
1. Электрическая схема
2. Сборка устройства
3. Программа тестирования
3.1. Огненный эффект
3.2. Вывод текста
4. Видеоинструкции

Но намного более интересные вещи можно создать на адресных светодиодных лентах. У них есть явное преимущество — можно управлять цветом и яркостью любого светодиода всего по одному сигнальному проводу!
В интернете есть красивые примеры такой реализации светильников, но захотелось создать свой оригинальный вариант на основе фоторамки.
Эта рамка должна уметь выводить различные цветные изображения в виде набора пятен. Таким образом формируются тот или иной эффект.

Электрическая схема соединений

Вот схема матрицы, которая легла в основу RGB фоторамки.

Как сделать светодиодную матрицу RGB для цветовых эффектов


Матрица построена по схеме параллельного соединения адресных светодиодных лент. Это сделано для равномерной подачи питания ко всем светодиодным модулям.

Процесс сборки цветового монитора

В качестве основы был использован лист толстой алюминиевой фольги. Он выполнит функции распределения тепла, экранирования сигнального провода от помех, отражателя света.
В фольге были сделаны пазы для сигнального провода, также выполняющие роль ребер жесткости. Затем лента обрезалась под размер заготовки, по 11 светодиодов на строку (при 60 светодиодов на метр).

Как сделать светодиодную матрицу RGB для цветовых эффектов

Перед установкой ленты поверхности обезжириваются бензином.
Вклейка начинается с нижней строки. Лента устанавливается так, чтобы контакты Din были вдоль левой стороны.
После этого нужно аккуратно залудить контакты. Залуживать нужно все сигнальные выводы Din и Dout и питающие только с одной стороны.
Сигнальный провод хорошо пропускается в сформированный алюминиевый канал от правой части ленты к левой части следующей строки. Потом припаиваются все силовые провода.

Как сделать светодиодную матрицу RGB для цветовых эффектов

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

Как сделать светодиодную матрицу RGB для цветовых эффектов

Теперь берем фоторамку нужного размера.

Как сделать светодиодную матрицу RGB для цветовых эффектов

Для того, чтобы излучение было корректно смешано и в тоже время не сильно размыто была применена бумага для выпечки. Экспериментально обнаружено, что если её расположить на расстоянии 20 мм от основания матрицы, будет баланс между смешиванием цветов и разрешающей способностью для вывода текста. Поэтому была сделана проставка из картона высотой 20 мм. Данная проставка вклеивалась на основу фоторамки и дополнительно укреплялась степлером.

Как сделать светодиодную матрицу RGB для цветовых эффектов

Рассеиватель закреплялся клеем карандашом по краям стекла.

Как сделать светодиодную матрицу RGB для цветовых эффектов

В коробе вырезалось отверстие под провода.
Матрица фиксировалась на термоклей и дополнительно сверху по углам.

Как сделать светодиодную матрицу RGB для цветовых эффектов

Затем остается зафиксировать короб с матрицей в раме при помощи алюминиевых уголков и саморезов.

Как сделать светодиодную матрицу RGB для цветовых эффектов

Программа тестирования монитора на Ардуино

Для проверки работы можно применить два скетча: с огнем и с текстом.

Огненный алгоритм взят от AlexGyver, а текст от NeoPixel.

Проверка огня.

Для работы алгоритма нужно установить библиотеку microLED.h

// настройки ленты
#define M_WIDTH 11      // ширина матрицы
#define M_HEIGHT 8      // высота матрицы
#define LED_PIN 13       // пин ленты
#define LED_BRIGHT 200  // яркость

// настройки пламени
#define FIRE_SCALE 32   // масштаб огня
#define HUE_GAP 60      // заброс по hue
#define FIRE_STEP 30    // шаг изменения "языков" пламени
#define HUE_START 0     // начальный цвет огня (0 красный, 80 зелёный, 140 молния, 190 розовый)
#define HUE_COEF 0.7    // коэффициент цвета огня (чем больше - тем дальше заброс по цвету)
#define SMOOTH_K 0.15   // коэффициент плавности огня
#define MIN_BRIGHT 50   // мин. яркость огня
#define MAX_BRIGHT 255  // макс. яркость огня
#define MIN_SAT 180     // мин. насыщенность
#define MAX_SAT 255     // макс. насыщенность
#define ORDER_GRB       // порядок цветов ORDER_GRB / ORDER_RGB / ORDER_BRG
#define COLOR_DEBTH 3   // цветовая глубина: 1, 2, 3 (в байтах)

#include <microLED.h>
#define NUM_LEDS M_WIDTH * M_HEIGHT
LEDdata leds[NUM_LEDS];  // буфер ленты типа LEDdata
microLED matrix(leds, LED_PIN, M_WIDTH, M_HEIGHT, PARALLEL, LEFT_BOTTOM, DIR_RIGHT);  // объект матрица
#define NUM_LEDS M_WIDTH*M_HEIGHT
unsigned char matrixValue[8][16];
unsigned char line[M_WIDTH];
int pcnt = 0;
#define FOR_i(from, to) for(int i = (from); i < (to); i++)
#define FOR_j(from, to) for(int j = (from); j < (to); j++)
void setup() {
  matrix.setBrightness(LED_BRIGHT);  // яркость (0-255)
  generateLine();
  memset(matrixValue, 0, sizeof(matrixValue));
}
void loop() {
  fireRoutine();
}
// ********************** огонь **********************
//these values are substracetd from the generated values to give a shape to the animation
const unsigned char valueMask[8][11] PROGMEM = {
  {0  , 0  , 0  , 0  , 0  , 0  , 0  , 0  , 0  , 0  , 0  },
  {0  , 0  , 0  , 0  , 32  , 32  , 0  , 0 , 0 , 0  , 0  },
  {0  , 32 , 0  , 0  , 64  , 64  , 32 , 0 , 0 ,  0 , 0  },
  {0  , 64 , 32 , 32 , 32  , 32  , 64 ,64 ,32 , 64 , 0  },
  {0  , 96 , 64 , 32 , 32 , 64 , 96 , 160, 160, 96 , 32 },
  {64, 128, 96 , 64 , 64 , 96 , 128, 192, 192, 128, 96 },
  {120, 160, 128, 96 , 96 , 128, 160, 255, 255, 160, 128},
  {160, 192, 160, 128, 128, 160, 192, 255, 255, 192, 160}
};
//these are the hues for the fire,
//should be between 0 (red) to about 25 (yellow)
const unsigned char hueMask[8][11] PROGMEM = {
  {1 , 11, 19, 25, 25, 22, 11, 1 , 1 , 11, 19},
  {1 , 8 , 13, 19, 25, 19, 8 , 1 , 1 , 8 , 13},
  {1 , 8 , 13, 16, 19, 16, 8 , 1 , 1 , 8 , 13},
  {1 , 5 , 11, 13, 13, 13, 5 , 1 , 1 , 5 , 11},
  {1 , 5 , 11, 11, 11, 11, 5 , 1 , 1 , 5 , 11},
  {0 , 1 , 5 , 8 , 8 , 5 , 1 , 0 , 0 , 1 , 5 },
  {0 , 0 , 1 , 5 , 5 , 1 , 0 , 0 , 0 , 0 , 1 },
  {0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 }
};
void fireRoutine() {
  static uint32_t prevTime = 0;
  if (millis() - prevTime > 30) {
    prevTime = millis();
    if (pcnt >= 100) {
      shiftUp();
      generateLine();
      pcnt = 0;
    }
    drawFrame(pcnt);
    pcnt += 30;
    matrix.show();
  }
}
// Randomly generate the next line (matrix row)
void generateLine() {
  for (uint8_t x = 0; x < M_WIDTH; x++) {
    line[x] = random(64, 255);
  }
}
//shift all values in the matrix up one row
void shiftUp() {
  for (uint8_t y = M_HEIGHT - 1; y > 0; y--) {
    for (uint8_t x = 0; x < M_WIDTH; x++) {
      uint8_t newX = x;
      if (x > 15) newX = x % 16;
      if (y > 7) continue;
      matrixValue[y][newX] = matrixValue[y - 1][newX];
    }
  }
  for (uint8_t x = 0; x < M_WIDTH; x++) {
    uint8_t newX = x;
    if (x > 15) newX = x % 16;
    matrixValue[0][newX] = line[newX];
  }
}
// draw a frame, interpolating between 2 "key frames"
// @param pcnt percentage of interpolation
void drawFrame(int pcnt) {
  int nextv;
  //each row interpolates with the one before it
  for (unsigned char y = M_HEIGHT - 1; y > 0; y--) {
    for (unsigned char x = 0; x < M_WIDTH; x++) {
      uint8_t newX = x;
      if (x > 15) newX = x % 16;
      if (y < 8) {
        nextv =
          (((100.0 - pcnt) * matrixValue[y][newX]
            + pcnt * matrixValue[y - 1][newX]) / 100.0)
          - pgm_read_byte(&(valueMask[y][newX]));

        LEDdata color = mHSV(
                          HUE_START + pgm_read_byte(&(hueMask[y][newX])), // H
                          255, // S
                          (uint8_t)max(0, nextv) // V
                        );

        matrix.setPix(x, y, color);
      } else if (y == 8) {
        if (random(0, 20) == 0 && matrix.getColorHEX(x, y - 1) != 0) matrix.setPix(x, y, mHEX(matrix.getColorHEX(x, y - 1)));
        else matrix.setPix(x, y, mHEX(0));
      } else if (true) {

        // старая версия для яркости
        if (matrix.getColorHEX(x, y - 1) > 0)
          matrix.setPix(x, y, mHEX(matrix.getColorHEX(x, y - 1)));
        else matrix.setPix(x, y, mHEX(0));
      }
    }
  }
  //first row interpolates with the "next" line
  for (unsigned char x = 0; x < M_WIDTH; x++) {
    uint8_t newX = x;
    if (x > 15) newX = x % 16;
    LEDdata color = mHSV(
                      HUE_START + pgm_read_byte(&(hueMask[0][newX])), // H
                      255,           // S
                      (uint8_t)(((100.0 - pcnt) * matrixValue[0][newX] + pcnt * line[newX]) / 100.0) // V
                    );
    matrix.setPix(x, 0, color);
  }
}
Как сделать светодиодную матрицу RGB для цветовых эффектов

В результате на экране появится динамически меняющийся эффект огня. Выглядит довольно эффектно и реалистично (см.видео). Однако не устроил на все 100%, поэтому будет произведена разработка нового алгоритма.

Проверка текстового вывода

Данная программа будет выводить на монитор бегущую строку с текстом 11:00.
Для работы программы требуется установить следующие библиотеки: Adafruit_GFX, Adafruit_NeoMatrix, Adafruit_NeoPixel.

// Adafruit_NeoMatrix example for single NeoPixel Shield.
#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>
#ifndef PSTR
 #define PSTR // Make Arduino Due happy
#endif
#define PIN 13

Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(11, 8, PIN,
  NEO_MATRIX_BOTTOM     + NEO_MATRIX_LEFT +
  NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE,
  NEO_RGB            + NEO_KHZ800);

const uint16_t colors[] = {
  matrix.Color(255, 0, 0), matrix.Color(0, 255, 0), matrix.Color(0, 0, 255) };

void setup() {
  matrix.begin();
  matrix.setTextWrap(false);
  matrix.setBrightness(40);
  matrix.setTextColor(colors[0]);
}

int x    = matrix.width();
int pass = 0;

void loop() {
  matrix.fillScreen(0);
  matrix.setCursor(x, 0);
  matrix.print(F("11:00"));
  if(--x < -36) {
    x = matrix.width();
    if(++pass >= 3) pass = 0;
    matrix.setTextColor(colors[pass]);
  }
  matrix.show();
  delay(100);
}

Текст читаем и выглядит довольно эффектно в темноте!

Как сделать светодиодную матрицу RGB для цветовых эффектов

Видео пояснения

Данная светодиодная RGB матрица будет использована как элемент проекта «Умная фоторамка«. Новости по данному проекту будут опубликованы в сообществе ВК. Подписывайтесь, чтобы не пропустить.

(с) Роман Исаков, 2020