FreeRTOS核心1中FastLED.show()失效:任务删改后LED不更新
问题原因分析
- FreeRTOS任务删除的异步特性:调用
vTaskDelete(Task1)后,系统不会立刻销毁目标任务,旧任务可能还在执行FastLED.show()或者LED缓冲区(led数组)的写入操作。此时新任务启动后,两个任务会竞争LED硬件资源和缓冲区,导致新任务的show操作被旧任务覆盖,最终LED停留在旧图案状态。 - FastLED非线程安全:FastLED的底层硬件传输(如SPI)和缓冲区读写没有内置线程同步机制,多任务同时操作时会导致数据混乱,硬件输出异常。
- 任务句柄未同步:删除任务后未及时将
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
相关产品推荐
相关产品推荐

