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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 02:55:17