Всем доброго времени суток. Появилось желание повторить проект с бесконечным кубом (пример выполнения:
Из железок используется: arduino uno, лента ws2812b, БП. Можно просто взять готовый код, банку клея (нужно ведь как-то это всё “клеить”? ) и повторить, однако было принято решение, что изменение режимов свечения по времени - не интересно, хочется управлять этим самостоятельно. Для этой цели определён инфракрасный модуль с пультом HX1838 (самый стандартный пульт для ардуинок). Вроде бы цели понятны, задачи определены и даже клей уже открыт, но руки упорно не хотят написать код, хоть немного похожий на правду. Вдохновение и немного букв программы черпал из кода от Gyver-а
Спойлер
#define EDGE_LEDS 11 // кол-во диодов на ребре куба
#define LED_DI 2 // пин подключения
#define BRIGHT 255 // яркость
#define CHANGE_PRD 10 // смена режима, секунд
#define CUR_LIMIT 2000 // лимит тока в мА (0 - выкл)
// ===== ДЛЯ РАЗРАБОВ =====
const int NUM_LEDS = (EDGE_LEDS * 24);
#define USE_MICROLED 0
#include <FastLED.h>
CRGBPalette16 currentPalette;
const int FACE_SIZE = EDGE_LEDS * 4;
const int LINE_SIZE = EDGE_LEDS;
#define PAL_STEP 30
CRGB leds[NUM_LEDS];
int perlinPoint;
int curBright = BRIGHT;
bool fadeFlag = false;
bool mode = true;
bool colorMode = true;
uint16_t counter = 0;
byte speed = 15;
uint32_t tmrDraw, tmrColor, tmrFade;
#define DEBUG(x) //Serial.println(x)
uint32_t getPixColor(CRGB color) {
return (((uint32_t)color.r << 16) | (color.g << 8) | color.b);
}
void setup() {
Serial.begin(9600);
FastLED.addLeds<WS2812, LED_DI, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
if (CUR_LIMIT > 0) FastLED.setMaxPowerInVoltsAndMilliamps(5, CUR_LIMIT);
FastLED.setBrightness(BRIGHT);
FastLED.clear();
randomSeed(getEntropy(A0)); // My system's in decline, EMBRACING ENTROPY!
perlinPoint = random(0, 32768);
fadeFlag = true; // сразу флаг на смену режима
}
void loop() {
// отрисовка
if (millis() - tmrDraw >= 40) {
tmrDraw = millis();
for (int i = 0; i < FACE_SIZE; i++) {
if (mode) fillSimple(i, ColorFromPalette(currentPalette, getMaxNoise(i * PAL_STEP + counter, counter), 255, LINEARBLEND));
else fillVertex(i, ColorFromPalette(currentPalette, getMaxNoise(i * PAL_STEP / 4 + counter, counter), 255, LINEARBLEND));
}
FastLED.show();
counter += speed;
}
// смена режима и цвета
if (millis() - tmrColor >= CHANGE_PRD * 1000L) {
tmrColor = millis();
fadeFlag = true;
}
// фейдер для смены через чёрный
if (fadeFlag && millis() - tmrFade >= 30) {
static int8_t fadeDir = -1;
tmrFade = millis();
if (fadeFlag) {
curBright += 5 * fadeDir;
if (curBright < 5) {
curBright = 5;
fadeDir = 1;
changeMode();
}
if (curBright > BRIGHT) {
curBright = BRIGHT;
fadeDir = -1;
fadeFlag = false;
}
FastLED.setBrightness(curBright);
}
}
} // луп
void changeMode() {
if (!random(3)) mode = !mode;
speed = random(4, 12);
colorMode = !colorMode;
int thisDebth = random(0, 32768);
byte thisStep = random(2, 7) * 5;
bool sparkles = !random(5);
if (colorMode) {
for (int i = 0; i < 16; i++) {
currentPalette[i] = CHSV(getMaxNoise(thisDebth + i * thisStep, thisDebth),
sparkles ? (!random(9) ? 30 : 255) : 255,
constrain((i + 7) * (i + 7), 0, 255));
}
} else {
for (int i = 0; i < 4; i++) {
CHSV color = CHSV(random(0, 256), random(0, 256), (uint8_t)(i + 1) * 64 - 1);
for (byte j = 0; j < 4; j++) {
currentPalette[i * 4 + j] = color;
}
}
}
}
// масштабируем шум
byte getMaxNoise(uint16_t x, uint16_t y) {
return constrain(map(inoise8(x, y), 50, 200, 0, 255), 0, 255);
}
// заливка всех 6 граней в одинаковом порядке
void fillSimple(int num, CRGB color) { // num 0-NUM_LEDS / 6
for (byte i = 0; i < 6; i++) {
leds[i * FACE_SIZE + num] = color;
}
}
// заливка из четырёх вершин
void fillVertex(int num, CRGB color) { // num 0-NUM_LEDS / 6
num /= 4;
byte thisRow = 0;
for (byte i = 0; i < 3; i++) {
leds[LINE_SIZE * thisRow + num] = color;
thisRow += 2;
leds[LINE_SIZE * thisRow - num - 1] = color;
leds[LINE_SIZE * thisRow + num] = color;
thisRow += 2;
leds[LINE_SIZE * thisRow - num - 1] = color;
}
thisRow = 13;
for (byte i = 0; i < 3; i++) {
leds[LINE_SIZE * thisRow - num - 1] = color;
leds[LINE_SIZE * thisRow + num] = color;
thisRow += 2;
leds[LINE_SIZE * thisRow - num - 1] = color;
leds[LINE_SIZE * thisRow + num] = color;
thisRow += 2;
}
}
// рандом сид из сырого аналога
uint32_t getEntropy(byte pin) {
unsigned long seed = 0;
for (int i = 0; i < 400; i++) {
seed = 1;
for (byte j = 0; j < 16; j++) {
seed *= 4;
seed += analogRead(pin) & 3;
}
}
return seed;
}
Здесь представлены 2 режима отрисовки: по граням и из вершин. Насколько я понимаю, это регулируется значением mode (true/false). По моей логике, если привязать функцию mode= !mode к кнопке, то я смогу менять эти 2 режима отрисовки. В розовых мечтах была ещё регулировка яркости и т.д., но хотел остановиться хотя бы на этом.
Мои потуги под спойлером:
Спойлер
#include <FastLED.h> // Для ленты
#include <IRremote.h> // Для пульта
#define EDGE_LEDS 11 // кол-во диодов на ребре куба
#define LED_PIN 2 // пин подключения ленты
#define IR_PIN 8 // пин подключения пульта
#define PAL_STEP 30 //шаг по палитре
#define USE_MICROLED 0
CRGBPalette16 currentPalette; //палитра
const int NUM_LEDS = (EDGE_LEDS * 24); //всего светодиодов
const int FACE_SIZE = EDGE_LEDS * 4; //светодиодов на грани
const int LINE_SIZE = EDGE_LEDS;//светодиодов на линии
CRGB leds[NUM_LEDS];
int perlinPoint; //точка шума Перлина
uint32_t getPixColor(CRGB color) {
return (((uint32_t)color.r << 16) | (color.g << 8) | color.b);
} //преобразует цвет из формата CRGB в 32-битное целое число для удобства работы с цветами
IRrecv irrecv(IR_PIN); //пульт
decode_results results;//пульт
// Коды кнопок ИК-пульта
#define BTN_0 0x97483BFB
#define BTN_LEFT 0x8C22657B
#define BTN_RIGHT 0x449E79F
int step = 25; // Шаг регулировки яркости
byte speed = 15;
uint16_t counter = 0;
uint32_t tmrColor, tmrFade; //Таймеры
bool mode = true; //переменная для режима отрисовки
void setup() {
Serial.begin(9600);
FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
//FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(255); // Изначально светим на всю
FastLED.clear(); // Очистим светодиоды от груза прошлого
perlinPoint = random(0, 32768); //Перлин
irrecv.enableIRIn();
}
void loop() {
//отрисовка
if (millis() - tmrDraw >= 40) {
tmrDraw = millis();
for (int i = 0; i < FACE_SIZE; i++) {
if (mode) fillSimple(i, ColorFromPalette(currentPalette, getMaxNoise(i * PAL_STEP + counter, counter), 255, LINEARBLEND));
else fillVertex(i, ColorFromPalette(currentPalette, getMaxNoise(i * PAL_STEP / 4 + counter, counter), 255, LINEARBLEND));
}
FastLED.show();
counter += speed;
}
if (irrecv.decode(&results)) {
unsigned long value = results.value;
Serial.print("Received IR code: 0x");
Serial.println(value, HEX);
switch (value) {
case BTN_0:
mode= !mode; //Меняем режим отрисовки
break;
default:
Serial.println("Unknown or unhandled button pressed");
break;
}
irrecv.resume();
}
}
// масштабируем шум
byte getMaxNoise(uint16_t x, uint16_t y) {
return constrain(map(inoise8(x, y), 50, 200, 0, 255), 0, 255);
}
// заливка всех 6 граней в одинаковом порядке
void fillSimple(int num, CRGB color) { // num 0-NUM_LEDS / 6
for (byte i = 0; i < 6; i++) {
leds[i * FACE_SIZE + num] = color;
}
}
// заливка из четырёх вершин
void fillVertex(int num, CRGB color) { // num 0-NUM_LEDS / 6
num /= 4;
byte thisRow = 0;
for (byte i = 0; i < 3; i++) {
leds[LINE_SIZE * thisRow + num] = color;
thisRow += 2;
leds[LINE_SIZE * thisRow - num - 1] = color;
leds[LINE_SIZE * thisRow + num] = color;
thisRow += 2;
leds[LINE_SIZE * thisRow - num - 1] = color;
}
thisRow = 13;
for (byte i = 0; i < 3; i++) {
leds[LINE_SIZE * thisRow - num - 1] = color;
leds[LINE_SIZE * thisRow + num] = color;
thisRow += 2;
leds[LINE_SIZE * thisRow - num - 1] = color;
leds[LINE_SIZE * thisRow + num] = color;
thisRow += 2;
}
}
void adjustBrightness(bool increase) { //Регулировка яркости
if (increase) {
FastLED.setBrightness(min(255, FastLED.getBrightness() + step));
} else {
FastLED.setBrightness(max(0, FastLED.getBrightness() - step));
}
FastLED.show();
}
При загрузке этого кода, лента не горит, нажатия пульта регистрируются, но в мониторе порта отображаются любые адреса, кроме правильных. Т.е. даже при нескольких нажатиях на одну и ту же кнопку, мне высветится несколько разных адресов. Если я вставлю кусочек кода из loop про отрисовку в if пульта (irrecv.decode(&results
), тогда регистрация нажатий кнопок корректна, однако лента всё равно не горит.
Стандартный набор косяков: неправильные адреса кнопок/подключил не в те пины/ брак модулей и проводов/разные версии библиотек - исправлены.
В других кодах у меня работает как лента, так и пульт (по раздельности), а вместе их подружить в этом коде не получается.
С лентой работаю первый день, пока добился того, что получается нажатием на кнопки пульта зажигать определённый светодиод или все сразу, а также поменять их цвет, отрегулировать яркость.
Но вот совместить пульт с кубом не выходит. Подскажите, где косяк в коде и как его поправить, чтобы я всё же мог управлять режимами с помощью пульта (в идеале, и яркостью)