freeRTOS基础
1 任务状态
FreeRTOS任务状态及状态机跳转
FreeRTOS是一个流行的实时操作系统,其核心功能之一是任务管理。任务状态定义了任务在系统中的当前行为,状态机跳转描述了任务在不同状态间的转换规则。下面我将逐步介绍任务状态及其转换机制,确保内容清晰易懂。
1. FreeRTOS任务状态
在FreeRTOS中,任务有五种主要状态,每个状态表示任务的不同执行阶段:
- 就绪状态(Ready):任务已准备好运行,但尚未被调度器选中执行。任务处于就绪队列中等待CPU资源。
- 运行状态(Running):任务正在CPU上执行。同一时间,只有一个任务处于此状态(单核系统中)。
- 阻塞状态(Blocked):任务因等待外部事件(如信号量、队列消息或延时)而暂停执行。任务不会占用CPU资源。
- 挂起状态(Suspended):任务被显式挂起(例如通过API调用),无法运行,直到被恢复。任务不参与调度。
- 删除状态(Deleted):任务已被删除,资源被释放。任务不再存在。
这些状态共同构成任务的生命周期,确保系统高效管理资源。
状态跳转如图所示:

2. 状态机跳转
状态机跳转描述了任务状态间的转换逻辑,由事件或API调用触发。下面用文字描述主要转换路径(类似状态图),并解释转换条件:
- 从就绪到运行:当调度器选中任务时发生。例如,高优先级任务进入就绪状态后,如果CPU空闲,会立即跳转到运行状态。
- 从运行到就绪:任务被更高优先级任务抢占时发生。调度器强制当前任务退出运行状态,返回就绪队列。
- 从运行到阻塞:任务调用阻塞API(如
vTaskDelay()或xQueueReceive())时触发。任务等待事件完成,例如延时结束或队列数据到达。 - 从阻塞到就绪:当等待的事件发生时(如延时结束或信号量释放),任务自动退出阻塞状态,进入就绪队列。
- 从运行到挂起:任务调用挂起API(如
vTaskSuspend())时触发。任务被手动暂停,不再参与调度。 - 从挂起到就绪:任务调用恢复API(如
vTaskResume())时触发。任务重新加入就绪队列。 - 从运行或就绪到删除:任务调用删除API(如
vTaskDelete())时触发。任务资源被释放,状态变为删除。 - 其他转换:例如,从阻塞到挂起(通过API强制挂起阻塞任务),但较少见。
状态跳转示例流程:
- 任务启动时通常进入就绪状态。
- 调度器选中后跳转到运行状态。
- 如果任务需要延时,调用
vTaskDelay()进入阻塞状态。 - 延时结束后,自动返回就绪状态。
- 任务完成后,调用
vTaskDelete()进入删除状态。
3. 代码示例
以下C代码展示了FreeRTOS API如何触发状态跳转。代码中,任务从运行状态转换到阻塞状态(通过延时),然后恢复运行。
#include "FreeRTOS.h"
#include "task.h"
void vExampleTask(void *pvParameters) {
while (1) {
// 任务处于运行状态
// 执行一些操作...
// 触发运行到阻塞的跳转:调用vTaskDelay()等待1000个tick
vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时期间任务进入阻塞状态
// 事件(延时结束)后,任务自动从阻塞跳转到就绪,再被调度为运行状态
}
}
int main() {
// 创建任务,初始状态为就绪
xTaskCreate(vExampleTask, "ExampleTask", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
vTaskStartScheduler(); // 启动调度器
return 0;
}
- 关键API说明:
vTaskDelay():使任务阻塞指定时间。vTaskSuspend():手动挂起任务。vTaskResume():恢复挂起的任务。vTaskDelete():删除任务。
4. 空闲任务和钩子函数
4.1 介绍
空闲任务的作用之一:释放被删除的任务的内存。
为什么必须要有空闲任务?一个良好的程序,它的任务都是事件驱动的:大部分时间处于阻塞状态。可能我们自己创建的所有任务都无法执行,但是调度器必须找到一个可以运行的任务,所以,我们需要提供空闲任务。在使用vTaskStartScheduler()函数来创建,启动调度器时,这个函数内部会创建空闲任务:
-
空闲任务优先级为0:它不能阻碍用户任务运行
-
空闲任务要么处于就绪态,要么处于运行态,永远不会阻塞
空闲任务的优先级为0,这意味着一旦某个用户的任务变为就绪态,那么空闲任务马上被切换出去,让这个用户任务运行。在这种情况下,我们说用户任务"抢占"(pre-empt)了空闲任务,这是由调度器实现的。
要注意的是:如果使用vTaskDelete()来删除任务,那么你就要确保空闲任务有机会执行,否则就无法释放被删除任务的内存。
我们可以添加一个空闲任务的钩子函数(Idle Task Hook Functions),空闲任务的循环每执行一次,就会调用一次钩子函数。钩子函数的作用有这些:
- 执行一些低优先级的、后台的、需要连续执行的函数
- 测量系统的空闲时间:空闲任务能被执行就意味着所有的高优先级任务都停止了,所以测量空闲任务占据的时间,就可以算出处理器占用率。
- 让系统进入省电模式:空闲任务能被执行就意味着没有重要的事情要做,当然可以进入省电模式了。
- 空闲任务的钩子函数的限制:
- 不能导致空闲任务进入阻塞状态、暂停状态
- 如果你会使用vTaskDelete()来删除任务,那么钩子函数要非常高效地执行。如果空闲任务移植卡在钩子函数里的话,它就无法释放内存。
4.2 使用钩子函数前提
在FreeRTOS\Source\tasks.c中,可以看到如下代码,所以前提就是
- 把这个宏定义为1:configUSE_IDLE_HOOK
- 实现vApplicationIdleHook函数

4. 总结
FreeRTOS的任务状态机确保了实时性和资源高效利用。状态跳转基于事件驱动:
- 就绪、运行和阻塞状态是动态转换核心。
- 挂起和删除状态用于管理任务生命周期。
理解这些状态及其转换,有助于优化任务调度和系统性能。例如,避免任务长时间阻塞可提升响应速度。
参考链接
https://rtos.100ask.net/zh/FreeRTOS/DShanMCU-F103/chapter9.html#_9-7-1-%E4%BB%8B%E7%BB%8D




1539

被折叠的 条评论
为什么被折叠?



