tags: [source-summary] type: source source: "尚硅谷嵌入式技术之FreeRTOS实时操作系统 V1.0.3 — FreeRTOS基础知识" author: "尚硅谷研究院" date: 2026-07-17
用生活理解:CPU 像一个只能同时接待一位顾客的收银员。多任务系统让收银员在多个顾客之间快速切换,让每个顾客都觉得自己被"同时"服务着。调度器就是排号系统——谁优先级高谁先结账,同优先级按顺序来。
内核是操作系统的核心组件。多任务操作系统通过任务之间的快速切换,在单核处理器上制造出"并发执行"的假象。
实际上,单核 CPU 在同一时刻只能运行一个任务。任务切换的速度非常快(毫秒级),让人感觉多个任务在同时运行。
多任务系统的好处:
调度器是内核中负责决定"下一时刻运行哪个任务"的组件。调度策略是决定算法。
FreeRTOS 默认使用固定优先级的抢占式调度策略,对同等优先级任务执行时间片轮询。
| 模式 | 说明 | 适用场景 |
|---|---|---|
| 抢占式调度 | 高优先级任务随时可以抢占正在执行的低优先级任务 | 需要确保高优先级任务实时响应的场景 |
| 时间片轮询 | 同优先级任务轮流执行固定长度的时间片 | 多任务需要公平分配 CPU 的场景 |
高优先级任务在等待资源(延时、信号量等)时会主动让出 CPU,调度器选择其他就绪的高优先级任务执行,不会让低优先级任务"饿死"。
除了抢占式调度,FreeRTOS 也支持协程式调度(configUSE_PREEMPTION = 0 时启用)。在协程式调度下,任务不会被强制打断,只有当任务主动调用 taskYIELD() 或阻塞等待时,调度器才会切换任务。协程式调度实时性较弱,一般不推荐使用。
FreeRTOS 中任务共存在 4 种状态:
| 状态 | 含义 | 进入方式 | 退出方式 |
|---|---|---|---|
| 运行态(Running) | 任务正在执行 | 调度器选中 | 被抢占、阻塞、挂起 |
| 就绪态(Ready) | 任务可执行但未运行 | 创建、解除阻塞、解挂 | 被调度器选中 |
| 阻塞态(Blocked) | 等待延时或外部事件 | vTaskDelay、等待队列/信号量等 | 延时到、事件发生 |
| 挂起态(Suspended) | 类似暂停 | vTaskSuspend() | vTaskResume() 解挂 |
只有就绪态可以转变为运行态。其他状态的任务想要运行,必须先转变为就绪态。
FreeRTOS 实时内核通过滴答计数变量(Tick Count)测量时间。SysTick 定时器中断以固定频率递增滴答数,每次中断称为一个 RTOS 滴答。
每次滴答中断时,内核检查是否有任务需要解除阻塞或唤醒。如果需要,就在 ISR 中进行任务切换。
configTICK_RATE_HZ 配置项定义每秒的滴答数(通常设为 1000,即 1ms 一次滴答)。
上下文是任务执行时使用的所有处理器资源(寄存器、堆栈等)的集合。
上下文切换就是:暂停当前任务时保存其上下文到栈中,切换到下一个任务时从栈中恢复其上下文。这样任务恢复执行时,"以为自己从未被打断过"。
taskYIELD() 主动触发实际的上下文切换在 PendSV 中断服务函数中完成。PendSV 被设置为最低中断优先级,这样上下文切换不会影响其他关键 ISR。
触发方式:将 ICSR 寄存器的 bit28(PendSV 挂起位)置 1。
调度器启动时自动创建空闲任务,以最低优先级创建,确保至少有一个任务可运行。
空闲任务的三个作用:
| 作用 | 说明 |
|---|---|
| 释放被删任务的内存 | 任务调用 vTaskDelete 后,其资源在空闲任务中统一回收 |
| CPU 空闲计数 | 统计 CPU 空闲率,辅助性能分析 |
| 低功耗模式 | 配合 tickless 模式,在空闲时进入低功耗状态 |
就绪列表是 pxReadyTasksLists[x] 数组,其中 x 代表任务优先级(0 ~ configMAX_PRIORITIES-1)。
在 32 位硬件上,一个 32 位的位图变量标记哪些优先级对应的就绪列表中有任务:
多个相同优先级的任务连接在同一个就绪列表上:
调度器始终在所有就绪列表中选择最高优先级的任务来执行。
| Function | Parameters | Return | Description |
|---|---|---|---|
vTaskStartScheduler() |
void | void | 启动任务调度器 |
vTaskSuspend() |
TaskHandle_t | void | 挂起指定任务 |
vTaskResume() |
TaskHandle_t | void | 恢复被挂起的任务 |
taskYIELD() |
void | void | 主动请求任务切换 |
FromISR 后缀的函数。