FreeRTOS 移植完整笔记
一、前置准备FreeRTOS 源码获取与结构1. 下载源码官网https://www.freertos.org/GitHubhttps://github.com/FreeRTOS/FreeRTOS/releasesFreeRTOS/Source/ # 内核核心必须用include/ # 通用头文件7个.c文件 # tasks.c/queue.c等portable/ # 移植关键文件RVDS/ARM_CM3/ # M3内核接口必须MemMang/heap_4.c # 内存管理必须Demo/ # 找 FreeRTOSConfig.h 配置文件移植只需要 3 部分Source 下 7 个通用 .c 文件portable/RVDS/ARM_CM3portable/MemMang/heap_4.c工程根目录新建文件夹FreeRTOS/ ├─ source/ ├─ portable/ └─ include/拷贝文件源码 Source/*.c → 工程 FreeRTOS/source/源码 Source/include/ → 工程 FreeRTOS/include/源码 Source/portable/RVDS/ARM_CM3 → 工程 FreeRTOS/portable/源码 Source/portable/MemMang/heap_4.c → 工程 FreeRTOS/portable/MemMang/拷贝配置文件从源码 Demo/CORTEX_STM32F103_Keil/ 复制 FreeRTOSConfig.hHAL 项目放到 Core/Inc寄存器项目放到 USER/Inc 或自定义头文件路径修改 FreeRTOSConfig.h添加 3 行直接加在文件末尾即可#define xPortPendSVHandler PendSV_Handler#define vPortSVCHandler SVC_Handler#define INCLUDE_xTaskGetSchedulerState 1修改 stm32f1xx_it.c#include FreeRTOS.h#include task.h注释掉系统默认的两个中断函数非常重要// void SVC_Handler(void){} // void PendSV_Handler(void){}修改SysTick_Handlerextern void xPortSysTickHandler(void); void SysTick_Handler(void) { if(xTaskGetSchedulerState() ! taskSCHEDULER_NOT_STARTED) { xPortSysTickHandler(); } }HAL 时钟源修改CubeMX / 代码中SysTick 给 FreeRTOS 使用HAL 库时钟源切换为TIM1或TIM2中断优先级设置高一点如 1防止系统卡死寄存器项目移植MDK 添加文件 头文件路径和 HAL 库完全一致修改 FreeRTOSConfig.h和 HAL 库一#define xPortPendSVHandler PendSV_Handler #define vPortSVCHandler SVC_Handler #define INCLUDE_xTaskGetSchedulerState 13. main.c 实现 SysTick 中断extern void xPortSysTickHandler(void); void SysTick_Handler(void) { if(xTaskGetSchedulerState() ! taskSCHEDULER_NOT_STARTED) { xPortSysTickHandler(); } }寄存器项目无需注释 SVC/PendSV因为 FreeRTOS 已经接管了这两个中断。1.为什么要在 FreeRTOSConfig.h 里加这两句#define xPortPendSVHandler PendSV_Handler #define vPortSVCHandler SVC_Handler原因FreeRTOS 自己实现了任务切换必须用的两个中断函数xPortPendSVHandlervPortSVCHandler但是STM32 官方启动文件startup_stm32f10x.s里写死的中断名是PendSV_HandlerSVC_Handler2. 为什么要注释掉 stm32f1xx_it.c 里的 SVC_Handler 和 PendSV_Handler//void SVC_Handler(void){} //void PendSV_Handler(void){}原因这两个函数HAL 库默认给你生成了空实现如果不注释编译器会发现FreeRTOS 写了一个PendSV_Handler我自己的文件里也写了一个PendSV_Handler结果重复定义报错 → 编译失败总结FreeRTOS 要用这两个中断你就必须把 HAL 生成的空函数删掉 / 注释掉3. 为什么要修改 SysTick_Handlerextern void xPortSysTickHandler(void); void SysTick_Handler(void) { if(xTaskGetSchedulerState() ! taskSCHEDULER_NOT_STARTED) { xPortSysTickHandler(); } }原因SysTick 是 FreeRTOS 的系统心跳RTOS 要做任务延时时间片轮转超时等待软件定时器全都靠 SysTick 提供时基所以每次滴答定时器中断我必须调用 FreeRTOS 提供的xPortSysTickHandler()告诉 RTOS时间又过去 1ms 啦4. 为什么 HAL 项目必须把时钟源从 SysTick 改成 TIM 定时器原因HAL 库和 FreeRTOS 抢同一个 SysTickHAL 用它做HAL_Delay()FreeRTOS 用它做任务调度两个同时用 →冲突 → 系统直接卡死 / 死机解决方法让一个人用另一个人换工具FreeRTOS 继续用 SysTick必须用HAL 改用 TIM1、TIM2 等普通定时器做时基这样就不打架了。5. 为什么寄存器项目不用注释 SVC/PendSV原因寄存器项目里根本没写这两个函数寄存器工程 你自己从零写代码没写SVC_Handler、PendSV_Handler所以 FreeRTOS 直接接管不会冲突HAL 工程 CubeMX 自动生成了空函数不注释就重复定义。总结SVC、PendSV 是 FreeRTOS 任务切换的核心必须让 FreeRTOS 接管。改名宏定义 让单片机认识 FreeRTOS 的中断函数。注释 HAL 空函数 防止重复定义。SysTick 给 FreeRTOSHAL 换 TIM 避免时钟冲突卡死。