前言
很多工程师习惯了裸机开发,觉得裸机逻辑好理解:代码是结构化、序列化 的,每一行代码什么时候跑、谁先谁后,在 while(1) 里一目了然。
但启动 RTOS后,这个世界就变了。
RTOS 最大的特点是"不确定性"。你的一行指令跑了一半,可能随时被硬件掐断;你的全局变量刚改完,可能就被另一个任务改了。这种从"顺序执行"到"任务抢占"的转变,就是很多 Bug 之源。RTOS的这种不确定性,源于 CPU 的"分身之术"------上下文切换(Context Switch)。
1. CPU 的分身之术
在 STM32(Cortex-M)内核中,CPU 其实是极其单纯的,它只认两个关键指针:
-
PC (Program Counter): 决定下一行代码跑哪。
-
SP (Stack Pointer): 决定当前的局部变量和函数调用栈存在哪。
实操观察:寄存器的"瞬间变化"
我们在 STM32CubeIDE 中开启 CMSIS-V2,创建两个任务:Task_High 和 Task_Low。
cpp
/* 任务 A:优先级高 (osPriorityAboveNormal) */
void StartHighTask(void *argument) {
uint32_t count_a = 0;
for(;;) {
count_a++; // 在此行打断点 (Breakpoint 1)
osDelay(10); // 关键:调用此函数会触发调度
}
}
/* 任务 B:优先级低 (osPriorityNormal) */
void StartLowTask(void *argument) {
uint32_t count_b = 0;
for(;;) {
count_b++; // 在此行打断点 (Breakpoint 2)
}
}
实验步骤:
-
进入 Debug 模式,打开 Registers 窗口。
-
当停在
count_b++时,记录下 R13 (SP) 的值(假设是0x20000A00)。 -
点击 Resume,当停在
count_a++时,再次观察 SP。 -
你会发现 SP 瞬间变成了类似
0x20000C00的位置。
底层逻辑: RTOS 为每个任务分配了独立的堆栈空间。切换任务时,内核做了三件事:
-
把当前 CPU 所有的寄存器(R0-R15, xPSR)像压压缩包一样,全部压入
Task_Low的堆栈。 -
把 CPU 的 SP 指针强行指向
Task_High的堆栈顶部。 -
从
Task_High的堆栈里把上次保存的寄存器数值"弹"回 CPU 硬件。
这就是上下文(Context)。对于 CPU 来说,它只是在不同的内存块(堆栈)之间跳来跳去,而对你来说,任务就像是在同时运行。
2. 调度的本质:抢占式 vs 协作式
在 FreeRTOSConfig.h 中,有一个决定生死定义的宏:
#define configUSE_PREEMPTION 1 // 1 为抢占式
为什么说高优先级任务是很霸道的?
在抢占式调度下,只要 Task_High 从 osDelay 中醒来,内核会立即 暴力切断 Task_Low。
-
代价: 这种切换不是发生在代码的行与行之间,而是可能发生在汇编指令级之间。
-
风险: 如果你的
Task_Low正在写一个 64 位的数据(需要两步汇编操作),写了一半被抢占,Task_High读到的就是一个"脏数据"。
3. 可重入性(Reentrancy)
这是裸机开发者最容易掉进去的深渊。为什么在两个任务里同时用 printf 或 strtok,系统会偶尔 HardFault 或者打印乱码?
案例分析
cpp
// 这是一个不可重入函数(Non-reentrant)
char* GlobalBuffer;
void MyDataProcess(char* input) {
GlobalBuffer = input; // 第一步:修改全局指针
osDelay(1); // 假设这里发生抢占!
printf("%s", GlobalBuffer); // 第二步:打印内容
}
当两个任务同时调用 MyDataProcess 时,GlobalBuffer 这个全局变量就成了冲突点。进阶思想:
-
能用局部变量就不用全局变量。 局部变量在各自任务的 Stack 里,是天然隔离的。
-
必须共享时,请加锁(下面某个章节我们会讲到互斥锁)。
4. 本章总结
RTOS 的便利不是免费的午餐,他是有代价的。
-
上下文切换耗时: 在 STM32G0 (M0+) 上,一次切换大约消耗几百个时钟周期。
-
内存开销: 每个任务都要独立分配堆栈,RAM 消耗远超裸机。
老鸟建议: 如果你的逻辑极其简单,裸机 while(1) 就能搞定,不要为了显摆而上 RTOS。RTOS 是为了解决复杂逻辑耦合 和实时响应需求而生的。