You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 10:07:08