Как сделать светодиодную матрицу RGB для цветовых эффектов
Давно интересовали цвето-световые эффекты, которые можно создать на основе RGB-светодиодов. Например, одну реализацию вы могли видеть в проекте Алкотестер RGB.
Содержание статьи:
1. Электрическая схема
2. Сборка устройства
3. Программа тестирования
3.1. Огненный эффект
3.2. Вывод текста
4. Видеоинструкции
Но намного более интересные вещи можно создать на адресных светодиодных лентах. У них есть явное преимущество — можно управлять цветом и яркостью любого светодиода всего по одному сигнальному проводу!
В интернете есть красивые примеры такой реализации светильников, но захотелось создать свой оригинальный вариант на основе фоторамки.
Эта рамка должна уметь выводить различные цветные изображения в виде набора пятен. Таким образом формируются тот или иной эффект.
Электрическая схема соединений
Вот схема матрицы, которая легла в основу RGB фоторамки.
Матрица построена по схеме параллельного соединения адресных светодиодных лент. Это сделано для равномерной подачи питания ко всем светодиодным модулям.
Процесс сборки цветового монитора
В качестве основы был использован лист толстой алюминиевой фольги. Он выполнит функции распределения тепла, экранирования сигнального провода от помех, отражателя света.
В фольге были сделаны пазы для сигнального провода, также выполняющие роль ребер жесткости. Затем лента обрезалась под размер заготовки, по 11 светодиодов на строку (при 60 светодиодов на метр).
Перед установкой ленты поверхности обезжириваются бензином.
Вклейка начинается с нижней строки. Лента устанавливается так, чтобы контакты Din были вдоль левой стороны.
После этого нужно аккуратно залудить контакты. Залуживать нужно все сигнальные выводы Din и Dout и питающие только с одной стороны.
Сигнальный провод хорошо пропускается в сформированный алюминиевый канал от правой части ленты к левой части следующей строки. Потом припаиваются все силовые провода.
Можно также установить антистатическую пленку на термоклей. Она выполняет роль дополнительной защиты электрических соединений.
По краям приклеить белую бумагу, чтобы соединения не отсвечивали.
Теперь берем фоторамку нужного размера.
Для того, чтобы излучение было корректно смешано и в тоже время не сильно размыто была применена бумага для выпечки. Экспериментально обнаружено, что если её расположить на расстоянии 20 мм от основания матрицы, будет баланс между смешиванием цветов и разрешающей способностью для вывода текста. Поэтому была сделана проставка из картона высотой 20 мм. Данная проставка вклеивалась на основу фоторамки и дополнительно укреплялась степлером.
Рассеиватель закреплялся клеем карандашом по краям стекла.
В коробе вырезалось отверстие под провода.
Матрица фиксировалась на термоклей и дополнительно сверху по углам.
Затем остается зафиксировать короб с матрицей в раме при помощи алюминиевых уголков и саморезов.
Программа тестирования монитора на Ардуино
Для проверки работы можно применить два скетча: с огнем и с текстом.
Огненный алгоритм взят от 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); } }
В результате на экране появится динамически меняющийся эффект огня. Выглядит довольно эффектно и реалистично (см.видео). Однако не устроил на все 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 матрица будет использована как элемент проекта «Умная фоторамка«. Новости по данному проекту будут опубликованы в сообществе ВК. Подписывайтесь, чтобы не пропустить.
(с) Роман Исаков, 2020