
1. 任务管理
任务是 FreeRTOS 的最小执行单元,每个任务都是一个无限循环的函数,拥有独立的栈空间、任务控制块(TCB)和执行上下文。
1.1 任务控制块(TCB)
TCB 是任务的 "身份证",是一个结构体,存储了任务的所有核心信息,包括:
- 任务栈顶指针
- 任务优先级
- 任务状态
- 任务名称
- 任务句柄
- 链表节点(用于挂载到不同状态的链表)
- 任务通知值等
1.2 任务栈
每个任务都有独立的栈空间,用于:
- 上下文切换时保存 CPU 寄存器状态
- 函数调用时保存返回地址、局部变量、函数参数
- 中断发生时保存现场
栈大小通过任务创建函数指定,栈溢出是嵌入式开发最常见的 bug ,FreeRTOS 提供了栈溢出检测机制,通过configCHECK_FOR_STACK_OVERFLOW宏开启。
1.3 核心任务管理 API
| API 函数 | 核心功能 |
|---|---|
xTaskCreate() |
动态创建任务,内核自动从堆中分配 TCB 和栈空间 |
xTaskCreateStatic() |
静态创建任务,用户预先分配 TCB 和栈空间,无内存分配失败风险 |
vTaskDelete() |
删除任务,动态创建的任务内存会在空闲任务中回收 |
vTaskSuspend() |
挂起任务,任务进入挂起态,不再参与调度 |
vTaskResume() |
恢复挂起的任务,任务回到就绪态 |
vTaskDelay() |
相对延时,任务进入阻塞态指定 Tick 数 |
vTaskDelayUntil() |
绝对延时,保证任务以固定周期执行,补偿任务执行时间 |
vTaskPrioritySet() |
动态修改任务优先级 |
uxTaskPriorityGet() |
获取任务当前优先级 |
2. 调度器
调度器是内核的核心,负责任务的调度决策,核心 API:
vTaskStartScheduler():启动调度器,自动创建空闲任务,开启 Tick 定时器,调度器启动后不会返回。vTaskEndScheduler():停止调度器,仅 x86 架构支持,嵌入式场景极少使用。vTaskSuspendAll():挂起调度器,禁止任务切换,但不关闭中断。xTaskResumeAll():恢复调度器,重新开启任务调度。
3. 队列
队列是 FreeRTOS 最核心的任务间通信机制,用于任务与任务、任务与中断之间传递数据,实现异步通信。
核心特性:
- 队列是带长度的缓冲区,可存储固定大小、固定数量的消息。
- 支持值传递(直接拷贝数据)和引用传递(传递指针)。
- 支持多任务读写,线程安全。
- 读写支持阻塞超时机制。
核心 API:
| API 函数 | 核心功能 |
|---|---|
xQueueCreate() |
动态创建队列,指定队列长度和单条消息大小 |
xQueueCreateStatic() |
静态创建队列 |
xQueueSend() / xQueueSendToBack() |
向队列尾部写入消息,支持阻塞超时 |
xQueueSendToFront() |
向队列头部写入消息 |
xQueueReceive() |
从队列头部读取消息,同时移除消息,支持阻塞超时 |
xQueuePeek() |
读取队列消息,不移除消息 |
uxQueueMessagesWaiting() |
获取队列中当前的消息数量 |
vQueueDelete() |
删除队列,释放内存 |
| 中断安全版本 | 带FromISR后缀,如xQueueSendFromISR(),用于中断服务函数中 |
4. 信号量与互斥锁
信号量用于任务间的同步、资源计数,互斥锁用于共享资源的互斥访问,解决临界区竞争问题。
4.1 二进制信号量
核心特性:计数值只有 0 和 1 两种状态,适用于任务与中断的同步、二值资源的互斥访问。典型场景:中断服务函数中释放信号量,唤醒任务执行后续的中断底半部处理。
4.2 计数信号量
核心特性:计数值可设置范围,适用于资源计数、多实例资源管理、事件计数。典型场景:生产者 - 消费者模型,生产者释放信号量增加计数,消费者获取信号量减少计数。
4.3 互斥锁(互斥信号量)
核心特性:
- 带优先级继承机制,解决优先级反转问题。
- 支持递归获取,同一个任务可多次获取,必须对应次数释放。
- 仅能由获取的任务释放,不能在中断中释放。典型场景:多任务访问同一硬件外设(如 UART、SPI)、共享全局变量,保证同一时刻只有一个任务访问。
4.4 核心 API
| API 函数 | 核心功能 |
|---|---|
xSemaphoreCreateBinary() |
创建二进制信号量 |
xSemaphoreCreateCounting() |
创建计数信号量,指定最大计数值和初始值 |
xSemaphoreCreateMutex() |
创建互斥锁 |
xSemaphoreCreateRecursiveMutex() |
创建递归互斥锁 |
xSemaphoreTake() |
获取信号量 / 互斥锁,支持阻塞超时 |
xSemaphoreGive() |
释放信号量 / 互斥锁 |
xSemaphoreTakeRecursive() / xSemaphoreGiveRecursive() |
递归互斥锁的获取 / 释放 |
| 中断安全版本 | 带FromISR后缀,仅适用于二进制 / 计数信号量 |
5. 任务通知
任务通知是 FreeRTOS 提供的轻量级同步 / 通信机制,每个任务都有一个 32 位的通知值,无需创建额外的内核对象,RAM 开销极小,速度比队列、信号量快 45% 左右。
核心特性:
- 无需创建内核对象,直接操作任务的通知值。
- 支持多种通知模式:设置通知值、累加通知值、置位位、发送事件。
- 支持阻塞等待通知,超时唤醒。
- 适用于中断到任务的同步、二值信号量、计数信号量、事件组、轻量级消息邮箱等场景。
核心 API:
| API 函数 | 核心功能 |
|---|---|
xTaskNotifyGive() |
发送通知,等效于释放二进制 / 计数信号量 |
ulTaskNotifyTake() |
获取通知,等效于获取二进制 / 计数信号量 |
xTaskNotify() |
发送通知,支持多种通知模式 |
xTaskNotifyWait() |
等待通知,支持掩码过滤位 |
| 中断安全版本 | 带FromISR后缀,用于中断服务函数中 |
6. 事件组
事件组用于多事件的组合等待、多任务的同步,一个事件组用一个 32 位的变量表示,每一位代表一个事件。
核心特性:
- 支持等待多个事件中的任意一个(逻辑或),或等待所有事件都发生(逻辑与)。
- 支持等待事件时自动清除事件位。
- 适用于多条件触发的任务、多个任务同步到同一个事件点的场景。
核心 API:xEventGroupCreate()(创建事件组)、xEventGroupSetBits()(置位事件位)、xEventGroupWaitBits()(等待指定位的事件)、xEventGroupClearBits()(清除事件位),以及对应的中断安全版本。
7. 软件定时器
软件定时器基于系统 Tick 时钟实现,无需占用硬件定时器,可设置定时时间,到期后执行回调函数。
核心特性:
- 支持单次模式和周期模式。
- 定时器回调函数在定时器服务任务中执行,回调函数中不能调用阻塞式 API。
- 可动态启动、停止、重置、修改定时周期。
核心配置与 API:
必须开启configUSE_TIMERS宏,配置定时器服务任务的优先级和栈大小。| API 函数 | 核心功能 ||---|---|| xTimerCreate() | 创建软件定时器,指定定时周期、模式、回调函数 |
| xTimerStart() | 启动定时器 || xTimerStop() | 停止定时器 |
| xTimerReset() | 重置定时器,重新开始计时 |
| xTimerChangePeriod() | 动态修改定时器的定时周期 |
| 中断安全版本 | 带FromISR后缀,用于中断服务函数中 |
8. 空闲任务与钩子函数
- 空闲任务:调度器启动时自动创建,优先级最低,仅当系统中无其他就绪任务时执行。核心职责:回收已删除任务的内存、执行空闲钩子函数、进入低功耗模式。
- 钩子函数 :FreeRTOS 提供的回调机制,用户可实现钩子函数,在特定事件发生时被系统调用,无需修改内核源码。常用钩子函数:
- 空闲钩子函数
vApplicationIdleHook():空闲任务执行时调用,可用于低功耗处理、CPU 使用率统计。 - Tick 钩子函数
vApplicationTickHook():每个 Tick 中断中调用,可用于时间统计、高频采样。 - 栈溢出钩子函数
vApplicationStackOverflowHook():检测到任务栈溢出时调用,用于故障处理。 - 内存分配失败钩子函数
vApplicationMallocFailedHook():内存分配失败时调用,用于故障处理。
- 空闲钩子函数