FREERTOS的核心内容与核心组件

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():内存分配失败时调用,用于故障处理。
相关推荐
xian_wwq3 小时前
【学习笔记】GB/T 20986-2023 详解,10 类网络安全事件分类
笔记·学习·web安全
鱼鳞_3 小时前
Java学习笔记_Day27(Stream流)
java·笔记·学习
_李小白3 小时前
【OSG学习笔记】Day 42: OSG 动态场景安全修改
笔记·学习·安全
Kapibalapikapi3 小时前
思考笔记 | SSL证书过期的影响
笔记·加解密
扣脑壳的FPGAer4 小时前
数字信号处理学习笔记--Chapter 1.3 常系数线性差分方程
笔记·学习·信号处理
NULL指向我4 小时前
TMS320F28379D笔记1:主控-从核双核架构认识
笔记·单片机
m0_716765234 小时前
数据结构三要素、时间复杂度计算详解
开发语言·数据结构·c++·经验分享·笔记·算法·visual studio
我不是懒洋洋4 小时前
AI的影响7
笔记
嵌入式×边缘AI:打怪升级日志5 小时前
Makefile 完全学习笔记:从入门到通用模板解析
笔记·学习