--- tags: [source-summary] type: source source: "尚硅谷嵌入式技术之FreeRTOS实时操作系统 V1.0.3 — FreeRTOS移植" author: "尚硅谷研究院" date: 2026-07-17 created: 2026-07-17 --- # FreeRTOS 移植指南 > **用生活理解**:移植 FreeRTOS 就像给一台电脑装操作系统——你得知道安装包(源码结构)里有什么,按照步骤装驱动(移植文件),再配置系统设置(FreeRTOSConfig.h),最后开机运行。我们的芯片是 Cortex-M3,选对应驱动即可。 ## FreeRTOS 源码结构 ### 基本概念 FreeRTOS 源码包顶层结构: | 目录 | 说明 | | -------------------- | ------------------------- | | `FreeRTOS/` | 内核源码——移植的核心 | | `FreeRTOS-Plus/` | 第三方组件(TCP、FAT 等) | | `Tools/` | 工具 | | `Quick_Start_Guide/` | 快速入门指南 | ### Source/ 目录详解 `FreeRTOS/Source/` 是最重要的文件夹: ``` Source/ ├── include/ # 通用头文件(与编译器/处理器无关) ├── portable/ # 移植文件(与编译器/架构相关) │ ├── Keil/ # → 指向 RVDS │ ├── RVDS/ # 各处理器核的接口文件 │ │ └── ARM_CM3/ # Cortex-M3 移植(port.c + portmacro.h) │ └── MemMang/ # 内存管理(heap_1 ~ heap_5) ├── croutine.c # 协程(可选) ├── event_groups.c # 事件组(可选) ├── list.c # 列表(必选) ├── queue.c # 队列(可选,但信号量/互斥量依赖它) ├── stream_buffer.c # 流式缓冲区(可选) ├── tasks.c # 任务管理(必选) └── timers.c # 软件定时器(可选) ``` - **必选** .c 文件:`tasks.c`、`list.c`(基础依赖) - **portable**:`RVDS/ARM_CM3/port.c`(Cortex-M3 移植接口)+ `portmacro.h` - **MemMang**:选一个 heap 文件,初学者推荐 **heap_4.c** ### Portable 层 portable 目录是连接 FreeRTOS 与硬件的桥梁,包含两部分: | 组件 | 文件 | 说明 | | ---------- | ------------- | ------------------------------------ | | 移植接口 | `port.c` | 上下文切换汇编代码(已由官方编写好) | | 移植头文件 | `portmacro.h` | 数据类型定义和宏定义 | 对于 STM32F103(Cortex-M3 内核),只需使用 `RVDS/ARM_CM3/` 下的这两个文件即可。官方已经把底层移植代码写好了,我们只需要"拿起即用"。 ### MemMang 方案对比 | 算法 | 特点 | 适用场景 | | ---------- | ------------------------------ | ------------------------ | | heap_1 | 只分配不释放,无碎片 | 确定不需要删除任务的场景 | | heap_2 | 最佳匹配,可释放,会碎片 | 不推荐,已被 heap_4 替代 | | heap_3 | 简单包装 malloc/free,线程安全 | 编译器的 malloc 可用时 | | **heap_4** | 首次匹配,合并相邻空闲块 | **初学者首选,通用场景** | | heap_5 | heap_4 + 跨非连续内存区域 | 多块物理内存的场景 | ## HAL 库移植步骤 ### 步骤1:目录添加源码文件 1. 在工程根目录新建 `FreeRTOS/` 文件夹,其下创建 `portable/` 和 `source/` 2. 复制 `FreeRTOS/Source/` 下的 **7 个 .c 文件**(tasks.c, queue.c, timers.c, event_groups.c, croutine.c, list.c, stream_buffer.c)到 `source/` 3. 复制 `portable/` 下的 `Keil/`、`RVDS/`、`MemMang/` 到 `portable/` 4. `MemMang/` 只保留 `heap_4.c` 5. `RVDS/` 只保留 `ARM_CM3/` 6. 复制 `include/` 到 `FreeRTOS/` 下 7. 从 `Demo/CORTEX_STM32F103_Keil/` 复制 `FreeRTOSConfig.h` 到 `Core/Inc/` ### Step 2: 工程添加源文件 1. 在 Keil 中创建两个 Group: - `FreeRTOS/Source` —— 添加 source/ 下的 7 个 .c 文件 - `FreeRTOS/Portable` —— 添加 `port.c` 和 `heap_4.c` 2. 添加头文件路径:`FreeRTOS/include/` 和 `FreeRTOS/portable/RVDS/ARM_CM3/` 3. `FreeRTOSConfig.h` 在 `Core/Inc/`(该路径通常已有) ### 步骤3:修改 FreeRTOSConfig.h 在 `FreeRTOSConfig.h` 中添加: ```c #define xPortPendSVHandler PendSV_Handler #define vPortSVCHandler SVC_Handler #define INCLUDE_xTaskGetSchedulerState 1 ``` ### 步骤4:修改 stm32f1xx_it.c 1. 添加头文件: ```c #include "FreeRTOS.h" #include "task.h" ``` 2. 注释掉默认的空中断: ```c // void SVC_Handler(void) { } // void PendSV_Handler(void) { } ``` 3. 添加 SysTick 中断服务函数: ```c /* USER CODE BEGIN PV */ extern void xPortSysTickHandler(void); /* USER CODE END PV */ void SysTick_Handler(void) { /* USER CODE BEGIN SysTick_IRQn 0 */ /* USER CODE END SysTick_IRQn 0 */ /* USER CODE BEGIN SysTick_IRQn 1 */ if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { xPortSysTickHandler(); } /* USER CODE END SysTick_IRQn 1 */ } ``` ### 步骤5:解决 HAL + SysTick 冲突 HAL 库默认使用 SysTick 作为时基。FreeRTOS 也依赖 SysTick 作为系统滴答。 **解决方案**:在 STM32CubeMX 的 SYS 配置中,将 Timebase Source 改为其他定时器(如 TIM6),并将中断优先级设为较高(如 1)。 ## 寄存器版移植步骤 与 HAL 库移植的前两步相同(目录添加 + 工程添加源文件)。 不同之处在于系统配置修改: 1. 同样在 `FreeRTOSConfig.h` 添加三个配置 2. 在 `main.c` 中添加 SysTick_Handler: ```c extern void xPortSysTickHandler(void); void SysTick_Handler(void) { if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { xPortSysTickHandler(); } } ``` ## 核心函数速查表 | 函数 | 参数 | 返回值 | 功能简述 | | -------------------------- | ---- | ---------- | --------------------------------------------------- | | `vTaskStartScheduler()` | void | void | 启动调度器 | | `xTaskGetSchedulerState()` | void | BaseType_t | 获取调度器状态(NOT_STARTED / RUNNING / SUSPENDED) | | `xPortSysTickHandler()` | void | void | 滴答中断处理函数(在 SysTick_Handler 中调用) | ## 常见问题与避坑 - **PendSV_Handler 被注释掉了吗?**:FreeRTOS 接管了 PendSV_Handler,必须在 `stm32f1xx_it.c` 中注释掉原有的空函数,否则链接时冲突。 - **SysTick 冲突卡死**:HAL 与 FreeRTOS 都默认使用 SysTick。启动调度器后,HAL 的 HAL_Delay 会失效甚至卡死。记得将 HAL 时基换到其他定时器。 - **变量报 undefined**:如果编译报变量未定义,检查 `FreeRTOSConfig.h` 开头是否包含了系统头文件(如 `stm32f1xx_hal.h`)并定义了 `SystemCoreClock`。 - **内存不足**:`configTOTAL_HEAP_SIZE` 默认可能太大。STM32F103 系列通常设为 10\*1024(10KB)即可。