裸机项目添加FreeRTOS操作系统--常见报错
常见报错一
这些报错是 FreeRTOS 移植不完整导致的链接错误,本质是工程里缺少 FreeRTOS 内核中与 “端口(port)” 相关的实现代码,导致链接器找不到 vPortEnterCritical
、xPortStartScheduler
等函数的定义。工程里只加了 FreeRTOS 通用内核代码(tasks.c
、queue.c
等),但没添加对应 Cortex - M 内核和 Keil 编译器的端口层文件 。
解决方法:
找到 FreeRTOS 源码中的 portable
目录,进入 RVDS
(或 Keil
,不同版本可能命名不同)→ ARM_CM3
(或对应内核,如 ARM_CM4
)。将目录里的 port.c
和 portmacro.h
文件,添加到工程中(一般放到 FreeRTOS/portable/Keil/ARM_CM3
分组)。
常见报错二
这是多重定义错误(Multiple Definition Error)
SVC_Handler
和 PendSV_Handler
这两个符号(中断服务函数),在工程中被重复定义了。从报错信息看,port.c
(FreeRTOS 端口层文件,负责上下文切换等内核关键逻辑 )和 stm32f10x_it.c
(STM32 标准中断文件,用户 / 库默认的中断服务函数实现 )里,都定义了这两个中断处理函数,导致链接器冲突。
关键背景知识
SVC_Handler
:即系统调用中断(Supervisor Call),FreeRTOS 用于任务切换、系统调用等内核操作,需要由端口层(port.c
)实现特定逻辑。PendSV_Handler
:可挂起的系统调用中断,FreeRTOS 依赖它实现任务上下文切换(抢占式调度核心 ),同样由端口层提供实现。stm32f10x_it.c
:STM32 标准外设库 / HAL 库的中断服务函数集中文件,默认会 “占位” 定义这些中断函数(通常是空实现或弱符号__weak
)。
解决方法:
法 1:保留 FreeRTOS 端口层的定义(推荐)
FreeRTOS的port.c
里,SVC_Handler
和PendSV_Handler
是内核正常运行必需的、包含上下文切换逻辑的实现。因此,需要让 STM32 标准中断文件里的默认定义 “失效”。
步骤:
①打开stm32f10x_it.c
(或 stm32f1xx_it.c
等中断文件 )
②找到以下代码(默认可能是空函数或弱定义):
void SVC_Handler(void)
{
}void PendSV_Handler(void)
{
}
③注释或删除这两个函数的定义,让 FreeRTOS 端口层(port.c
)里的实现 “生效”。
法 2:利用弱符号(__weak
)兼容(如果库支持)
部分 STM32 库(如 HAL 库)会用 __weak
修饰默认中断函数,允许用户代码 “覆盖” 定义。
检查 stm32f10x_it.c
里的函数是否带 __weak
:
__weak void SVC_Handler(void)
{// 空实现
}__weak void PendSV_Handler(void)
{// 空实现
}
如果带 __weak
,则FreeRTOS 端口层(port.c
)里的非 __weak
定义会自动覆盖默认实现,理论上无需修改。但如果实际仍报错,说明库版本未用 __weak
,需走方案 1。
常见报错三
这个报错是多重定义错误(Multiple Definition Error),具体原因是 SysTick_Handler
这个符号(即 SysTick 定时器的中断服务函数)在工程中被重复定义了。从报错信息看到,stm32f10x_it.c
(STM32 标准中断处理文件编译后的目标文件 )和 delay.c
(delay.c
编译后的目标文件 )里,都定义了 SysTick_Handler
函数,导致链接器不知道该用哪个,从而报错。
解决方法:
法1:保留一处定义,删除另一处
确定需求:如果用 FreeRTOS,通常 FreeRTOS 会依赖 SysTick_Handler
做系统节拍,或你的delay.c
有特殊逻辑,需明确保留哪一个。
删除重复定义:
若 delay.c
里的 SysTick_Handler
是自定义且不需要,直接删除 delay.c
里的该函数。
若 stm32f10x_it.c
里的是默认空函数,删除 stm32f10x_it.c
里的 SysTick_Handler
定义,保留 delay.c
里的实现(或反之,根据实际需求 )。
法2:也是利用 __weak
关键字(如果库支持)
部分 STM32 库(如 HAL 库)会用 __weak
修饰默认中断函数,允许用户代码 “覆盖” 定义。检查 stm32f10x_it.c
里的 SysTick_Handler
:
__weak void SysTick_Handler(void)
{// 空实现或默认逻辑
}
如果带 __weak,
则你在 delay.c
里的非 __weak
定义会自动覆盖默认实现,理论上无需修改。但如果实际仍报错,说明库版本未用 __weak
,需走方案 1 。