Arduino如何实现收到新蓝牙数据时切换正在执行的LED循环任务
问题根因
代码无法切换效果的核心原因有两点:
green、blue函数内置了固定1000次的for循环,调用后会一直卡在函数内部执行,无法回到主循环检测新指令- 亮灭控制用了阻塞式的
FastLED.delay(),延时过程中程序停止所有其他逻辑,完全收不到新的蓝牙串口数据
修复方案
采用状态机+非阻塞延时的逻辑重构代码,核心思路是:
- 新增全局变量存储当前需要运行的效果标识,收到新蓝牙指令时仅修改标识,不调用阻塞函数
- 去掉所有效果函数内的循环和阻塞延时,亮灭切换用
millis()计时实现非阻塞触发,主循环全程可以随时检测串口数据
修复后完整代码
#include "FastLED.h" // 固定配置 #define LED_DT 7 #define COLOR_ORDER GRB #define LED_TYPE WS2812B #define NUM_LEDS 23 // 效果标识定义 #define EFFECT_OFF 0 #define EFFECT_RED 1 #define EFFECT_GREEN 2 #define EFFECT_BLUE 3 struct CRGB leds[NUM_LEDS]; // 当前运行的效果标识 uint8_t current_effect = EFFECT_OFF; // 非阻塞计时用变量 unsigned long last_tick = 0; // LED当前亮灭状态 bool led_on = false; // 亮灭切换间隔1000ms const long interval = 1000; void setup() { Serial.begin(9600); delay(1000); LEDS.addLeds<LED_TYPE, LED_DT, COLOR_ORDER>(leds, NUM_LEDS); FastLED.clear(); FastLED.show(); } void loop () { // 第一步:检测蓝牙串口新指令 if (Serial.available()) { char val = Serial.read(); switch(val) { case 'r': current_effect = EFFECT_RED; break; case 'g': current_effect = EFFECT_GREEN; break; case 'b': current_effect = EFFECT_BLUE; break; case 'o': current_effect = EFFECT_OFF; FastLED.clear(); FastLED.show(); break; } // 收到新指令后重置状态,下次立即切换效果 led_on = false; last_tick = millis(); } // 第二步:非阻塞执行当前效果 unsigned long now = millis(); if (current_effect != EFFECT_OFF && now - last_tick >= interval) { last_tick = now; led_on = !led_on; if (led_on) { // 亮灯:根据当前效果选颜色 switch(current_effect) { case EFFECT_RED: fill_solid(leds, NUM_LEDS, CRGB::Red); break; case EFFECT_GREEN: fill_solid(leds, NUM_LEDS, CRGB::Green); break; case EFFECT_BLUE: fill_solid(leds, NUM_LEDS, CRGB::Blue); break; } } else { // 灭灯 FastLED.clear(); } FastLED.show(); } }
内容的提问来源于stack exchange,提问作者Adlan N
相关产品推荐
相关产品推荐

