Обзор светодиодной матрицы из GearBest.com
- Войдите на сайт для отправки комментариев
GearBest.com: светодиодная матрица
Давайте посмотрим на полноцветную (RGB) светодиодную матрицу, который продаётся в Интернет-магазине GearBest.com. Исследование образца проводилось по просьбе магазина.
В пути матрица была около двух недель и несколько пострадала от неаккуратного обращения со стороны доставщиков (см. отдельный отчёт о доставке и упаковке). После несложных восстановительных работ (пришлось вооружиться пинцетом и выравнивать контакты один за другим), всё пришло в работсопсобное состояние и о том как именно оно работает мы сегодня и поговорим.
1. Внешний вид
Выглядит матрица собственно как и должна выглядеть - никаких претензий. всё аккуратно и солидно.
2. Подключение
Матрица подключается через 32 пина, расположенные по 16 в ряд. Восемь пинов отвечают за строки матрицы, а остальные 24 - за столбцы. Столбцов-то вообще-то восемь, но поскольку это RGB светодиоды, каждый из них имеет три пина, отвечающие за красный, голубой и зелёный цвета соответсвенно. Таким образом можно сказать, что каждая строка состоит из 24 светодиодов.
Как же её подключать? Напрямую к ардуино-UNO (или Nano) она не подключится по банальной причине - у них просто нет столько ножек. Можно, конечно, взять Arduino-Mega, но это плохая идея. Одиночная такая матрица всё равно используется крайне редко, а если потребуется подключить две, то уже никакой Меги не хватит. Надо искать более систематический способ. С монохромными матрицами нас всегда выручала микросхема MAX7219, но здесь она нам не помошник. Во-первых, она не поддерживает индивидуальное управление яркостью каждого светодиода, что нам необходимо для смешивания цветов, а, во-вторых, она отлично работает с матрицами 8х8, но не с 8х24 как у нас. Городить три штуки? Больно дорого и громоздко (хотя и можно, конечно), да и управление яркостью всё равно ниоткуда не возьмётся. В принципе, есть много способов подключить эту матрицу. Я остановился на использовании двух микросхем TLC5940. Не то, чтобы это обусловлено какими-то высокими соображениями, просто они у меня были под рукой.
Микросхема TLC5940 - это 16-канальный драйвер светодиодов и, по совместительтву, ШИМ-контроллер. Две штуки дают нам 32 канала, на которых поддерживается постоянным ток и на которых можно организовать 12-разрядный ШИМ. Последнее явно избыточно, мы ограничимся 8-ю (что тоже избыточно, кстати).
Схема подключения проста и незамысловата:
Все пронумерованный цифрами термииналы должны быть соединены (по цифрам). Эти соединения не показаны, чтобы схема была хоть немного читабельной.
Синий разъём S1 справа - это разъём S1 следущей такой же платы, если их у Вас несколько.
Транзисторы подойдут любые PNP с током коллектора от 500 мА и коэффициентом усиления по току не менее 24. Я использовал 2N2907A просто потому, что они у меня были в нужном количестве.
На схеме отсутствует резистор 10к от пина Blank к питанию, который нужен, чтобы держать все выходы выключенными в момент инициализации устройства, чтобы избежать беспорядочного мигания при включении. Дело в том, что при каскадировании TLC5940, все пины Blank соединяются, а резистор нужен только один на всех. Поэтому он располагается не на этой плате (чтобы все платы были одинаковыми), а возле контроллера.
Именно эти пины были выбраны ислючительно из соображений удобства разводки печатной платы, чтобы поменьше ставить перемычек и вообще, чтобы она попроще была. А вот, кстати и печатная плата:
В результате получилась плата размером точно с матрицу. Матрица вставляется в неёё на два разъёма по 16 пин. Можно ставить радом несколько матриц, соединять их проводами с помощью разъемов, которые предусмотрены и получится единый (без щелей) экран из несколькх матриц. Вот как выглядит готовая плата.
|
3. Базовая библиотека
Основу нашей конструкции составляют две микросхемы TLC5940, поэтому, разумно было бы воспользоваться распространённой библиотекой для этой микросхемы. Но мы не будем этого делать. Дело в том, что эта библиотека заннимает два таймера, а это значит, что в нашем проекте с Ардуино на базе микроконтроллера ATMega328P нам пришлось бы остаться без таймеров вовсе, что неприятно. Поэтому, специально для данного исследования была написана мини-библиотека, которая использует только 8 бит управления яркостью и, за счёт этого, занимает только один таймер. Бибилотека написана именно для этого исследования и потому работает только с ATMega328P (Ардуино UNO, Nano и им подобные). С другими платами (Ардуино Мега, например), данная библиотека работать не будет.
На задней стенке матрицы нанесена маркировка «Hew2338RGB5» - это и будет названем библиотеки. Состоит она из двух файлов Hew2338RGB5.cpp и Hew2338RGB5.h.
Hew2338RGB5.h
#ifndef HEW2338RGB5_H #define HEW2338RGB5_H #include <arduino.h> #define TOTAL_LINES 8 #define TOTAL_COLUMNS 8 #define MAX_VALUE 255 // мы используем только 256 градация яркости цвета #define DATA_AMOUNT 48 // TLC5940 требует 24 байта. Мы используем 2 микросхемы, отсюда 48 class RGBColor { public: RGBColor(const byte red = 0, const byte green = 0, const byte blue = 0) { m_red = red; m_green = green; m_blue = blue; } byte m_red; byte m_green; byte m_blue; }; class RGBDiode : public RGBColor { public: static byte gsData[DATA_AMOUNT * TOTAL_LINES]; RGBDiode(const byte row, const byte column, const byte red = 0, const byte green = 0, const byte blue = 0) : RGBColor (red, green, blue) { m_dataBase = gsData + ((int)row) * DATA_AMOUNT; // // КОНФИГУРАЦИЯ // bluePin - номер пина TLC5940 для голубого светодиода в колонке column // redPin - номер пина TLC5940 для красного светодиода в колонке column // greenPin - номер пина TLC5940 для зелёного светодиода в колонке column // при этом пины первой (от Ардуино) TLC5940 - 0-15, а пины второй - 16-31 // const byte bluePin = column; const byte redPin = column + 8; const byte greenPin = 27 - column; // calculateBaseHalf(bluePin, m_blueBase, m_blueHalf); m_even.blue = (!(bluePin & 1)); calculateBaseHalf(redPin, m_redBase, m_redHalf); m_even.red = (!(redPin & 1)); calculateBaseHalf(greenPin, m_greenBase, m_greenHalf); m_even.green = (!(greenPin & 1)); setRed(m_red); setGreen(m_green); setBlue(m_blue); } void setRed(const byte val) { setColor(val, m_red, m_even.red, m_redBase, m_redHalf); } void setGreen(const byte val) { setColor(val, m_green, m_even.green, m_greenBase, m_greenHalf); } void setBlue(const byte val) { setColor(val, m_blue, m_even.blue, m_blueBase, m_blueHalf); } void setRGB(const byte r, const byte g, const byte b) { setRed(r); setGreen(g); setBlue(b); } RGBDiode & operator = (const RGBColor & orig) { setRed(orig.m_red); setGreen(orig.m_green); setBlue(orig.m_blue); return *this; } void incRed(int d) { incColor(d, m_red, m_even.red, m_redBase, m_redHalf); } void incGreen(int d = 1) { incColor(d, m_green, m_even.green, m_greenBase, m_greenHalf); } void incBlue(int d = 1) { incColor(d, m_blue, m_even.blue, m_blueBase, m_blueHalf); } RGBDiode & Add(const RGBColor & colorToAdd, byte transparency = 127) { const unsigned antiTr = 256 - transparency; setRed(addColors(m_red, colorToAdd.m_red, transparency, antiTr)); setGreen(addColors(m_green, colorToAdd.m_green, transparency, antiTr)); setBlue(addColors(m_blue, colorToAdd.m_blue, transparency, antiTr)); return *this; } private: inline byte addColors(const unsigned first, const unsigned second, const unsigned tr, const unsigned antitr) const { const unsigned newCol = first * antitr + second * tr; return newCol >> 8; //div_t dt = div(newCol, 255); //return (dt.rem > 127) ? dt.quot + 1 : dt.quot; } void incColor(int d, byte & col, const bool even, const byte base, const byte half) { d += col; if (d > 255) d = 255; if (d < 0) d = 0; setColor(d, col, even, base, half); } void setColor(const byte val, byte & col, const bool even, const byte base, const byte half) { if (col == val) return; col = val; if (even) writeEven(val, base, half); else writeOdd(val, base, half); } void calculateBaseHalf(const byte pin, byte & base, byte & half) { if (!(pin & 1)) { // чётный base = DATA_AMOUNT - 1 - (pin >> 1) * 3; half = base - 1; } else { // нечётный base = DATA_AMOUNT - 3 - ((pin - 1) >> 1) * 3; half = base + 1; } } void writeOdd(const unsigned val, const byte base, const byte half) { const uint8_t mask = ((val & 0x000F) << 4); byte * pb = (byte *)m_dataBase + half; *pb = (*pb & 0x0F) | mask; m_dataBase[base] = ((val & 0x0FF0) >> 4); } void writeEven(const unsigned val, const byte base, const byte half) { const byte mask = ((val & 0x0F00) >> 8); byte * pb = (byte *)m_dataBase + half; *pb = (*pb & 0xF0) | mask; m_dataBase[base] = (val & 0x00FF); } byte m_redBase, m_redHalf, m_greenBase, m_greenHalf, m_blueBase, m_blueHalf; struct { unsigned red : 1; unsigned green : 1; unsigned blue : 1; } m_even; byte *m_dataBase; }; extern void activateMatrix(void); extern void clearMatrix(const byte = 0); extern RGBDiode screen[TOTAL_LINES][TOTAL_COLUMNS]; #endif // HEW2338RGB5_H
Hew2338RGB5.cpp
#include "Hew2338RGB5.h" // // КОНФИГУРАЦИЯ (т.ж. см. слово "КОНФИГУРАЦИЯ" в конструкторе RGBDiode // // Строки сверху вниз от 0 до 7 - соотыетстыме пинам // #define LINE_0 2 #define LINE_1 4 #define LINE_2 5 #define LINE_3 6 #define LINE_4 7 #define LINE_5 8 #define LINE_6 A0 #define LINE_7 A1 // пин 12 (MISO) лучше не трогать от греха. В принципе его можно использовать // как INPUT пин, но см. описание работы SPI в master mode в даташите #define _SIN_PIN 11 // MOSI pin Arduino - не менять, зарезервирован SPI #define _SCLK_PIN 13 // SCLK pin Arduino - не менять, зарезервирован SPI #define _BLANK_PIN 10 // SS pin Arduino - можно поменять, хотя это стандарт SPI #define _XLAT_PIN 9 // можно поменять #define _GSCLK_PIN 3 // не менять, если не хотите переписывать инициализацию таймера ///////////////////////////////////////////////////////////////////// // // Минимальная реализация быстрых пиновых операций для ATmega328P // #if ! defined(__AVR_ATmega328P__) #ifndef IGNORE_CPU_CHECK #error This code is designed for ATmega328P MCU only. Define IGNORE_CPU_CHECK option to ignore this check. #endif // !IGNORE_CPU_CHECK #endif // ! defined(__AVR_ATmega328P__) #define ___pin2Port(pin, portD, portB, portC) (((pin) < 8) ? (portD) : (((pin) >= 8 && (pin) < 14) ? (portB) : (((pin) >= A0 && (pin) <= A7) ? (portC) : _SFR_IO8(255)))) #define __pin2Port(pin) ___pin2Port(pin, PORTD, PORTB, PORTC) #define __pin2DirectionPort(pin) ___pin2Port(pin, DDRD, DDRB, DDRC) #define __pin2InputPort(pin) ___pin2Port(pin,PIND,PINB,PINC) #define __pin2PortBit(pin) (((pin) < 8) ? (pin) : (((pin) >= 8 && (pin) < 14) ? ((pin)-8) : (((pin) >= A0 && (pin) <= A5) ? ((pin)-A0) : 255))) #define __pin2Mask(pin) (1 << __pin2PortBit(pin)) #define __pinHigh(port,mask) ((port) |= (mask)) #define __pinLow(port,mask) ((port) &= ~(mask)) #define __digitalWrite(port,mask,val) (((val)!=LOW) ? (__pinHigh(port,mask)) : (__pinLow(port,mask))) #define __pinModeOutput(dirport,mask) ((dirport) |= (mask)) #define __pinModeInput(dirport, mask) ((dirport) &= ~(mask)) #define __pinMode(pin,state,mask) ((state) == INPUT) ? (__pinModeInput(__pin2DirectionPort(pin), mask)) : ((state) == OUTPUT) ? (__pinModeOutput(__pin2DirectionPort(pin), mask)) : (__pinModeOutput(__pin2DirectionPort(pin),0)) #define _pinMode(pin,state) __pinMode(pin,state,__pin2Mask(pin)) #define _digitalWrite(pin,val) __digitalWrite(__pin2Port(pin),__pin2Mask(pin),val) // // Таймер 2 устанавливаем CTC режим на пин 3 // static inline void setupTimer(void) { _pinMode(_GSCLK_PIN, OUTPUT); TCCR2A = bit(COM2B0) | bit(WGM21); // инвертировать пин 3 по сравнению TCCR2B = bit(CS21); // делитель частоты = 8 OCR2A = 9; // для нормальной частоты обновления экрана TIMSK2 = bit(OCIE2B); // установить перывание по сравнению } static inline void initSPI(void) { _pinMode(_SIN_PIN, OUTPUT); _pinMode(_SCLK_PIN, OUTPUT); _digitalWrite(_SCLK_PIN, LOW); SPCR = bit(SPE) | bit(MSTR); // SPI master mode SPSR = bit(SPI2X); // Скорость SPI F_CPU/2 _pinMode(_BLANK_PIN, OUTPUT); // С точки зрения SPI это пин SS _digitalWrite(_BLANK_PIN, HIGH); } static inline void writeSPI(const byte b) { SPDR = b; asm ("nop"); while (!(SPSR & bit(SPIF))); } byte RGBDiode::gsData[DATA_AMOUNT * TOTAL_LINES]; RGBDiode screen[TOTAL_LINES][TOTAL_COLUMNS] = { { RGBDiode(0,0), RGBDiode(0,1), RGBDiode(0,2), RGBDiode(0,3), RGBDiode(0,4), RGBDiode(0,5), RGBDiode(0,6), RGBDiode(0,7) }, { RGBDiode(1,0), RGBDiode(1,1), RGBDiode(1,2), RGBDiode(1,3), RGBDiode(1,4), RGBDiode(1,5), RGBDiode(1,6), RGBDiode(1,7) }, { RGBDiode(2,0), RGBDiode(2,1), RGBDiode(2,2), RGBDiode(2,3), RGBDiode(2,4), RGBDiode(2,5), RGBDiode(2,6), RGBDiode(2,7) }, { RGBDiode(3,0), RGBDiode(3,1), RGBDiode(3,2), RGBDiode(3,3), RGBDiode(3,4), RGBDiode(3,5), RGBDiode(3,6), RGBDiode(3,7) }, { RGBDiode(4,0), RGBDiode(4,1), RGBDiode(4,2), RGBDiode(4,3), RGBDiode(4,4), RGBDiode(4,5), RGBDiode(4,6), RGBDiode(4,7) }, { RGBDiode(5,0), RGBDiode(5,1), RGBDiode(5,2), RGBDiode(5,3), RGBDiode(5,4), RGBDiode(5,5), RGBDiode(5,6), RGBDiode(5,7) }, { RGBDiode(6,0), RGBDiode(6,1), RGBDiode(6,2), RGBDiode(6,3), RGBDiode(6,4), RGBDiode(6,5), RGBDiode(6,6), RGBDiode(6,7) }, { RGBDiode(7,0), RGBDiode(7,1), RGBDiode(7,2), RGBDiode(7,3), RGBDiode(7,4), RGBDiode(7,5), RGBDiode(7,6), RGBDiode(7,7) } }; static int8_t currentActiveLine = 0; static inline void updateTLC5940(void) { //sei(); const byte * data = RGBDiode::gsData + ((int)currentActiveLine) * DATA_AMOUNT; for (register int8_t i = 0; i < DATA_AMOUNT; writeSPI(data[i++])); _digitalWrite(_BLANK_PIN, HIGH); _digitalWrite(_XLAT_PIN, HIGH); _digitalWrite(_BLANK_PIN, LOW); _digitalWrite(_XLAT_PIN, LOW); } static const int8_t lines[TOTAL_LINES] = {LINE_0, LINE_1, LINE_2, LINE_3, LINE_4, LINE_5, LINE_6, LINE_7 }; // // Задача этой функции, вызывать функцию reloadTLC // каждое 256-ое прерывание. // ISR(TIMER2_COMPB_vect) { static byte counter = 0; if (! (++counter)) { currentActiveLine = (currentActiveLine + 1) % TOTAL_LINES; updateTLC5940(); } } void clearMatrix(const byte val) { memset((void *)RGBDiode::gsData, val, sizeof(RGBDiode::gsData)); RGBDiode::gsData[23] = 0xFF; RGBDiode::gsData[69] = 0x0F; RGBDiode::gsData[70] = 0xF0; RGBDiode::gsData[116] = 0xFF; RGBDiode::gsData[162] = 0x0F; RGBDiode::gsData[163] = 0xF0; RGBDiode::gsData[197] = 0xFF; RGBDiode::gsData[243] = 0x0F; RGBDiode::gsData[244] = 0xF0; RGBDiode::gsData[290] = 0xFF; RGBDiode::gsData[336] = 0x0F; RGBDiode::gsData[337] = 0xF0; } void activateMatrix(void) { clearMatrix(); initSPI(); _pinMode(_XLAT_PIN, OUTPUT); _digitalWrite(_XLAT_PIN, LOW); setupTimer(); }
В результате в нашем распоряжении оказался двумерный массив screen размерами 8х8, каждый элмент которого представляет собой экземпляр класса RGBDiode. В классе определены операции установки цвета и классическое аддитивное сложение цветов. Перед началом работы необходимы вызвать функцию activateMatrix(), которая выполнит необходимую инициализацию. Подробнее методы и типы параметров можно посмотреть в тексте.
Первым делом хотелось посмотреть на насыщенность цветов и вообще работоспособность матрицы. Для этого был написан простой скетч,
///////////////////////////////////////////////////////////////////////// // // Базовый тест для проверки работспособности матрицы и правильности // соединения. Если всё нормально, то Вы должны наблюдать как экран сначала // закрашивается красным - диод за диодом, строка за строкой, затем также // перекрашивается в зелёный, а затем в голубой и, ..., наконец, в белый. // Все диоды должны светиться с одинаковой яркостьюю. // Если Вы видите именно это, поздравляю, всё у Вас работает отлично! // #include "Hew2338RGB5.h" void setup() { delay(1000); activateMatrix(); } static void FillOutScreen(const byte r, const byte g, const byte b) { for (register byte i=0; i < 8; i++) { for (register byte j = 0; j < 8; j++) { screen[i][j].setRGB(r, g, b); delay(200); } } } void loop() { FillOutScreen(MAX_VALUE, 0, 0); // Красный FillOutScreen(0, MAX_VALUE, 0); // Зелёный FillOutScreen(0, 0, MAX_VALUE); // Голубой FillOutScreen(MAX_VALUE, MAX_VALUE, 0); // Жёлтый FillOutScreen(MAX_VALUE, 0, MAX_VALUE); // Розовый FillOutScreen(0, MAX_VALUE, MAX_VALUE); // Синий FillOutScreen(MAX_VALUE, MAX_VALUE, MAX_VALUE); // Белый }
Скетч простой и в достаточной мере самодокументирован, поэтому, мы не будем останавливаться на его коде.
Заработало всё сразу, ниже представлены несколько фото.
Здесь я должен извиниться перед читателем. Толи потому, что я ни разу не фотограф, толи просто в силу особенностей имеющейся у меня камеры, но цвета сильно перевраны и вообще, вместо красного, например, Вы видите что-то бело-жёлтое с красной каёмкой. Я пытался как-то настроить фото-камеру (играл с балансом белого и т.п.), но не получилось. Поэтому, снимки столь ужасны. Прошу Вас просто поверить мне на слово - цвета реально красивые. сочные, полные. Работающая матрица и впрямь выглядит намного красивее, чем на моих убогих фото.
Итак, цвета оказались яркими и очень красивыми. Особенно приятно удивил чистый белый цвет и чистые цвета смешанные из двух. те, кто имел дело с цветными светодиодами, поймут о чём я. Добиться чистого белого или там чистого жёлтого обычно на них не так-то просто. Здесь всё отлично - цвета замечательные.
Втормым тестом было попробовать нарисовать окружность, углы которой сглажены за счёт слабо закрашенных соседних точек.
Результат показал некоторую нелинейность яркости свечения светодиодов. При уменьшении скважности яркость сначала падает медленно, а потом намного быстрее. Впрочем, это свойство я наблюдал у всех светодиодов, которые видел в жизни.
Вот скетч для окружности:
///////////////////////////////////////////////////////////////////////// // // Программа рисвования окружности. За счёт того, что некоторые // светодиоды подсвечиваются неполность, а "чем дальше от точного попадания // на окружность, тем тусклее, изображение действительно больше похоже на // оружность, чем если рисовать только на полной яркости. // #include <Hew2338RGB5.h> static void drawCircle(const byte xc, const byte yc, RGBColor & color) { const byte r = 3; // Ниже приведено 4 варианта массива яркостей. чем ниже, тем резче // падает яркость при отдалении от точного попадания static const unsigned transparensies[] = { // /*4*/ 336, 303, 286, 255, 238, 164, 0, 162, 225, 269, 255, 263, 281, 303, 326, 303, 307, 317, 331, 346, 362, 336, 338, 344, 354, 365, 378, 390, 361, 362, 367, 374, 382, 392, 403, 413 /*5*/ 318, 293, 280, 255, 242, 179, 0, 177, 231, 266, 255, 261, 276, 293, 310, 293, 296, 303, 314, 326, 338, 318, 319, 324, 331, 340, 349, 358, 336, 338, 341, 346, 353, 360, 368, 375 // /*6*/ 306, 286, 275, 255, 244, 190, 0, 188, 235, 264, 255, 260, 272, 286, 300, 286, 289, 295, 303, 313, 322, 306, 308, 312, 317, 324, 331, 339, 321, 322, 325, 329, 334, 340, 346, 352 // /*7*/ 298, 282, 272, 255, 245, 198, 0, 197, 237, 263, 255, 259, 269, 282, 293, 282, 283, 289, 296, 304, 312, 298, 299, 303, 308, 313, 319, 325, 311, 312, 314, 317, 321, 326, 331, 336 }; for (byte k2 = 0; k2 <= r; k2 ++) { for (byte k1 = k2; k1 <= r; k1 ++) { const byte index = k2 + k1 * (k1 + 1) / 2; const unsigned transp = transparensies[index]; if (transp >= 255) continue; const byte trans = 255 - transp; screen[xc + k2][yc + k1].Add(color, trans); screen[xc + k1][yc + k2].Add(color, trans); screen[xc + k2][yc - k1].Add(color, trans); screen[xc + k1][yc - k2].Add(color, trans); screen[xc - k2][yc + k1].Add(color, trans); screen[xc - k1][yc + k2].Add(color, trans); screen[xc - k2][yc - k1].Add(color, trans); screen[xc - k1][yc - k2].Add(color, trans); } } } void setup() { activateMatrix(); RGBColor color(0, 0, MAX_VALUE); drawCircle(3, 3, color); } void loop() {}
А вот приблизительно, что получилось:
Опять фото ужасное, но в реальности я доволен результатом.
Ну и последний тест - небольшая цветомузыкальная программа. В аналоговому входу Ардуино A7 был поключён звуковой сигнал и написана небольшая программа визуализации звука (без деления на частоты, просто по амплитуде, для простоты). Вот что в итоге полуилось (изображение плывёт по тем же причинам почему в кино плывут экраны телевизиров - в реальности ничего не плывёт и выглядит вполне прилично) - https://www.youtube.com/watch?v=wXN9dGQElUM
А вот и текст программы:
///////////////////////////////////////////////////////////////////////// // // Простая цветомузыкальная программа для мтарицы. // звуковой вход подключается к аналоговому пину 7 // #include <Hew2338RGB5.h> #define TRANSPARENCY 1 #define NOSOUND_LEVEL 24 #define TWICE_LEVEL 200 #define THRICE_LEVEL 240 #define MUSIC_PIN 7 int signalLevel() { const int signal = analogRead(MUSIC_PIN); const int aSignal = abs(signal - 485) / 2; const int mappedSignal = map(aSignal, 0, 251, 0, 255); return constrain(mappedSignal, 0, 255); } void darkerAll(void) { static const RGBColor black; RGBDiode * cell = & (screen[0][0]); for (int8_t indx = 0; indx < TOTAL_LINES * TOTAL_COLUMNS; indx ++, cell ++ ) cell->Add(black, TRANSPARENCY); } void setupTimer1(void) { TCCR1A = bit(WGM11); TCCR1B = bit(WGM13) | bit(CS12); // СТС режим и делитель 256 TIMSK1 = bit(TOIE1); ICR1 = 625; TCNT1 = 0; } ISR(TIMER1_OVF_vect) { sei(); darkerAll(); } void setup() { randomSeed(analogRead(0)); activateMatrix(); setupTimer1(); } void setNeighbourColor(const int8_t x, const int8_t y, RGBColor & original) { if (x >= 0 && x < TOTAL_COLUMNS && y >= 0 && y < TOTAL_LINES) screen[x][y].Add(original, 200); } void loop() { const int upperBarrier = signalLevel(); if (upperBarrier < NOSOUND_LEVEL) return; const int8_t x = random(8); const int8_t y = random(8); const uint8_t red = random(upperBarrier); const uint8_t green = random(upperBarrier); const uint8_t blue = random(upperBarrier); const RGBColor col(red, green, blue); screen[x][y].Add(col); if (upperBarrier > TWICE_LEVEL) { setNeighbourColor(x-1, y-1, screen[x][y]); setNeighbourColor(x-1, y, screen[x][y]); setNeighbourColor(x-1, y+1, screen[x][y]); setNeighbourColor(x, y-1, screen[x][y]); setNeighbourColor(x, y+1, screen[x][y]); setNeighbourColor(x+1, y-1, screen[x][y]); setNeighbourColor(x+1, y, screen[x][y]); setNeighbourColor(x+1, y+1, screen[x][y]); } if (upperBarrier > THRICE_LEVEL) { setNeighbourColor(x-2, y-2, screen[x][y]); setNeighbourColor(x-2, y-1, screen[x][y]); setNeighbourColor(x-2, y, screen[x][y]); setNeighbourColor(x-2, y+1, screen[x][y]); setNeighbourColor(x-2, y+2, screen[x][y]); setNeighbourColor(x+2, y-2, screen[x][y]); setNeighbourColor(x+2, y-1, screen[x][y]); setNeighbourColor(x+2, y, screen[x][y]); setNeighbourColor(x+2, y+1, screen[x][y]); setNeighbourColor(x+2, y+2, screen[x][y]); setNeighbourColor(x-1, y-2, screen[x][y]); setNeighbourColor(x, y-2, screen[x][y]); setNeighbourColor(x+1, y-2, screen[x][y]); setNeighbourColor(x-1, y+2, screen[x][y]); setNeighbourColor(x, y+2, screen[x][y]); setNeighbourColor(x+1, y+2, screen[x][y]); } }
Вывод
Отличная вещь! Цвета красивые, насыщенные - очень хороший белый цвет - никаких смещений, действительно белый. Мне очень понравилось.
Рекомендация магазину
Подумать о размещении на странице товара инструкции по подключению. Не обязательно так, как здесь, но какая-нибудь инструкция точно нужна, т.к. подключение этой матрицы не самая простая операция, особенно для начинающего энтузиаста.
Круто!
Интересно, через какое время у китайцев появится шилд для подключения этой матрицы? Может им ссылку на эту тему кинуть? :)
Да, я думаю, что у них есть какой-нибудь шилд, просто я не видел. Я шилдов вообще не покупаю, потому не особо знаю что есть, а чего нет.
КРУТО!
Скорее появится такая-же матрица со встроенным контроллером.
Скорее появится такая-же матрица со встроенным контроллером.
Так я это и имел в виду.
Не оно? p10 ?????
http://ru.aliexpress.com/item/Popular-Outdoor-P10-SMD-Full-Color-LED-Dis...
Не оно? p10 ?????
http://ru.aliexpress.com/item/Popular-Outdoor-P10-SMD-Full-Color-LED-Dis...
Это похоже часть светодиодного экрана, из которых бегущие строки делают.
Это похоже часть светодиодного экрана, из которых бегущие строки делают.
Оно и есть.
Но к обсуждаемой матрице это не имеет отношения.
у меня была такая похожа. по размерам и тем что она многоцветная интереснее той что бывает в комплекте
https://www.youtube.com/watch?v=0ZkZ4uOY3xs&feature=em-upload_owner
http://vfl.ru/fotos/45e68de814152911.html
Вот у Вас тоже на видео вместо красного - белое с красной каёмкой, как и у меня. А в реалье - наверняка нормальные красные точки. Не знаете как правильно снимать?
наверно снимал в темноте поэтому и пиксели слишком яркие для камеры в темноте поэтому.
Вот у Вас тоже на видео вместо красного - белое с красной каёмкой, как и у меня. А в реалье - наверняка нормальные красные точки. Не знаете как правильно снимать?
под большим углом
Спасибо, попробую.
Хороший обзор. Мне, как программисту и ни разу не инженеру, очень помогло в понимании матчасти. Не только по дисплею.
И подход с массивом интересный.
Очищается матрица. В строке 2 весь массив цветов заполняется значением val, а в строка 3-14 элемента массива данных, соответствующие общим пинам матрицы, заполняются единицами.
В результате все светодиоды получат цвет (R=val, G=val, B=val). Т.е. если val равно 0, то матрица полностью погаснет, если val равно 255, то станет белой, а при промежуточных значениях val - серой, чем меньше val, тем темнее.