Светодиодная доска с адресными светодиодами
С помощью этой светодиодной доски можно создавать пиксельные рисунки. С помощью поворота двух энкодеров осуществляется управление горизонтальным и вертикальным положением курсор. Для изменения цвета энкодер необходимо нажать. Все это контролируется Arduino Nano.
Инструменты и материалы:
-Arduino Nanо;
-Два поворотных энкодера с нажимным переключателем;
-Две ручки для энкодеров;
-Светодиодная матрица WS2812b 16 x 1;
-Макетная плата;
-Перемычки -15 шт;
-Источник питания;
-МДФ;
-Клей ПВА;
-Красная краска;
-Клеевой пистолет;
Шаг первый: схема
Сначала мастер проверил схему, используя макетную плату. Для светодиодной матрицы нужно использовать дополнительный источник питания, хотя мастер запитал ее напрямую Arduino.
Шаг второй: код
Для работы матрицы потребуется установить библиотеки FastLED и LEDMatrix .
Не все светодиодные матричные панели имеют одинаковую конфигурацию. Библиотека LEDMatrix включает в себя различные конфигурации, нужно поэкспериментировать со строками 14, 15 и 16.
Код можно скачать ниже.
Показать / Скрыть текст// RGB LED Etch-A-Sketch // Author: John-Lee Langford // Website: www.mr.langford.co // Includes #include <FastLED.h> // https://github.com/FastLED/FastLED #include <LEDMatrix.h> // https://github.com/AaronLiddiment/LEDMatrix // Change the next 6 defines to match your matrix type and size #define LED_PIN 10 #define COLOR_ORDER GRB #define CHIPSET WS2812 #define MATRIX_WIDTH -16 // Set this negative if physical led 0 is opposite to where you want logical 0 #define MATRIX_HEIGHT -16 // Set this negative if physical led 0 is opposite to where you want logical 0 #define MATRIX_TYPE VERTICAL_ZIGZAG_MATRIX // See top of LEDMatrix.h for matrix wiring types cLEDMatrix<MATRIX_WIDTH, MATRIX_HEIGHT, MATRIX_TYPE> leds; // Rotary A — Horizontal movement int horizontalA = 9; // DT int horizontalB = 8; // CLK int buttonA = 7; // Button int btnA; // Button A value int horizontalALast; int horizontal, horizontalCursor = 0; unsigned char encoder_horizontalA; unsigned char encoder_horizontalB; unsigned char encoder_horizontalA_prev = 0; // Rotary B — Vertical movement int verticalA = 6; // DT int verticalB = 5; // CLK int buttonB = 4; // Button int btnB; // Button B value int verticalALast; int vertical, verticalCursor = 0; unsigned char encoder_verticalA; unsigned char encoder_verticalB; unsigned char encoder_verticalA_prev = 0; // Common unsigned long currentTime; unsigned long loopTime; bool moved = false; // Colours const int numberColours = 9; // Total number of colours available unsigned long colours[numberColours][2] = { {0xFF0000, 0x330000}, {0xFF6600, 0x331100}, {0xFFFF00, 0x333300}, {0x00FF00, 0x003300}, {0x00FFFF, 0x001111}, {0x0000FF, 0x000033}, {0xFF00FF, 0x330033}, {0xFFFFFF, 0x111111}, {0x111111, 0x000000} }; int currentColour = 0; // Set to first colour in array void setup() { FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds[0], leds.Size()); FastLED.setBrightness(255); // Clear the display in a pretty way int colourBounce = 1; for (int i = 0; i < 16; i++){ leds.DrawLine(0, i, 15, i, colours[currentColour][0]); leds.DrawLine(i, 0, i, 15, colours[currentColour][0]); FastLED.show(); delay(25); leds.DrawLine(0, i, 15, i, CRGB(0, 0, 0)); leds.DrawLine(i, 0, i, 15, CRGB(0, 0, 0)); currentColour = currentColour + colourBounce; if (i == 7) { colourBounce = -1; } } FastLED.clear(true); // Rotary A — Horizontal pinMode (horizontalA, INPUT); pinMode (horizontalB, INPUT); pinMode (buttonA, INPUT); horizontalALast = digitalRead(horizontalA); // Rotary B — Vertical pinMode (verticalA, INPUT); pinMode (verticalB, INPUT); pinMode (buttonB, INPUT); verticalALast = digitalRead(verticalA); // Common currentTime = millis(); loopTime = currentTime; } void loop() { // get the current elapsed time currentTime = millis(); if (currentTime >= (loopTime + 5)) { // Read encoder pins encoder_horizontalA = digitalRead(horizontalA); encoder_horizontalB = digitalRead(horizontalB); encoder_verticalA = digitalRead(verticalA); encoder_verticalB = digitalRead(verticalB); // Check for button presses btnA = digitalRead(buttonA); btnB = digitalRead(buttonB); if (btnA == 0) { currentColour++; if (currentColour > (numberColours — 1)) { currentColour = 0; } delay(500); } if (btnB == 0) { currentColour—; if (currentColour < 0) { currentColour = numberColours — 1; } delay(500); } // Encoder A if ((!encoder_horizontalA) && (encoder_horizontalA_prev)) { // A has gone from high to low if (encoder_horizontalB) { // B is high so counter-clockwise if (horizontalCursor > 0) { horizontalCursor —; moved = true; } } else { // B is low so clockwise if (horizontalCursor < 15) { horizontalCursor ++; moved = true; } } } encoder_horizontalA_prev = encoder_horizontalA; // Store value of A for next time // Encoder B if ((!encoder_verticalA) && (encoder_verticalA_prev)) { // C has gone from high to low if (encoder_verticalB) { // B is high so counter-clockwise if (verticalCursor < 15) { verticalCursor ++; moved = true; } } else { // D is low so clockwise if (verticalCursor > 0) { verticalCursor —; moved = true; } } } encoder_verticalA_prev = encoder_verticalA; // Store value of C for next time loopTime = currentTime; // Updates loopTime leds(horizontalCursor, verticalCursor) = colours[currentColour][0]; // Move the LED if (moved) { leds(horizontal, vertical) = colours[currentColour][1]; horizontal = horizontalCursor; vertical = verticalCursor; moved = false; } FastLED.show(); } }
Шаг третий: рамка
Для изготовления рамки мастер использовал 6-миллиметровые листы МДФ. Сначала он отрезал четыре листа размером А4. Затем, отступив от края 2,5см, вырезал у трех заготовок середину. Эти три листа, когда они склеены, должны обеспечивать достаточную глубину для размещения Arduino и других компонентов.
Дальше четыре листа МДФ были склеены с помощью клея ПВА. Когда ПВА полностью затвердел, отшлифовали края.
В передней части корпуса просверлил отверстия. Два, по краям, для энкодеров. Три центральных, для проводов.
Покрасил рамку в красный цвет.
Шаг четвертый: сборка
Чтобы устройство было как можно более тонким, мастер использовал тонкие полоски перфорированной платы (1 x 4) для питания.
Энкодеры прикручиваются с помощью гаек входящих в комплект, остальные детали крепятся с помощью термоклея.
Шаг пятый: управление
Управляется матрица следующим образом.
При повороте левого энкодера курсор перемещается влево и вправо. Нажатие на энкодер перемещает курсор вперед.
При повороте правого энкодера курсор перемещается вверх и вниз. Нажатие на энкодер перемещает курсор назад.
Когда курсор перемещается, выбранный цвет остается в предыдущем «пикселе».
Курсор отображается ярче, чем другие пиксели, поэтому пользователи могут видеть, где он находится.