| 状态 | 核心含义 | 触发方式 | 恢复方式 | 是否参与调度 | 
|---|---|---|---|---|
| 运行态 | 正在占用 CPU 执行 | 调度器选择就绪任务 | 时间片到 / 被抢占 | 是(占用 CPU) | 
| 就绪态 | 等待 CPU 分配 | 任务创建 / 阻塞到期 / 被恢复 | 调度器选中 | 是(等待调度) | 
| 阻塞态 | 等待事件(主动放弃 CPU) | 调用 vTaskDelay / 等信号量 | 事件触发 / 延迟到期(自动) | 否 | 
| 挂起态 | 被强制暂停 | 调用 vTaskSuspend | 调用 vTaskResume(手动) | 否 | 
| 删除态 | 已删除,等待内存回收 | 调用 vTaskDelete | 空闲任务回收内存 | 否 | 
状态
1. 就绪态 ↔ 运行态
- 就绪态 → 运行态 :由调度器触发,选择 "就绪态中优先级最高" 的任务,将其切换为运行态(独占 CPU 执行)。
- 运行态 → 就绪态 :满足以下任一条件时触发:
- 时间片结束(同优先级任务轮转调度);
- 被更高优先级的就绪任务 "抢占";
- 任务主动放弃 CPU(如进入阻塞态、挂起态)。
2. 运行态 ↔ 阻塞态
- 运行态 → 阻塞态 :任务因 "等待事件" 主动放弃 CPU,触发条件包括:
- 调用
vTaskDelay()/vTaskDelayUntil()等待时间延迟;- 调用
xSemaphoreTake()/xQueueReceive()等待信号量、队列数据等同步 / 通信事件。- 阻塞态 → 就绪态 :当 "等待的事件满足" 时自动触发,如:
- 延迟时间到期;
- 信号量被释放、队列有新数据等事件到达。
3. 就绪态 / 运行态 / 阻塞态 ↔ 挂起态
- 就绪态 / 运行态 / 阻塞态 → 挂起态 :通过 API
vTaskSuspend()触发,无论任务当前处于就绪、运行还是阻塞态,均可被强制挂起(暂停执行,不参与调度)。- 挂起态 → 就绪态 :仅通过 API
vTaskResume()(任务上下文)或vTaskResumeFromISR()(中断上下文)手动唤醒,才能从挂起态回到就绪态,重新参与调度。4. 运行态 → 僵尸态(删除态)
- 运行态 → 僵尸态 :当任务 "正常结束" 或被
vTaskDelete()显式删除时,进入僵尸态(即 "删除态")。- 僵尸态 → 内存释放 :由 FreeRTOS 的空闲任务(Idle Task) 自动回收该任务的 TCB 和栈内存,完成最终清理。
核心区分总结
- 阻塞态 :因 "等事件" 被动阻塞,事件满足后自动恢复为就绪态;
- 挂起态 :因
vTaskSuspend()强制暂停,需手动调用vTaskResume()才能恢复;- 僵尸态:任务已逻辑删除,仅等待空闲任务回收物理内存。
延时
一、核心计时逻辑与起点
vTaskDelay(相对延时) :计时起点是 **"调用函数并进入阻塞态的瞬间"**(即任务加入等待队列的时刻),延时时长为相对当前时刻的xTicksToDelay个系统节拍(如 1000 节拍 = 1000ms)。例如:任务执行到vTaskDelay(1000)时,从 "此时" 开始等待 1000ms 后解除阻塞,与任务 "何时开始执行" 无关。
vTaskDelayUntil(绝对延时) :计时起点是 **"上次被唤醒的绝对时间点"**(通过xLastWakeTime记录),下次唤醒时间严格为xLastWakeTime + 固定周期(xPeriod)。例如:首次唤醒时间为t0,则下次唤醒时间必为t0 + 1000ms,无论任务执行耗时或中断占用多久,周期间隔始终固定。二、周期稳定性对比
vTaskDelay:周期不稳定。实际周期 = 任务执行时间 + 延时节拍时间 + 中断占用时间(若中断发生在任务执行阶段),会随执行耗时、中断等因素漂移。
vTaskDelayUntil:周期绝对稳定。两次唤醒的时间间隔严格等于xPeriod(如 1000ms),不受任务执行耗时、中断的影响(仅压缩任务可执行时间,不改变周期)。三、适用场景
vTaskDelay:适合非周期性任务(如单次延时后执行、对周期精度无要求的场景),例如初始化后延时启动传感器、临时等待某个条件。
vTaskDelayUntil:必须用于周期性任务(如定时采样、周期性控制指令),需严格保证固定频率,避免因执行耗时或中断导致的周期偏差。四、选择原则
- 若只需 "延时一段时间后执行一次",用
vTaskDelay(简单直观);- 若需 "按固定周期重复执行",必须用
vTaskDelayUntil(确保周期稳定,是高精度周期任务的唯一选择)。