ESP32/FreeRTOS:触发新任务时终止旧任务避免重叠(门禁场景)
实现思路
1. 全局维护任务句柄
把TaskMen任务句柄定义为全局变量(初始化为NULL),确保每次触发开门操作时都能访问到它,用来跟踪当前是否有正在运行的开门任务。
2. 触发新任务前终止旧任务
每次需要触发开门时,统一通过一个函数处理,步骤如下:
- 检查旧任务状态:用
eTaskGetState(TaskMen)判断任务是否处于活跃状态(运行、就绪或阻塞态),如果是,说明旧任务还在执行。 - 终止旧任务:调用
vTaskDelete(TaskMen)终止正在运行的旧任务,同时将TaskMen置为NULL,避免后续误判。 - 创建新任务:调用
xTaskCreate创建新的开门任务,更新TaskMen为新任务的句柄。
3. 优化任务内部逻辑
任务结束后主动将TaskMen置为NULL,确保句柄不会指向已删除的任务;新任务启动时再次设置继电器为开门状态(LOW),即便旧任务被中途终止,也能保证门处于开启状态。
修改后的代码示例
// 全局任务句柄,初始化为NULL TaskHandle_t TaskMen = NULL; // 继电器引脚定义(根据实际硬件调整) const int manRelay = 2; void TaskOpenManRoom(void *parameter){ Serial.println("Opening men room"); digitalWrite(manRelay, LOW); // 触发开门 vTaskDelay(6000 / portTICK_PERIOD_MS); // 保持开启6秒 digitalWrite(manRelay, HIGH); // 关闭门 Serial.println("Closing men room"); TaskMen = NULL; // 任务结束后置空句柄 vTaskDelete(NULL); }; // 统一的开门触发函数 void triggerManRoomOpen(){ // 检查并终止旧任务 if(TaskMen != NULL && eTaskGetState(TaskMen) != eDeleted){ vTaskDelete(TaskMen); TaskMen = NULL; } // 创建新任务 xTaskCreate( TaskOpenManRoom, "TaskOpenManRoom", 1000, NULL, // 若原代码的&man参数有用可保留 1, &TaskMen ); } void setup(){ Serial.begin(115200); pinMode(manRelay, OUTPUT); digitalWrite(manRelay, HIGH); // 初始状态为关门 }
注意事项
- 如果在中断中触发开门,需要使用
xTaskCreateFromISR代替xTaskCreate,并遵循FreeRTOS中断安全规范。 - 确保继电器引脚初始化正确,初始状态设置为关门(
HIGH)。
内容的提问来源于stack exchange,提问作者luj12
相关产品推荐
相关产品推荐

