FastLED矩阵LED开机初始动画实现问题:自动运行firstanimation
实现FastLED开机自动运行初始动画并支持按钮中断切换
问题背景
我正在使用FastLED库开发矩阵LED控制程序,设置有5个按钮,每个按钮可触发对应的动画。希望程序启动后,在任何按钮被按下前,自动运行firstanimation()动画函数。该动画单独运行正常,但将其放入setup()中仅能显示第一帧无法持续;放入while(1)循环中则无法被按钮触发中断切换至其他动画。需要实现开机自动运行初始动画且可被按钮中断切换。
解决方案
核心逻辑是利用现有状态标志的默认值,在无按钮触发时自动执行初始动画:
- 保留原有按钮检测逻辑,通过
is_fog、is_rain等标志控制对应动画的运行 - 在原有动画分支的末尾添加
else分支,当所有按钮标志均为0时,执行firstanimation() - 开机时所有标志默认初始化为0,因此会持续执行初始动画;当任意按钮按下,对应标志被置1,程序会切换到目标动画,且不会再自动回到初始动画
修改后的完整代码
首先确保全局变量中is_fog、is_rain、is_rlight、is_sun、is_wind初始化为0(如果未显式初始化),然后修改loop()函数如下:
// 全局变量初始化 int is_fog = 0; int is_rain = 0; int is_rlight = 0; int is_sun = 0; int is_wind = 0; int state = 0; CHSV chsv[256]; // 确保颜色数组全局定义 void setup() { pinMode(tx, INPUT); pinMode(rx, OUTPUT); delay(50); Serial.begin(9600); BT.begin(9600); pinMode(btn1, INPUT); pinMode(btn2, INPUT); pinMode(btn3, INPUT); pinMode(btn4, INPUT); pinMode(btn5, INPUT); FastLED.setDither(1); FastLED.addLeds<NEOPIXEL, DATAPIN>(leds, LEDNUM).setCorrection(TypicalPixelString); // 降低蓝色占比,色调更暖 FastLED.setBrightness(BRIGHTNESS); FastLED.setMaxPowerInVoltsAndMilliamps(5, 39500); // 电源管理(电压和电流) } void loop() { BT.listen(); int c = BT.read(); delay(30); // 按钮检测逻辑保持不变 if (digitalRead(btn1) == HIGH && is_fog != 1) { Serial.println("btn1 pressed"); is_fog = 1; is_rain = 0; is_rlight = 0; is_sun = 0; is_wind = 0; } else if (digitalRead(btn2) == HIGH && is_rain != 1) { Serial.println("btn2 pressed"); is_fog = 0; is_rain = 1; is_rlight = 0; is_sun = 0; is_wind = 0; } else if (digitalRead(btn3) == HIGH && is_rlight != 1) { Serial.println("btn3 pressed"); is_fog = 0; is_rain = 0; is_rlight = 1; is_sun = 0; is_wind = 0; } else if (digitalRead(btn4) == HIGH && is_sun != 1) { Serial.println("btn4 pressed"); is_fog = 0; is_rain = 0; is_rlight = 0; is_sun = 1; is_wind = 0; } else if (digitalRead(btn5) == HIGH && is_wind != 1) { Serial.println("btn5 pressed"); is_fog = 0; is_rain = 0; is_rlight = 0; is_sun = 0; is_wind = 1; } // 动画执行逻辑:添加else分支处理初始动画 if (is_fog == 1) { state = 0; animation1(); } else if (is_rain == 1) { state = 3; animation2(); } else if (is_rlight == 1) { state = 0; animation3(); } else if (is_sun == 1) { state = 0; animation4(); } else if (is_wind == 1) { state = 2; animation5(); } else { // 所有按钮未触发时,执行初始动画 firstanimation(); } } // 保留原有的firstanimation()及相关函数代码 #define FASTER 1 #define TIMING 1 byte bump[LEDNUM]; void generatebumpmap() { uint16_t t = millis() / 11; int index = 0; for (int j = 0; j < ROWS; j++) { for (int i = 0; i < COLS; i++) { byte col; uint16_t u, v; u = i * (36 + 4) + t / 5; v = j * (23 + 6) - t / 3; if (!FASTER) { col = inoise8(u, v, t); col = map(col, 0, 255, 0, 255); } else // FASTER==1 { col = 76 + inoise8_raw(u, v, t); } bump[index++] = col; } } } void Bumpmap(int8_t lightx, int8_t lighty) { int yindex = COLS; int8_t vly = lighty; for (int y = 1; y < ROWS - 1; y++) { ++vly; int8_t vlx = lightx; for (int x = 1; x < COLS - 1; x++) { ++vlx; int8_t nx = bump[x + 1 + yindex] - bump[x - 1 + yindex]; int8_t ny = bump[x + yindex + COLS] - bump[x + yindex - COLS]; if (!FASTER) { byte difx = abs8(vlx - nx); byte dify = abs8(vly - ny); int col = 255 - sqrt16(difx * difx + dify * dify) * 3; if (col < 0) col = 0; leds[XY(x, y)] = CHSV(250, 255, col); } else { uint16_t sumsquare = (vlx - nx) * (vlx - nx) + (vly - ny) * (vly - ny); byte col = 0; if (sumsquare < 7225) // 7225 == (255 / 3)² col = 255 - sqrt16(sumsquare) * 3; leds[XY(x, y)] = chsv[col]; } } yindex += COLS; } } void firstanimation() { // 生成颜色数组 for (int i = 0; i < 256; i++) { chsv[i] = CHSV((i / 1.5 ) + 16 , 255, i); } int time = millis() / 8; int8_t lightX = 1 - (sin8(time / 3) - 128) / 3.2; int8_t lightY = 1 - (sin8(time / 2) - 128) / 3.1; unsigned long t1 = micros(); generatebumpmap(); unsigned long t2 = micros(); Bumpmap(lightX, lightY); unsigned long t3 = micros(); FastLED.show(); if (TIMING) { static unsigned long t2_sum, t3_sum; t2_sum += t2 - t1; t3_sum += t3 - t2; static byte frame; if (!(++frame % 64)) { t2_sum = t3_sum = 0; } } }
说明
- 新增的
else分支会在所有按钮未被触发时持续调用firstanimation(),借助loop()的循环特性实现动画持续刷新,解决了放入setup()只显示一帧的问题 - 按钮检测逻辑在每次
loop()循环中都会执行,一旦按钮按下,对应标志被置1,程序就会切换到目标动画,不会陷入无法中断的死循环 - 注意确保
chsv数组已全局定义,避免编译错误
内容的提问来源于stack exchange,提问作者venusrainbow
相关产品推荐
相关产品推荐

