STM32移植Freertos

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

  1. SysTick_Handler
    • FreeRTOS 使用它作为 节拍中断(tick)
    • 用于管理任务延时、任务切换计时等
  2. PendSV_Handler
    • FreeRTOS 用它实现 任务切换
    • 在 PendSV 中切换任务上下文(寄存器、栈指针)
  3. SVC_Handler
    • FreeRTOS 可能用它初始化第一个任务(vPortSVCHandler

如果 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,全速运行,看是否两个断点都能进入,编译无报错,能进入,则移植成功