FreeRTOS 是市场领先的面向微控制器和小型微处理器的实时操作系统 (RTOS),在世界范围内被广泛应用。它通过 MIT 开源许可免费分发,包含一个内核和一组不断丰富的 IoT 库,其设计核心是可靠性与易用性。
一、裸机与RTOS
1、裸机开发模式
裸机开发通常被称为前后台系统。这里的“前台”指的是中断服务函数,而“后台”则指的是包含主要应用程序逻辑的大循环。
想象一个典型的应用场景:你正在打游戏,同时需要回复信息。在裸机系统里,代码结构往往是这样的:
while(1) {
打游戏();
回复信息();
if(FLAG == 1) {
去医院();
FLAG = 0;
}
}
这意味着你必须先打完一局游戏,或者先回复完所有信息,才能处理其他事情。
这种模式有几个显著特点:
- 实时性差:所有功能依次轮流执行,紧急事件无法得到即时响应。
- CPU空转:使用
delay 函数时,CPU 会进入空等待,宝贵资源被白白浪费。
- 结构臃肿:所有功能都堆积在无限循环中,代码难以维护和扩展。

图示:裸机系统中大循环(后台任务)与中断(前台)的交替执行过程。
2、RTOS的优势
RTOS 全称 Real Time OS,即实时操作系统,其核心诉求就是实时性。
同样以打游戏和回复信息为例,在 RTOS 下,事情的处理方式截然不同。系统可以将这两件事定义为两个独立的任务,然后每间隔一个很短的时间片(例如1ms),就在这两个任务之间进行切换。由于切换速度极快,从宏观上看,两件事就像是在同步执行!
这种设计带来了诸多优点:
- 分而治之:将复杂功能划分为多个独立的、易于管理的任务。
- 高效延时:任务的延时函数不会导致CPU空等,而是会交出 CPU 使用权给其他就绪的任务,这个过程就是任务调度。
- 抢占式调度:高优先级任务可以随时打断正在运行的低优先级任务,确保紧急事务优先处理。
- 独立堆栈:每个任务都拥有自己的栈空间,用于保存局部变量和任务上下文,这是多任务并发的基石。
注意:
- 中断可以打断任何优先级的任务。
- 多个任务可以设置为同等优先级。
潜在问题:如果高优先级任务一直处于运行态(例如一个死循环),那么低优先级任务将永远无法获得执行机会。这需要开发者通过合理的任务设计和调度策略来避免。

图示:在RTOS中,任务通过创建函数生成,调度器根据优先级管理其执行,中断(ISR)可以介入。
二、深入理解FreeRTOS
简介:FreeRTOS 是一款专为嵌入式领域设计的实时操作系统内核。
核心特点:
- 免费开源:采用 MIT 许可证,商业应用无风险。
- 高度可裁剪:内核精简,可根据需求裁剪,最小化资源占用。
- 简单易移植:架构清晰,可移植性极佳,易于适配不同硬件。
- 灵活的优先级:任务优先级分配无限制,允许多个任务共享同一优先级。
- 任务数无硬限制:可创建的任务数量取决于可用内存,无软件层面的限制。
- 调度方式多样:支持抢占式、协程式和时间片轮转等多种调度算法。
1、任务调度剖析
调度器是操作系统的核心,它负责根据既定算法决定当前应执行哪个任务。FreeRTOS主要支持三种调度方式。
① 抢占式调度
这是针对不同优先级任务的调度策略。核心规则很简单:高优先级任务可随时抢占低优先级任务的CPU使用权。

图示:优先级分别为1、2、3的三个任务(数值越大优先级越高)的抢占调度过程。
运行过程解析:
- Task1(优先级1)首先运行。
- 当优先级更高的 Task2(优先级2)就绪时,立即抢占 Task1 并开始运行。
- 当优先级更高的 Task3(优先级3)就绪时,又立即抢占 Task2。
- 如果 Task3 因等待事件而阻塞,则系统会转而执行就绪态中优先级最高的任务,即 Task2。
- 一旦 Task3 阻塞解除,它会再次抢占 Task2,恢复执行。
要点总结:
- 高优先级任务绝对优先执行。
- 只要高优先级任务不主动让出 CPU(如进入阻塞态),低优先级任务就无法运行。
- 被抢占的任务会进入就绪态,等待下次被调度。
② 时间片调度
当多个任务优先级相同时,抢占式调度无法区分它们。这时就需要时间片调度:系统会在每个时钟节拍中断到来时,在同优先级任务之间进行切换。每个任务每次运行的时间长度称为一个“时间片”,在 FreeRTOS 中,一个时间片就等于系统滴答定时器 (SysTick) 的中断周期。

