当前位置: 首页 > news >正文

04-FreeRTOS的概述及编程规范

概述

本文对FreeRTOS源码进行概述,包括其核心文件作用,及其编程规范,有助于阅读rtos的内核源码,更好的帮助理解。

一、FreeRTOS 源码核心结构概述

FreeRTOS 是轻量级实时操作系统,核心功能围绕 “任务调度” 和 “任务间通信” 展开,源码结构清晰,可分为内核核心文件可选组件

类别 核心文件 主要功能
任务管理 task.c 任务创建(xTaskCreate())、删除、挂起 / 恢复,以及核心的调度器实现(vTaskStartScheduler())。
调度器核心 同上(调度逻辑嵌入task.c 基于优先级的抢占式调度(可配置为时间片轮转),上下文切换(portYIELD())。
队列 / 通信 queue.c/list.c 实现队列(任务间数据传递)、信号量(SemaphoreHandle_t)、互斥锁(MutexHandle_t)等。
时间管理 timers.c 软件定时器(xTimerCreate()),基于系统时基触发回调函数。
配置文件 FreeRTOSConfig.h 内核裁剪配置(如任务最大优先级、栈大小、钩子函数使能等),是适配硬件的关键。
硬件接口 port.c/portmacro.h 与 CPU 架构相关的底层实现(如 ARM Cortex-M 的上下文切换、中断处理),由芯片厂商适配。

二、STM32CubeMX 生成的 RTOS 中间件文件及作用

CubeMX 会自动集成 FreeRTOS 源码,并生成适配 STM32 的配置文件初始化代码,核心文件如下(以 STM32 工程为例):

  1. FreeRTOSConfig.h

    • 作用:FreeRTOS 的 “开关面板”,由 CubeMX 根据用户配置(如任务优先级数量、栈大小、是否启用互斥锁等)自动生成。
    • 关键配置项:
      • configMAX_PRIORITIES:最大任务优先级(如5,数值越大优先级越高);
      • configTOTAL_HEAP_SIZE:内核堆大小(任务、队列等动态内存从这里分配);
      • configUSE_PREEMPTION:是否启用抢占式调度(1启用,实时性核心);
      • configUSE_IDLE_HOOK:是否启用空闲任务钩子函数(自定义空闲任务行为)。
  2. MX_FreeRTOS_Init.c/MX_FreeRTOS_Init.h

    • 作用:用户任务的初始化入口,CubeMX 会在此文件中生成任务创建代码(基于用户在 CubeMX 中配置的任务)。

    • 典型内容:

      void MX_FreeRTOS_Init(void) {// 创建任务(参数:任务函数、名称、栈大小、参数、优先级、任务句柄)xTaskCreate(StartDefaultTask, "DefaultTask", 128, NULL, 1, &DefaultTaskHandle);// 若配置了其他任务(如Task1、Task2),会在此处继续创建
      }
      
  3. stm32f1xx_it.c(中断服务函数文件)

    • 作用:集成 FreeRTOS 的中断适配,主要是系统时基中断(通常用 SysTick 定时器)。

    • 关键代码:

      void SysTick_Handler(void) {HAL_IncTick();  // HAL库时基if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {xPortSysTickHandler();  // 调用FreeRTOS的SysTick处理函数,用于任务调度计时}
      }
      
  4. FreeRTOS 官方源码文件
    CubeMX 会将task.cqueue.ctimers.c等核心文件复制到工程的Middlewares/Third_Party/FreeRTOS/Source目录下,与硬件无关的逻辑保持不变。

三、FreeRTOS 源码的 “入口函数”

FreeRTOS 的运行始于调度器启动,整体流程如下(结合 CubeMX 生成的代码):

  1. 用户程序入口:main()函数
    CubeMX 生成的main.c中,main()先初始化硬件(HAL_Init()、时钟配置等),再调用MX_FreeRTOS_Init()创建任务,最后启动调度器:

    /* Init scheduler */
    osKernelInitialize();  /* 初始化FreeRTOS运行环境 */
    MX_FREERTOS_Init();    /* 创建任务 *//* Start scheduler */
    osKernelStart();       /* 启动调度器 里面调用vTaskStartScheduler()函数*/
    
  2. 调度器启动:vTaskStartScheduler()
    位于task.c,是 FreeRTOS 内核真正开始工作的入口,主要做三件事:

    • 初始化内核数据结构(任务链表、就绪列表、堆内存等);
    • 创建空闲任务prvIdleTask,优先级最低,用于释放删除的任务内存);
    • 触发第一次上下文切换(portRESTORE_CONTEXT()),切换到最高优先级的就绪任务执行。
  3. 第一个执行的任务
    调度器启动后,会从 “就绪列表” 中选择优先级最高的任务执行。若用户在MX_FreeRTOS_Init()中创建了StartDefaultTask(默认任务),且它是最高优先级,则第一个执行的就是该任务。

四、FreeRTOS 源码的 “编程规则”

1、基础数据类型的前缀规则

FreeRTOS 不直接使用 C 语言原生类型(如intlong,因不同平台长度可能不同),而是通过自定义类型实现跨平台,这些类型的前缀有明确含义:

前缀 含义 对应原生类型(举例) 用途场景
u Unsigned(无符号) unsigned charunsigned int 无符号整数(如计数、长度)
s Signed(有符号) signed charsigned int 有符号整数(如差值、偏移量)
x 结构体 / 枚举 / 大型类型(自定义) 无固定原生类型(如任务控制块、队列) 复杂结构(任务、队列、事件组)
p Pointer(指针) 任意类型的指针 指向变量、数组、结构体的指针
ul Unsigned Long(无符号长整数) unsigned long(通常 32 位) 较大的无符号数值(如系统时间)
l Long(有符号长整数) long(通常 32 位) 较大的有符号数值

