背景
将 FreeRTOS v9.0.0 移植到你现有的 STM32F103C8T6 Keil/EIDE 工程中。你的工程使用 AC5 (ARMCC) 编译器,Cortex-M3 内核。
移植 FreeRTOS 主要分为 4 个步骤:
- 拷贝源文件到工程目录
- 创建 FreeRTOSConfig.h 配置文件
- 修改中断处理函数(解决冲突)
- 在 EIDE/Keil 中添加文件和头文件路径
步骤一:拷贝 FreeRTOS 源文件
在工程根目录下创建 FreeRTOS 文件夹,把以下文件拷贝进去:
1.1 内核源文件(必须)
从 FreeRTOSv9.0.0/FreeRTOS/Source/ 拷贝以下 5 个 .c 文件 到 FreeRTOS/src/:
| 文件名 | 作用 |
|---|---|
tasks.c | 任务管理(核心) |
queue.c | 队列(消息队列/信号量基础) |
list.c | 链表(内核数据结构) |
timers.c | 软件定时器 |
event_groups.c | 事件标志组 |
1.2 头文件(必须)
从 FreeRTOSv9.0.0/FreeRTOS/Source/include/ 拷贝 所有头文件 到 FreeRTOS/include/
1.3 移植层文件(必须)
你用的是 ARMCC (AC5) 编译器 + Cortex-M3,所以需要从 FreeRTOSv9.0.0/FreeRTOS/Source/portable/RVDS/ARM_CM3/ 拷贝以下 2 个文件到 FreeRTOS/portable/RVDS/ARM_CM3/:
| 文件名 | 作用 |
|---|---|
port.c | Cortex-M3 的上下文切换、SysTick 配置等 |
portmacro.h | 移植层的宏定义 |
[!NOTE]
RVDS 和 Keil (ARMCC/AC5) 使用相同的 port 文件,所以用RVDS/ARM_CM3目录下的文件即可。
1.4 内存管理文件(必须,选一个)
从 FreeRTOSv9.0.0/FreeRTOS/Source/portable/MemMang/ 拷贝 一个 heap 文件到 FreeRTOS/portable/MemMang/:
| 文件名 | 特点 | 推荐场景 |
|---|---|---|
heap_1.c | 只能分配不能释放 | 任务数固定,永不删除 |
heap_2.c | 可分配可释放,不合并碎片 | 简单场景 |
heap_3.c | 直接封装 malloc/free | 需要标准库支持 |
heap_4.c | 可分配可释放,自动合并碎片 | ⭐ 推荐,最常用 |
heap_5.c | 支持多个不连续内存区域 | 有外部 SRAM 时使用 |
[!IMPORTANT]
推荐使用heap_4.c,它是最通用的选择,支持动态创建和删除任务。
最终目录结构
rtos学习/
├── CORE/
├── FWLIB/
├── HARDWARE/
├── USER/
│ ├── main.c
│ ├── FreeRTOSConfig.h ← 新增
│ ├── stm32f10x_it.c ← 需修改
│ └── ...
└── FreeRTOS/ ← 新增整个目录
├── src/
│ ├── tasks.c
│ ├── queue.c
│ ├── list.c
│ ├── timers.c
│ └── event_groups.c
├── include/
│ ├── FreeRTOS.h
│ ├── task.h
│ ├── queue.h
│ └── ... (所有头文件)
└── portable/
├── RVDS/ARM_CM3/
│ ├── port.c
│ └── portmacro.h
└── MemMang/
└── heap_4.c
步骤二:创建 FreeRTOSConfig.h
在 USER/ 目录下创建 FreeRTOSConfig.h,这是 FreeRTOS 的核心配置文件。
[!IMPORTANT]
关键配置说明(针对 STM32F103C8T6 的 20KB RAM):
configTOTAL_HEAP_SIZE设为10 * 1024(10KB),因为 C8T6 只有 20KB RAM,留一半给栈和全局变量configCPU_CLOCK_HZ设为 72000000(72MHz),这是 F103 的标准主频configMINIMAL_STACK_SIZE设为 128 字(512 字节),每个任务最少的栈空间#ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H /*----------------------------------------------------------- * FreeRTOS 配置文件 - STM32F103C8T6 (72MHz, 20KB RAM, 64KB Flash) *----------------------------------------------------------*/ /* 基本配置 */ #define configUSE_PREEMPTION 1 /* 1: 抢占式调度, 0: 合作式调度 */ #define configUSE_IDLE_HOOK 0 /* 空闲任务钩子函数 */ #define configUSE_TICK_HOOK 0 /* 时钟节拍钩子函数 */ #define configCPU_CLOCK_HZ ((unsigned long)72000000) /* CPU 主频 72MHz */ #define configTICK_RATE_HZ ((TickType_t)1000) /* 系统节拍频率 1000Hz = 1ms */ #define configMAX_PRIORITIES (5) /* 最大优先级数量 */ #define configMINIMAL_STACK_SIZE ((unsigned short)128) /* 空闲任务栈大小(单位:字, 即 512 字节) */ #define configTOTAL_HEAP_SIZE ((size_t)(10 * 1024)) /* FreeRTOS 堆大小 10KB (C8T6 总共 20KB RAM) */ #define configMAX_TASK_NAME_LEN (16) /* 任务名最大长度 */ #define configUSE_TRACE_FACILITY 0 /* 跟踪功能 */ #define configUSE_16_BIT_TICKS 0 /* 0: 32位tick计数器, 1: 16位 */ #define configIDLE_SHOULD_YIELD 1 /* 空闲任务是否让出 CPU */ /* 软件定时器 */ #define configUSE_TIMERS 0 /* 0: 不使用软件定时器 */ #define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) #define configTIMER_QUEUE_LENGTH 5 #define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) /* 协程 (一般不用) */ #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES (2) /* 可选 API 函数开关: 1=包含, 0=排除 */ #define INCLUDE_vTaskPrioritySet 1 #define INCLUDE_uxTaskPriorityGet 1 #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskCleanUpResources 0 #define INCLUDE_vTaskSuspend 1 #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1 /*----------------------------------------------------------- * Cortex-M3 中断优先级配置 * * STM32 使用 4 位优先级 (0~15), NVIC 中左移 4 位变成 0x00~0xF0 * FreeRTOS 使用的是 NVIC 原始值 (0~255) *----------------------------------------------------------*/ /* 内核中断优先级 (最低优先级) */ #define configKERNEL_INTERRUPT_PRIORITY 255 /* 可管理的最高中断优先级 * 优先级数值 >= 此值的中断可以调用 FreeRTOS API (FromISR 系列) * 优先级数值 < 此值的中断不受 FreeRTOS 管理, 响应更快但不能调用 FreeRTOS API * 191 = 0xBF, 对应优先级 11 (4位有效位时) */ #define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* 用于 ST 标准库中断优先级设置时的参考值 (0~15) */ #define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15 /*----------------------------------------------------------- * 将 FreeRTOS 的中断处理函数映射到 STM32 的中断向量名 * 这样 port.c 中定义的函数能正确对应到中断向量表 *----------------------------------------------------------*/ #define vPortSVCHandler SVC_Handler #define xPortPendSVHandler PendSV_Handler #define xPortSysTickHandler SysTick_Handler #endif /* FREERTOS_CONFIG_H */
步骤三:修改 stm32f10x_it.c(解决中断冲突)
[!CAUTION]
这是最关键的一步! FreeRTOS 的port.c中已经定义了SVC_Handler、PendSV_Handler、SysTick_Handler这三个中断处理函数。如果stm32f10x_it.c中也有这三个函数,编译时会报 重复定义错误。
需要做的修改:
- 注释掉
stm32f10x_it.c中的SVC_Handler() - 注释掉
stm32f10x_it.c中的PendSV_Handler() - 注释掉
stm32f10x_it.c中的SysTick_Handler()(或改为在 FreeRTOSConfig.h 中用 hook 回调)
对于你的 SysTick_Handler 中的 g_SystemTick++,可以通过 FreeRTOS 的 Tick Hook 机制来保留这个功能(在 config 中设置 configUSE_TICK_HOOK 为 1,然后实现 vApplicationTickHook() 函数)。
步骤四:修改 EIDE 工程配置
需要在 eide.yml 中:
4.1 添加头文件包含路径
在 incList 中添加:
FreeRTOS/includeFreeRTOS/portable/RVDS/ARM_CM3
4.2 添加源文件到虚拟文件夹
在 virtualFolder 中新增 FreeRTOS 分组,包含所有 .c 文件。
步骤五:修改 main.c 添加测试任务
修改 main.c 来创建 FreeRTOS 任务,用两个 LED 闪烁任务来验证移植是否成功。