图示:三个同等优先级任务按时间片轮流执行。
运行过程解析:
- Task1 运行一个完整时间片后,切换至 Task2。
- Task2 运行一个完整时间片后,切换至 Task3。
- Task3 运行过程中,若未用完一个时间片就发生阻塞,则立即切换到下一个任务 Task1,剩余的时间片被舍弃。
- 当再次轮到 Task3 执行时,它将重新获得一个完整的时间片。
要点总结:
- 同等优先级任务轮流执行,公平分享 CPU 时间。
- 时间片大小由滴答定时器周期决定。
- 未用完的时间片不会累积,任务下次被调度时,计时将重新开始。
③ 协程式调度
这种方式已不再被官方推荐和更新。其特点是:当前运行的任务会一直执行直到主动放弃 CPU,且高优先级任务不能抢占低优先级任务。目前主要作为了解即可。
2、任务的四种状态
FreeRTOS 中的任务在任何时刻都处于以下四种状态之一:
- 运行态:任务正在 CPU 上执行。对于单核 MCU(如 STM32),同一时刻只能有一个任务处于运行态。
- 就绪态:任务已准备就绪,随时可以执行,只是当前还未被调度器选中。
- 阻塞态:任务因为等待某些事件(如延时到期、信号量、队列消息)而暂时无法运行。
- 挂起态:任务被暂停,只能通过调用
vTaskSuspend() 进入此状态,并且必须调用 vTaskResume() 解挂后才能回到就绪态。

图示:任务在运行态、就绪态、阻塞态和挂起态之间的转换关系。
核心规则:只有就绪态的任务才能转变为运行态。其他状态的任务想要运行,必须先转换到就绪态。
任务状态列表的管理:
除了运行态,其他三种状态的任务都由相应的列表(本质是链表)来管理,分别是:就绪列表、阻塞列表、挂起列表。

图示:就绪列表通过一个位图和指针数组来高效管理不同优先级的就绪任务。
- 就绪列表:一个按优先级索引的数组,每个元素指向一个链表,链接着所有处于该优先级的就绪任务。
- 阻塞列表:一个按唤醒时间排序的链表。
- 挂起列表:一个简单的链表。
调度器的工作,就是从所有就绪列表中,选出优先级最高的那个任务来执行。如果同一优先级有多个任务,它们会被链接到同一个就绪列表上,根据调度策略(如时间片)轮流执行。

图示:三个优先级不同的任务在就绪列表中的组织方式。
三、FreeRTOS源码与移植指南
1、源码结构解析
你可以从 FreeRTOS官网 下载最新源码。

下载后通常能看到 FreeRTOS(内核)、FreeRTOS-Plus(附加组件)和 tools(工具)三个主要目录。我们最关心的是内核目录。

进入 FreeRTOS 目录,关键子目录包括:
Demo:丰富的演示例程。
Source:真正的内核源代码,这是移植的核心。
License:许可证文件。

Source 目录下是关键文件,其中必须关注的有:
include/:所有头文件。
portable/:移植层文件,这是连接 FreeRTOS 与不同编译器和 MCU 硬件的桥梁。
tasks.c:任务创建、调度相关。
queue.c:队列相关。
list.c:内核使用的链表实现。
timers.c:软件定时器。
对于使用 Keil MDK 开发 STM32 的开发者,在 portable 目录下需要重点关注 MemMang(内存管理方案)和 RVDS(对应 ARM 内核的移植文件)文件夹。

2、移植步骤概览(基于HAL库)
将 FreeRTOS 移植到 STM32 工程,通常遵循以下步骤,这也是理解操作系统如何与硬件结合的好机会:
- 添加源码到工程:将
Source 目录下的核心文件(.c 和 .h)添加到你的 MDK 工程中,并正确配置头文件包含路径。
- 配置
FreeRTOSConfig.h:这是 FreeRTOS 的“总控开关”文件。你需要根据项目需求,在此文件中通过宏定义来裁剪功能、使能或禁用API、配置系统时钟、堆栈大小等。
官方配置说明参考:https://www.freertos.org/a00110.html
- 修改系统文件:通常需要修改
delay.c(用 FreeRTOS 的时钟节拍替代原有延时)、usart.c(中断中发送信号量或消息)等。
- 处理关键中断:主要是配置好 SysTick 中断(作为系统时钟节拍)、SVC 和 PendSV 中断(用于任务调度和上下文切换)。
- 编写测试任务:创建一两个简单的任务(如让 LED 闪烁),验证移植是否成功。
FreeRTOSConfig.h 中的宏定义主要分三类:
INCLUDE_ 开头:用于控制可选 API 函数是否被编译。
config 开头:完成内核功能的配置和裁剪(如最大优先级、任务数等)。
- 其他:如
PendSV、SVC 的中断优先级配置。
掌握了这些关于计算机基础的核心概念与实操步骤,你就能为项目成功引入 FreeRTOS,迈出开发复杂嵌入式应用的关键一步。如果想与更多开发者交流此类问题,可以到 云栈社区 的相关板块参与讨论。