STM32移植Freertos
1、FreeRTOS™ - FreeRTOS™官网下载源码
解压后
FreeRTOSv202406.04-LTS\FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel
仅保留FreeRTOS-Kernel文件夹下文件
仅保留选中文件

工程中添加Freertos组

添加头文件路径

FreeRTOSv202406.04-LTS\FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel\includeFreeRTOSv202406.04-LTS\FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel\include
将.c文件添加进工程文件夹中

根据所移植目标芯片选择内核文件(stm32f103,选择ARM_CM3),将文件夹内文件添加至工程

将FreeRTOSv202406.04-LTS\FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel\examples\template_configuration
FreeRTOSConfig.h文件添加至工程

根据所需功能,开启宏定义
打开stm32f10x_it.c/.h文件,注释三个中断函数(确保不会重定义,同时让freertos接管中断)


| 函数 | 用途 |
|---|---|
SVC_Handler |
Supervisor Call(软件中断)处理,用于操作系统调用或异常 |
PendSV_Handler |
挂起中断,用于任务切换(Context Switch) |
SysTick_Handler |
系统滴答定时器中断,通常用于系统节拍计数 |
2️⃣ FreeRTOS 对这些函数的要求
FreeRTOS 核心任务调度依赖 SysTick、PendSV、SVC:
- SysTick_Handler
- FreeRTOS 使用它作为 节拍中断(tick)
- 用于管理任务延时、任务切换计时等
- PendSV_Handler
- FreeRTOS 用它实现 任务切换
- 在 PendSV 中切换任务上下文(寄存器、栈指针)
- SVC_Handler
- FreeRTOS 可能用它初始化第一个任务(
vPortSVCHandler)
- FreeRTOS 可能用它初始化第一个任务(
如果 startup 文件里有原始弱符号的这几个函数,它们可能与 FreeRTOS 自己实现的 vPortXXX_Handler 冲突。
-
不要删除这些函数,只是注释掉或确保 FreeRTOS 的实现覆盖它们
-
如果你不移植 FreeRTOS,用系统默认空实现即可
-
FreeRTOS 的
port.c里有宏:#define vPortSVCHandler SVC_Handler #define xPortPendSVHandler PendSV_Handler #define xPortSysTickHandler SysTick_Handler链接器会把中断向量表自动指向 FreeRTOS 的处理函数
总结一句话:
注释这三个默认函数,是为了让 FreeRTOS 自己实现的 SVC/PendSV/SysTick 处理函数覆盖系统默认空函数,从而实现正确的任务调度和系统节拍。
测试代码
c
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "queue.h"
#include "stream_buffer.h"
#include "semphr.h"
//创建队列句柄
QueueHandle_t Queue_Data_Handle;
#define queue_data_length 10
//宏定义 send_task
BaseType_t retA;
TaskHandle_t Pt_send_Task_TaskHandle;
void queue_sned_Task(void *p);
#define Sned_Task_Name "queue_send"
#define Sned_Task_StackD 128
#define Sned_Task_Priority 1
//宏定义 rece_task
BaseType_t retB;
TaskHandle_t Pt_rece_Task_TaskHandle;
void queue_receive_Task(void *p);
#define Rece_Task_Name "queue_rece"
#define Rece_Task_StackD 128
#define Rece_Task_Priority 1
u8 i,j;
void queue_send_Task(void *p)
{
uint32_t send_value = 0;
while(1)
{ i++;
vTaskDelay(1000);
}
}
void queue_receive_Task(void *p)
{
uint32_t rece_value = 0;
while(1)
{
j++;
vTaskDelay(1000);
}
}
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
// Debug_Init(115200);
/*创建队列 注意队列长度 和 数据字节大小*/
Queue_Data_Handle = xQueueCreate(queue_data_length, //队列长度
sizeof(uint32_t)); //单个数据大小四字节
/*创建发送任务*/
retA = xTaskCreate( (TaskFunction_t) queue_send_Task,
(const char *)Sned_Task_Name,
(uint16_t)Sned_Task_StackD,
(void *)NULL,
(UBaseType_t)Sned_Task_Priority,
(TaskHandle_t *)&Pt_send_Task_TaskHandle);
/*创建接收任务*/
retA = xTaskCreate( (TaskFunction_t) queue_receive_Task,
(const char *)Rece_Task_Name,
(uint16_t)Rece_Task_StackD,
(void *)NULL,
(UBaseType_t)Rece_Task_Priority,
(TaskHandle_t *)&Pt_rece_Task_TaskHandle);
/*开始调度*/
vTaskStartScheduler();
/*不会执行到这里*/
while (1) {
;
}
}
将断点打在

进入Debuge,全速运行,看是否两个断点都能进入,编译无报错,能进入,则移植成功