2、RTOS基础概念:任务、调度器、内核、临界区、上下文切换
好,咱们正式开始聊RTOS的核心概念。说实话,很多初学者一上来就被这些术语吓住了——任务、调度器、内核、临界区、上下文切换……听着像一堆黑话。其实没那么玄乎,咱们一个一个拆开看。
2.1 任务(Task)—— 说白了就是“独立干活的小线程”
任务是什么?我习惯这么理解:任务就是一段独立的程序,有自己的栈、有自己的优先级,能独立地被调度器调度。在裸机编程里,你只有一个main函数,所有事情都得排队干。但在RTOS里,你可以把不同功能拆成多个任务,让它们“看起来”在同时运行。
举个例子,血氧仪里至少有三个任务:
- 采集任务:定时读取传感器数据
- 显示任务:刷新OLED屏幕
- 按键任务:检测用户操作
每个任务都有自己的优先级。采集任务最重要,优先级最高;显示任务次之;按键任务最低。这样设计的好处是——万一按键卡住了,不会影响血氧数据的采集。
任务的核心属性:
- 任务控制块(TCB)—— 内核用来管理任务的数据结构
- 任务栈 —— 每个任务独立的栈空间
- 优先级 —— 决定谁先跑
- 状态 —— 就绪、运行、阻塞、挂起
我在项目中遇到过一个问题:有个同事把任务栈开得太小,结果任务一跑复杂逻辑就栈溢出,系统随机死机。排查了两天才找到原因。嗯,这里要提醒你:任务栈大小一定要留余量,至少多给20%。
2.2 调度器(Scheduler)—— 系统的大脑
调度器是RTOS的核心组件。它的工作很简单:决定下一个该运行哪个任务。但实现起来,学问就大了。
常见的调度策略有两种:
| 调度策略 | 特点 | 适用场景 |
|---|---|---|
| 抢占式调度 | 高优先级任务可以打断低优先级任务 | 实时性要求高的系统(血氧仪就是典型) |
| 时间片轮转 | 同优先级任务轮流跑固定时间 | 多个同等重要的任务 |
血氧仪用的是抢占式调度。为什么?因为血氧数据采集必须准时,不能被显示任务拖累。你想想看,如果采集任务被显示任务堵住了,血氧波形就会断掉,那还怎么监测?
我个人习惯在项目初期就把所有任务的优先级列出来,画一张优先级表格。这样调度器怎么工作,心里就有数了。
2.3 内核(Kernel)—— 整个系统的管家
内核是RTOS最底层的部分。它负责:
- 任务管理(创建、删除、切换)
- 内存管理(分配、回收)
- 中断管理(响应、处理)
- 时钟管理(系统节拍、延时)
说白了,内核就是那个“啥都管”的角色。你写的每个任务、每个信号量、每个消息队列,最终都要通过内核来协调。
我记得刚接触FreeRTOS时,总觉得内核很神秘。后来自己动手移植了一遍,才发现内核其实就是一堆C函数加上汇编的上下文切换代码。嗯,没那么高不可攀。
小提示:选内核时别盲目追新。对于血氧仪这种资源受限的MCU,像FreeRTOS、uC/OS-II这种轻量级内核就够用了。别为了“高大上”去上Linux,那是给自己找麻烦。
2.4 临界区(Critical Section)—— 保护共享资源的“禁地”
临界区这个概念,说白了就是一段不允许被打断的代码。为什么需要它?因为多个任务可能会访问同一个全局变量或硬件寄存器。如果不加保护,就会出现“数据竞争”。
举个例子:血氧仪里有一个全局变量 spo2_value,采集任务往里面写数据,显示任务从里面读数据。如果采集任务写到一半被切换走了,显示任务读到的就是半成品数据——显示出来的血氧值就是错的。
解决办法就是加临界区保护:
// 进入临界区
taskENTER_CRITICAL();
// 操作共享资源
spo2_value = read_sensor();
// 退出临界区
taskEXIT_CRITICAL();
警告:临界区里的代码要尽量短!我曾经见过有人把整个显示刷新函数都包在临界区里,结果系统响应变得极慢。临界区只保护“读写共享资源”那几行代码就够了,别贪多。
2.5 上下文切换(Context Switch)—— 任务的“换岗”过程
上下文切换,就是暂停当前任务,保存它的现场,然后恢复另一个任务的现场,让它继续跑。这个过程由调度器触发,由内核完成。
切换时保存的内容包括:
- CPU寄存器(R0-R15、PC、LR、PSP等)
- 栈指针
- 浮点寄存器(如果有FPU)
这些信息都保存在任务的栈里。所以任务栈大小直接影响上下文切换的可靠性——栈太小,切换时数据存不下,系统就崩了。
我曾经调试过一个血氧仪原型,发现系统每隔几分钟就死一次。查了三天,最后用逻辑分析仪抓出上下文切换的时序,发现是任务栈溢出导致保存现场时写到了非法地址。把栈从128字节改成256字节,问题就解决了。
你看,有时候问题就这么简单——但排查过程是真折磨人。
2.6 这些概念怎么串起来?
咱们用血氧仪的场景串一遍:
- 系统上电,内核初始化,创建三个任务(采集、显示、按键)
- 调度器开始工作,根据优先级决定先跑采集任务
- 采集任务读取传感器,通过临界区保护写入共享变量
- 采集任务主动延时,调度器触发上下文切换,保存采集任务的现场
- 恢复显示任务的现场,显示任务开始刷新屏幕
- 如此循环往复,每个任务各司其职
整个过程,内核在幕后默默调度,临界区在关键时刻保护数据,上下文切换让任务无缝衔接。这就是RTOS的魅力——让复杂的系统变得井井有条。
一句话总结:任务是你写的功能代码,调度器决定谁先跑,内核负责底层管理,临界区保护共享数据,上下文切换让任务轮换。五个概念,一个系统。
下一章咱们聊任务状态和状态转换,这是理解RTOS任务生命周期的关键。到时候我会结合血氧仪的实际代码,让你看看任务是怎么“活”起来的。