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

FreeRTOS核心1中FastLED.show()失效:任务删改后LED不更新

问题原因分析
  1. FreeRTOS任务删除的异步特性:调用vTaskDelete(Task1)后,系统不会立刻销毁目标任务,旧任务可能还在执行FastLED.show()或者LED缓冲区(led数组)的写入操作。此时新任务启动后,两个任务会竞争LED硬件资源和缓冲区,导致新任务的show操作被旧任务覆盖,最终LED停留在旧图案状态。
  2. FastLED非线程安全:FastLED的底层硬件传输(如SPI)和缓冲区读写没有内置线程同步机制,多任务同时操作时会导致数据混乱,硬件输出异常。
  3. 任务句柄未同步:删除任务后未及时将Task1置为NULL,或新任务创建时旧任务仍在运行,可能导致任务状态管理混乱,出现任务句柄与实际任务状态不匹配的情况。
优化方案

方案一:单任务+任务通知切换图案(推荐)

放弃删除重建任务的方式,让Task1持续运行,通过任务通知+互斥锁控制图案切换,彻底避免任务销毁重建带来的异步问题。

实现代码示例

#include "FastLED.h"

TaskHandle_t Task1;
SemaphoreHandle_t xPatternMutex;
int currentPattern = 0; // 当前选中的图案编号

// 图案函数声明
void updateBPM();
void updateRainbow();

void Task1Code(void *parameter) {
  while(1) {
    // 安全读取当前图案编号
    int targetPattern = 0;
    if(xSemaphoreTake(xPatternMutex, portMAX_DELAY) == pdTRUE) {
      targetPattern = currentPattern;
      xSemaphoreGive(xPatternMutex);
    }

    // 根据图案编号执行对应更新逻辑
    switch(targetPattern) {
      case 1:
        updateBPM();
        break;
      case 2:
        updateRainbow();
        break;
      // 扩展其他图案...
    }
    // 短延时降低CPU占用,也可改用任务通知休眠等待切换指令
    vTaskDelay(10 / portTICK_PERIOD_MS);
  }
}

// BLE指令处理逻辑修改
if (command.startsWith("p")) {
  int newPattern = command.substring(1).toInt();
  // 安全更新图案编号
  if(xSemaphoreTake(xPatternMutex, portMAX_DELAY) == pdTRUE) {
    currentPattern = newPattern;
    xSemaphoreGive(xPatternMutex);
  }
  // 唤醒Task1(若任务处于休眠状态)
  if(Task1 != NULL) {
    xTaskNotifyGive(Task1);
  }
  
  mode = 1;
  preferences.putInt("mode", mode);
}

// 图案函数改为单次更新逻辑(不再死循环)
void updateBPM() {
  uint8_t BeatsPerMinute = 62;
  CRGBPalette16 palette = PartyColors_p;
  uint8_t beat = beatsin8(BeatsPerMinute, 64, 255);
  for (int i = 0; i < NUM_LEDS; i++) {
    led[i] = ColorFromPalette(palette, (i * 2), beat + (i * 10));
  }
  FastLED.show();
}

// 初始化时创建互斥锁
void setup() {
  xPatternMutex = xSemaphoreCreateMutex();
  // 创建Task1
  xTaskCreatePinnedToCore(Task1Code, "Task1", 20000, NULL, 1, &Task1, 1);
  // 其他初始化操作...
}

方案二:安全销毁旧任务后重建

若坚持使用删除重建任务的方式,需确保旧任务完全停止,并对LED资源加锁避免竞争。

实现代码示例

#include "FastLED.h"

SemaphoreHandle_t xLEDSemaphore;
bool taskShouldExit = false;
TaskHandle_t Task1;

// 修改图案函数,加入退出判断
void BPM(void *parameter) {
  while(!taskShouldExit) {
    // 获取LED资源锁,确保独占操作
    if(xSemaphoreTake(xLEDSemaphore, portMAX_DELAY) == pdTRUE) {
      uint8_t BeatsPerMinute = 62;
      CRGBPalette16 palette = PartyColors_p;
      uint8_t beat = beatsin8(BeatsPerMinute, 64, 255);
      for (int i = 0; i < NUM_LEDS; i++) {
        led[i] = ColorFromPalette(palette, (i * 2), beat + (i * 10));
      }
      FastLED.show();
      xSemaphoreGive(xLEDSemaphore);
    }
    vTaskDelay(10 / portTICK_PERIOD_MS);
  }
  // 任务自行退出并销毁
  vTaskDelete(NULL);
}

// BLE指令处理逻辑修改
if (command.startsWith("p")) {
  if (Task1 != NULL) {
    // 通知旧任务退出
    taskShouldExit = true;
    // 等待旧任务完全销毁(延时需根据任务循环周期调整)
    vTaskDelay(50 / portTICK_PERIOD_MS);
    // 重置退出信号
    taskShouldExit = false;
    // 置任务句柄为NULL
    Task1 = NULL;
  }

  // 创建新任务
  xTaskCreatePinnedToCore(
      switchPattern(command.substring(1).toInt()),
      "Task1",
      20000,
      NULL,
      1,
      &Task1,
      1);

  mode = 1;
  preferences.putInt("mode", mode);
}

// 初始化时创建互斥锁
void setup() {
  xLEDSemaphore = xSemaphoreCreateMutex();
  // 其他初始化操作...
}

内容的提问来源于stack exchange,提问作者Maker Mo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 15:45:43