2、典型组合示例(前缀 + 类型)

这些组合在源码中高频出现,掌握后能快速识别变量用途:

变量 / 类型示例 前缀解析 含义说明
uint8_t u(无符号)+ int8 8 位无符号整数(等价于unsigned char
int32_t s(隐含)+ int32 32 位有符号整数(等价于int32_t
pucBuffer p(指针)+ u(无符号)+ c(字符) 指向无符号字符数组的指针(缓冲区指针)
pxTaskTCB p(指针)+ x(结构体) 指向任务控制块(TCB,结构体)的指针
ulTickCount ul(无符号长整数) 以系统时基为单位的计数器(如uint32_t
xQueueHandle x(自定义类型) 队列句柄(本质是指向队列结构体的指针)
s16Error s(有符号)+ 16(16 位) 16 位有符号错误码

3、FreeRTOS 核心自定义类型(带固定前缀)

除了基础类型,FreeRTOS 定义了大量用于特定功能的类型,其命名也遵循规则:

自定义类型 前缀 / 后缀 含义与用途
BaseType_t Base(基础) 平台默认的 “基础整数类型”(通常是 32 位有符号),作为多数 API 的返回值类型(如成功返回pdPASS)。
TickType_t Tick(时基) 用于表示系统时基( ticks )的类型(通常是uint32_t),如vTaskDelay()的参数类型。
TaskHandle_t Handle_t(句柄) 任务句柄(本质是指向TCB_t结构体的指针),用于操作任务(如vTaskSuspend(TaskHandle_t))。
QueueHandle_t Handle_t 队列句柄(指向队列结构体的指针),用于队列操作(如xQueueSend(QueueHandle_t))。
SemaphoreHandle_t Handle_t 信号量句柄(与队列句柄通用,因信号量基于队列实现)。
TCB_t TCB(任务控制块) 任务控制块结构体(x类型),存储任务的所有信息(栈、优先级、状态等)。

4、特殊标识:宏定义与常量的前缀

FreeRTOS 的宏和常量也有前缀规则,用于区分功能:

前缀 含义 示例
pd Portable Define(可移植定义) pdTRUE(真)、pdFALSE(假)、pdPASS(成功)、pdFAIL(失败)。
config 配置项(来自FreeRTOSConfig.h configMAX_PRIORITIES(最大优先级)、configTICK_RATE_HZ(时基频率)。
err 错误码 errQUEUE_FULL(队列满)、errTIMEOUT(超时)。

5、通过前缀快速理解源码的技巧

  1. 看到p开头的变量:立即识别为指针(如pxCurrentTCB是当前任务 TCB 的指针)。
  2. 看到x开头的类型 / 变量:通常是结构体或复杂类型(如xTaskCreate()返回的是BaseType_t,但xQueue是队列结构体实例)。
  3. 看到ul开头的变量:多为 32 位无符号整数(如ulTaskNumber表示任务编号)。
  4. 看到Handle_t结尾的类型:均为 “句柄”,本质是指针,用于操作内核对象(任务、队列等)。

五、阅读源码的建议路径

  1. main()开始,跟踪到freertos.c文件,看到vTaskStartScheduler(),理解调度器启动流程;
  2. 重点看task.c中的xTaskCreate()(任务创建)和vTaskSwitchContext()(任务切换);
  3. 结合FreeRTOSConfig.h的配置项,理解 “可裁剪” 特性(如关闭某个功能后,对应源码不参与编译);
  4. 先忽略硬件相关的port.c,聚焦通用逻辑(任务、队列),再深入架构适配细节。
http://www.hskmm.com/?act=detail&tid=17076

相关文章:

  • 10_ select/poll/epoll实现服务端的io多路复用
  • 模拟实战配置实验
  • 国标GB28181公网直播EasyGBS如何构建全域覆盖的应急管理与安全生产解决方案?
  • Serilog.AspNetCore与Serilog的区别
  • 基于MATLAB S函数实现多智能体间歇通信仿真
  • 我天,前端岗要消亡了吗?
  • 闲话
  • java8的集合新API - --
  • 基于MATLAB/Simulink的500kW三相光伏逆变器仿真
  • Docker Compose启动多个镜像实例
  • 卫星时间同步平台:助力分布式测控系统同步工作
  • mkfx 对磁盘设置标签
  • C# Avalonia 15- Animation- Easing
  • 安卓编译重点记录
  • kubelet源码阅读(二)——device plugin 的ListAndWatch过程
  • CyberLink ColorDirector Ultra 2026 14.0.5712.0 视频后期调色
  • CF 1053 Div.2
  • vi编辑器
  • 豆油
  • MQTT
  • 源码安装fail2ban
  • 类的继承与继承的覆盖
  • linux shell awk 中括号 方括号 分割 []
  • springboot配置文件关系及加载顺序
  • 绩效面谈中的优质提问(一)
  • 简单博弈
  • 从 “纸笔清单” 到全栈引擎:数据填报与类 Excel 控件如何重塑企业效率曲线 - 详解
  • 触摸IC原厂 VKD223EB是一款低电流1通道触控1按键触摸芯片 HBM静电大于5KV
  • 09_五大IO模型
  • wsl Ubuntu 使用cmake