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 工程为例):
FreeRTOSConfig.h- 作用:FreeRTOS 的 “开关面板”,由 CubeMX 根据用户配置(如任务优先级数量、栈大小、是否启用互斥锁等)自动生成。
- 关键配置项:
configMAX_PRIORITIES:最大任务优先级(如5,数值越大优先级越高);configTOTAL_HEAP_SIZE:内核堆大小(任务、队列等动态内存从这里分配);configUSE_PREEMPTION:是否启用抢占式调度(1启用,实时性核心);configUSE_IDLE_HOOK:是否启用空闲任务钩子函数(自定义空闲任务行为)。
MX_FreeRTOS_Init.c/MX_FreeRTOS_Init.h作用:用户任务的初始化入口,CubeMX 会在此文件中生成任务创建代码(基于用户在 CubeMX 中配置的任务)。
典型内容:
void MX_FreeRTOS_Init(void) {
// 创建任务(参数:任务函数、名称、栈大小、参数、优先级、任务句柄)
xTaskCreate(StartDefaultTask, "DefaultTask", 128, NULL, 1, &DefaultTaskHandle);
// 若配置了其他任务(如Task1、Task2),会在此处继续创建
}
stm32f1xx_it.c(中断服务函数文件)作用:集成 FreeRTOS 的中断适配,主要是系统时基中断(通常用 SysTick 定时器)。
关键代码:
void SysTick_Handler(void) {
HAL_IncTick(); // HAL库时基
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
xPortSysTickHandler(); // 调用FreeRTOS的SysTick处理函数,用于任务调度计时
}
}
FreeRTOS 官方源码文件
CubeMX 会将task.c、queue.c、timers.c等核心文件复制到工程的Middlewares/Third_Party/FreeRTOS/Source目录下,与硬件无关的逻辑保持不变。
三、FreeRTOS 源码的 “入口函数”
FreeRTOS 的运行始于调度器启动,整体流程如下(结合 CubeMX 生成的代码):
用户程序入口:
main()函数
CubeMX 生成的main.c中,main()先初始化硬件(HAL_Init()、时钟配置等),再调用MX_FreeRTOS_Init()创建任务,最后启动调度器:/* Init scheduler */
osKernelInitialize(); /* 初始化FreeRTOS运行环境 */
MX_FREERTOS_Init(); /* 创建任务 */ /* Start scheduler */
osKernelStart(); /* 启动调度器 里面调用vTaskStartScheduler()函数*/
调度器启动:
vTaskStartScheduler()
位于task.c,是 FreeRTOS 内核真正开始工作的入口,主要做三件事:- 初始化内核数据结构(任务链表、就绪列表、堆内存等);
- 创建空闲任务(
prvIdleTask,优先级最低,用于释放删除的任务内存); - 触发第一次上下文切换(
portRESTORE_CONTEXT()),切换到最高优先级的就绪任务执行。
第一个执行的任务
调度器启动后,会从 “就绪列表” 中选择优先级最高的任务执行。若用户在MX_FreeRTOS_Init()中创建了StartDefaultTask(默认任务),且它是最高优先级,则第一个执行的就是该任务。
四、FreeRTOS 源码的 “编程规则”
1、基础数据类型的前缀规则
FreeRTOS 不直接使用 C 语言原生类型(如int、long,因不同平台长度可能不同),而是通过自定义类型实现跨平台,这些类型的前缀有明确含义:
| 前缀 | 含义 | 对应原生类型(举例) | 用途场景 |
|---|---|---|---|
u |
Unsigned(无符号) | unsigned char、unsigned int |
无符号整数(如计数、长度) |
s |
Signed(有符号) | signed char、signed 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、通过前缀快速理解源码的技巧
- 看到
p开头的变量:立即识别为指针(如pxCurrentTCB是当前任务 TCB 的指针)。 - 看到
x开头的类型 / 变量:通常是结构体或复杂类型(如xTaskCreate()返回的是BaseType_t,但xQueue是队列结构体实例)。 - 看到
ul开头的变量:多为 32 位无符号整数(如ulTaskNumber表示任务编号)。 - 看到
Handle_t结尾的类型:均为 “句柄”,本质是指针,用于操作内核对象(任务、队列等)。
五、阅读源码的建议路径
- 从
main()开始,跟踪到freertos.c文件,看到vTaskStartScheduler(),理解调度器启动流程; - 重点看
task.c中的xTaskCreate()(任务创建)和vTaskSwitchContext()(任务切换); - 结合
FreeRTOSConfig.h的配置项,理解 “可裁剪” 特性(如关闭某个功能后,对应源码不参与编译); - 先忽略硬件相关的
port.c,聚焦通用逻辑(任务、队列),再深入架构适配细节。
04-FreeRTOS的概述及编程规范的更多相关文章
- 中兴软件编程规范C/C++
Q/ZX 深圳市中兴通讯股份有限公司企业标准 (设计技术标准) Q/ZX 04.302.1–2003 软件编程规范C/C++ 20 ...
- JAVA编程规范(下)
JAVA编程规范(下) 2016-03-27 6. 代码的格式化 6.1 对代码进行格式化时,要达到的目的 1. 通过代码分割成功能块和便于理解的代码段,使代码更容易阅读和理解: 2. ...
- 华为C语言编程规范
DKBA华为技术有限公司内部技术规范DKBA 2826-2011.5C语言编程规范2011年5月9日发布 2011年5月9日实施华为技术有限公司Huawei Technologies Co., Ltd ...
- C#编程规范
C#编程规范 Version 1.0 目录 第一章 概述.... 4 规范制定原则.... 4 术语定义.... 4 Pascal 大小写.... 4 Camel 大小写.... 4 文件命名组织 ...
- 快速构建Windows 8风格应用23-App Bar概述及使用规范
原文:快速构建Windows 8风格应用23-App Bar概述及使用规范 本篇博文主要介绍App Bar概述.App Bar命令组织步骤.App Bar最佳实践. App Bar概述 Windo ...
- .NET编程规范
.NET开发编程规范 第1章 程序的版式 版式虽然不会影响程序的功能,但会影响可读性.程序的版式追求清晰.美观,是程序风格的重要构成因素. 可以把程序的版式比喻为"书法".好的&q ...
- jQuery编程规范与最佳实践(附带一些个人的笔记)
加载jQuery-Loading jQuery 1.坚持使用CDN来加载jQuery,这种别人服务器免费帮你托管文件的便宜干嘛不占呢.点击查看使用CDN的好处,点此查看一些主流的jQuery CDN地 ...
- 国内大型的内部 C# 编程规范
C#编程规范 改动记录 Ver. No 发版日期 编制人 批准人 改动的说明 目 录 1 1.1 1.2 2 2.1 2.1.1 Pascal 大写和小写 2.1.2 Came ...
- Qt编程规范
一.概述 良好的编程规范可以大幅提高一个程序的可读性.可理解性和可维护性. 本规范参考Effective C++中文版.Google C++编码规范及Qt编码风格. 二.头文件 1) #de ...
- 第04章 AOP概述
第04章 AOP概述 1.AOP概述 ●AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传统 OOP(Object-Oriented Progra ...
随机推荐
- 【字节跳动高频面试题】不超过 N 的最大数拼接
[字节跳动高频面试题]不超过 N 的最大数拼接 题目描述 给定一个按 非递减顺序 排列的数字字符数组 digits(如 ["1","3","5&quo ...
- node调用powershell脚本
前提 .bat 是 Windows 批处理脚本文件的扩展名,用于编写和执行一系列 Windows 命令. .ps1才是是 PowerShell 脚本文件的扩展名,用于编写和执行 PowerShell ...
- jenkins部署完微信推送
前言 我需要一款使用简单方便: 支持微信.企业微信.短信.邮件等通知: 消息多样化,支持markdown等格式消息: 支持消息存储: 免费使用: 于是我找到了一款插件.目前还是免费pushplus. ...
- 前端开发系列034-基础篇之RegExp正则表达式
本文介绍RegExp相关的知识点,包括正则表达式的创建.匹配规则等内容. RegExp简单介绍 正则表达式Regular Expression是描述字符模式的对象,在JavaScript语言中提供了内 ...
- 模拟退火 python 实现
简介 一直以为是一个高深的算法,好像据说在量子计算机中可以应用.发现原理并不难 参考链接 https://blog.csdn.net/google19890102/article/details/45 ...
- Day7 备战CCF-CSP练习
Day 7 题目描述 栋栋最近开了一家餐饮连锁店,提供外卖服务. 随着连锁店越来越多,怎么合理的给客户送餐成为了一个急需解决的问题. 栋栋的连锁店所在的区域可以看成是一个 \(n×n\)的方格图(如下 ...
- ETL数据集成丨SQLServer到Doris的无缝数据同步策略
在数据驱动的新时代,企业对数据的需求日益增加,尤其是数据同步的速度和准确性.随着数据源和数据目标的多样化,如何实现高效.无缝的数据同步成为了许多企业的关注焦点.ETLCloud正是这一领域的先锋,为用 ...
- RestCloud ETL抽取动态库表数据实践
RestCloud ETL社区版是一款数据集成工具,提供可视化多数据管道构建.数据源管理.运行监控及权限管理功能. 1.场景说明: 对于一些业务系统每天运行自动产生一张新数据表,希望通过1条数据流 ...
- SciTech-Mathmatics - Advanced Linear Algebra: 矩阵乘法 的 四种理解方式 + 向量 的空间&基、坐标&坐标变换 + Eigenvalue Decompression(特征值分解) + SVD(奇异值分解, Singular Value Decomposition)
SciTech-Mathmatics - Advanced Linear Algebra(高等线性代数): 矩阵乘法 的 四种理解方式 矩阵乘法有四种理解方式: 线性方程组视角:将矩阵看作行向量与向量 ...
- 题解:Luogu-P9433 [NAPC-#1] Stage5 - Conveyors
传送门 个人认为,做这种题把思路想清晰代码自然就写出来了,所以要注重思考的过程,重点把握一些自己想不到的性质或技巧. 本篇题解在现有题解的基础上对解法进行了更详细的说明.阅读前建议确保自己会树链剖分和 ...