4. RTOS基础概念:任务、调度器、临界区、上下文切换、实时性指标
好,咱们进入正题。这一章讲的是RTOS的五个核心概念。说实话,我刚入行时觉得这些概念很抽象,直到亲手在STM32上移植了一个FreeRTOS,才真正理解它们的分量。
你想想看,一个裸机程序,无非就是main函数里一个大循环。但RTOS不一样,它把整个系统拆成了多个独立的任务。每个任务各司其职,互不干扰。嗯,这里要注意,这种「互不干扰」是有前提的——你得理解下面这几个概念。
4.1 任务(Task)
任务,说白了就是一个无限循环的函数。每个任务都有自己的栈空间、优先级和状态。
我个人习惯把任务分成三类:
- 周期性任务:比如每10ms采集一次传感器数据
- 事件驱动型任务:比如按键按下才处理
- 后台任务:比如系统状态监控,优先级最低
任务的状态有四种:运行态、就绪态、阻塞态、挂起态。我在项目中遇到过一个问题:一个任务因为等待信号量超时,直接卡死了整个系统。后来才发现,是任务优先级设置不合理,高优先级任务一直占着CPU不放。
任务创建示例(FreeRTOS):
void vTaskLed(void *pvParameters) {
while(1) {
GPIO_ToggleBits(GPIOA, GPIO_Pin_5);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
xTaskCreate(vTaskLed, "LED", 128, NULL, 1, NULL);
4.2 调度器(Scheduler)
调度器是RTOS的大脑。它决定下一个该运行哪个任务。常见的调度策略有两种:
| 调度策略 | 特点 | 适用场景 |
|---|---|---|
| 抢占式调度 | 高优先级任务随时打断低优先级任务 | 实时性要求高的系统 |
| 时间片轮转 | 同优先级任务轮流执行固定时间 | 多个同等重要的任务 |
我建议新手先从抢占式调度入手。为什么?因为大部分智能照明项目,都需要保证响应速度。比如你按一下开关,灯必须立刻亮,不能等别的任务跑完。
调度器的工作原理其实很简单:每个系统时钟节拍(tick),调度器都会检查当前运行的任务是否应该被换掉。如果有一个更高优先级的任务就绪了,调度器就会触发上下文切换。
4.3 临界区(Critical Section)
临界区,说白了就是「不允许被打断的代码段」。比如你在更新一个全局变量,突然被高优先级任务打断,数据就乱了。
我曾经踩过一个坑:两个任务共享一个缓冲区,一个写一个读。没有加临界区保护,结果读到的数据一半是旧的,一半是新的。嗯,从那以后,我只要看到共享资源,第一反应就是加临界区。
避坑指南:临界区代码要尽量短。我曾经见过有人把整个任务都包在临界区里,结果系统响应慢得像蜗牛。记住,临界区只保护关键操作,比如读写一个变量、操作一个寄存器。
临界区的实现方式有两种:
- 关中断:最简单粗暴,但会影响系统实时性
- 使用互斥量:更灵活,但要注意优先级反转问题
小技巧:在FreeRTOS中,taskENTER_CRITICAL()和taskEXIT_CRITICAL()就是用来保护临界区的。我习惯在操作硬件寄存器时使用它们,比如配置定时器、更新PWM占空比。
4.4 上下文切换(Context Switch)
上下文切换,就是CPU从一个任务切换到另一个任务的过程。它保存当前任务的寄存器、栈指针等状态,然后恢复下一个任务的状态。
你想想看,这个过程有多快?在Cortex-M3上,一次上下文切换大约需要几十个时钟周期。我实测过,在72MHz的STM32上,一次切换大概1-2微秒。
上下文切换的触发条件:
- 当前任务主动让出CPU(比如调用vTaskDelay)
- 高优先级任务就绪(抢占式调度)
- 时间片用完(时间片轮转)
- 中断服务程序唤醒了更高优先级的任务
我记得有一次调试一个奇怪的问题:系统偶尔会卡顿一下。用逻辑分析仪抓了波形,发现是上下文切换太频繁了。后来把任务周期调整了一下,问题就解决了。
4.5 实时性指标
实时性,不是「快」,而是「可预测」。一个实时系统必须保证:在规定的截止时间之前,完成规定的任务。
三个关键指标:
| 指标 | 定义 | 典型要求 |
|---|---|---|
| 响应时间 | 从事件发生到任务开始处理的时间 | 智能照明:< 10ms |
| 截止时间 | 任务必须完成的最晚时间 | PWM更新:< 1ms |
| 抖动 | 任务完成时间的最大偏差 | 调光控制:< 100μs |
我建议你在做智能照明项目时,重点关注抖动这个指标。为什么?因为人眼对亮度变化非常敏感。如果PWM的更新抖动太大,灯光就会闪烁,用户体验极差。
实时性测试方法:
用GPIO翻转来测量任务执行时间。在任务开始和结束时各翻转一次GPIO,然后用示波器看脉冲宽度。我当年就是这么干的,简单有效。
最后说一句:RTOS不是万能的。如果你的系统只有两三个任务,裸机加状态机可能更简单。但一旦任务超过5个,或者有严格的实时性要求,RTOS就是你的最佳选择。
下一章,我会带你手把手移植一个RTOS到STM32上。到时候,这些概念都会变成实实在在的代码。