2. FreeRTOS内核基础:任务创建与删除、任务状态与优先级、任务调度机制
大家好,我是你们的老朋友。今天咱们来聊聊FreeRTOS最核心的东西——任务管理。说实话,我刚开始用RTOS那会儿,总觉得任务就是个“高级循环”。后来踩了不少坑才明白,任务管理才是整个系统的灵魂。
你想想看,一个实时系统里,可能有十几个甚至几十个任务在同时跑。谁先执行?谁后执行?谁被踢出去?这些都得靠内核来管。今天我就把这块掰开了揉碎了讲给你听。
核心要点:任务就是一段独立执行的代码,有自己的栈空间和优先级。FreeRTOS的任务调度器负责决定哪个任务该运行。
2.1 任务创建与删除
先说说任务创建。FreeRTOS里创建任务用的是 xTaskCreate() 这个API。原型长这样:
BaseType_t xTaskCreate(
TaskFunction_t pvTaskCode, // 任务函数指针
const char * const pcName, // 任务名称(调试用)
configSTACK_DEPTH_TYPE usStackDepth, // 栈深度(单位是字,不是字节)
void *pvParameters, // 传给任务的参数
UBaseType_t uxPriority, // 任务优先级
TaskHandle_t *pxCreatedTask // 返回的任务句柄
);
嗯,这里要注意几个坑。第一个就是栈深度。我见过太多新手把栈设得太小,结果任务跑着跑着就崩了。我个人习惯给每个任务至少128个字(512字节)的栈空间,如果任务里用了printf或者浮点运算,那得翻倍。
实战技巧:用 uxTaskGetStackHighWaterMark() 可以查看任务栈还剩多少空间。我每次调试新板子都会先跑这个函数,看看栈够不够用。
任务删除就更简单了,调用 vTaskDelete(NULL) 就能把自己干掉。不过要注意,删除任务后,它占用的栈空间和TCB(任务控制块)并不会立即释放——得等空闲任务来打扫战场。
我曾经踩过的坑:在中断服务函数里直接调用 vTaskDelete() 删除任务。结果系统直接死机了。后来才明白,vTaskDelete() 必须在任务上下文中调用,不能在中断里用。
2.2 任务状态与优先级
FreeRTOS的任务有四种状态:运行态、就绪态、阻塞态、挂起态。说白了就是:
- 运行态:正在占用CPU,一个核上只能有一个任务在跑
- 就绪态:啥都准备好了,就等调度器给CPU时间
- 阻塞态:在等某个事件(比如延时、信号量、队列)
- 挂起态:被 vTaskSuspend() 强制暂停了
优先级这块,数字越大优先级越高。0是最低优先级。我记得有个项目,客户要求系统响应特别快,我就把关键任务优先级设成了 configMAX_PRIORITIES-1。结果发现高优先级任务把低优先级任务饿死了——这就是所谓的“优先级反转”问题。
经验之谈:优先级不是越高越好。我一般把任务分成三类:实时任务(高优先级)、普通任务(中优先级)、后台任务(低优先级)。这样既保证了实时性,又不会饿死其他任务。
2.3 任务调度机制
FreeRTOS支持两种调度方式:抢占式调度和时间片轮转。默认是抢占式,这也是我推荐的方式。
抢占式调度是什么意思呢?就是高优先级任务一旦就绪,立马把当前正在运行的低优先级任务踢出去。你想想看,这就像公司里来了个大客户,老板马上让你放下手头的工作去接待——这就是抢占。
举个例子:
// 任务A:优先级2
void vTaskA(void *pvParameters) {
for(;;) {
// 做点重要的事
vTaskDelay(pdMS_TO_TICKS(100));
}
}
// 任务B:优先级1
void vTaskB(void *pvParameters) {
for(;;) {
// 做点次要的事
vTaskDelay(pdMS_TO_TICKS(200));
}
}
在这个例子里,任务A优先级更高。只要任务A就绪了,任务B就得乖乖让路。这就是抢占式调度的核心逻辑。
时间片轮转呢?它只对相同优先级的任务起作用。比如两个任务优先级都是1,那调度器就会轮流给它们分配时间片(默认一个tick,通常是1ms)。
我个人的建议:除非你有特殊需求,否则别轻易改时间片长度。默认的1ms在大多数场景下都够用。改短了会增加调度开销,改长了会影响响应速度。
最后说个关键点:FreeRTOS的调度器是可剥夺型的。这意味着任何时刻,只要有个更高优先级的任务就绪了,当前任务就会被挂起。这保证了系统的实时性,但也带来了同步问题——这就是为什么我们需要信号量和互斥锁。
注意:抢占式调度虽然好,但如果你在多个任务里操作同一个全局变量,一定要加保护。我曾经在一个项目里忘了加锁,结果两个任务同时修改一个数组,数据全乱了。排查了整整两天才找到问题。
好了,任务管理这块就聊到这儿。记住三个关键词:创建、状态、调度。把这三点吃透了,FreeRTOS就算入门了。