(一)FreeRTOS源码的下载
1. FreeRTOS官网下载
FreeRTOS官网:https://www.freertos.org/,但在官网只能下载最新V202406.04版,我们教程用的是经典且更稳定的V9.0.0版
https://www.freertos.org/
https://www.freertos.org/
2. 代码托管网站下载
2.1直接跳转到网站:https://sourceforge.net/projects/freertos/files/FreeRTOS/
https://sourceforge.net/projects/freertos/files/FreeRTOS/
https://sourceforge.net/projects/freertos/files/FreeRTOS/2.2 然后完成真人验证往下滑,找到V9.0.0版本点击

2.3 点击FreeRTOSv9.0.0.zip,自动即可开始下载,因是国外的网站下载过程较慢,耐心等待一下

(二) FreeRTOS系统移植
1.创建stm32裸机项目工程
1.1任意写一个stm32标准库程序,我这里使用的是最基础的stmf103c8t6的驱动LED闪烁程序

1.2在文件夹根目录下创建一个名为FreeRTOS的文件夹,用来存放FreeRTOS的移植文件

1.3在刚创建的FreeRTOS文件夹中,分别创建include,port,src文件夹,
- include文件夹用来存放头文件
- port文件夹用来存放移植平台的相关文件
- src文件夹用来存放源码

2.解压移植FreeRTOS文件
2.1解压第一步下载的FreeRTOSv9.0.0,

2.2打开FreeRTOS——Source,复制里面的所有文件,粘贴到第一步创建的FreeRTOS文件夹中

点击替换目标中的文件


2.3把这7个.c文件全移动到src文件夹中
2.4打开portable选中MemMang与RVDS复制粘贴到第一步创建的port中,然后删掉portable即可
2.5打开port——MemMang,删除处heap_4.c外的所有文件
2.6去FreeRTOS——Demo——CORTEX_STM32F103_Keil文件夹,复制里面的FreerRTOSConfig.h文件到新建的stm32程序的User文件夹中,至此FreeRTOS文件移植完成

3.添加头文件和微调文件内容
3.1 接着开始添加头文件路径,打开keil软件点击魔术棒,进入C/C++,在Include Paths中添加文件路径,将.\\FreeRTOS\\port\\RVDS\\ARM_CM3、.\\FreeRTOS\\include的路径添加进来
3.2将上面创建的文件夹添加到项目工程中,点击魔术棒旁边的三个格子的图标,选择新建组,我们分别新建FreeRTOS\\src、FreeRTOS_port三个组,将工程文件夹src中的所有.c文件添加到FreeRTOS_src中,将工程文件夹inc中的所有.h文件添加到FreeRTOS_inc中(不包括.readme),将工程文件夹port\\RVDS\\ARM_CM3中的文件port.c、portmacro.h与port\\MemMang中的heap_4.c添加到FreeRTOS\\port中 

3.3打开项目工程User文件夹中的stm32f10x_it.c,文件夹注释掉STM库函数中的void SVC_Handler(void); void PendSV_Handler(void); void SysTick_Handler(void);这三个中断空函数
void SVC_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);

3.4 完成中断函数的宏定义,打开上面步骤中移植的FreeRTOSConfig.h中,在条件编译中加入以下三条宏定义:
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
#define xPortSysTickHandler SysTick_Handler

到这里,FreeRTOS系统移植已经全部完成,可以编译一下,无错误,无警告
(三) FreeRTOS系统运行验证
1.对我们移植后的LED闪烁项目工程.main函数进行简单修改,使其调用移植的FreeRTOS任务调度函数运行程序,(这里需要注意如果裸机工程的Delay函数使用的是SysTick系统滴答定时器,移植FreeRTOS系统之后需要删除掉裸机的Delay函数或者替换成time定时器,因为FreeRTOS 底层依赖的是 SysTick 定时器实现 tick 计数驱动vTaskDelay和任务调度)
#include "FreeRTOS.h" // Device header #include "task.h" #include "LED.h" #include "stm32f10x.h"
//任务优先级 #define START_TASK_PRIO 1 //任务堆栈大小 #define START_STK_SIZE 128 //任务句柄 TaskHandle_t StartTask_Handler; //任务函数 void start_task(void *pvParameters);
//任务优先级 #define LED0_TASK_PRIO 2 //任务堆栈大小 #define LED0_STK_SIZE 50 //任务句柄 TaskHandle_t LED0Task_Handler; //任务函数 void led0_task(void *pvParameters);
//任务优先级 #define LED1_TASK_PRIO 3 //任务堆栈大小 #define LED1_STK_SIZE 50 //任务句柄 TaskHandle_t LED1Task_Handler; //任务函数 void led1_task(void *pvParameters);
int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4 LED_Init(); //初始化LED //创建开始任务 xTaskCreate((TaskFunction_t )start_task, //任务函数 (const char* )"start_task", //任务名称 (uint16_t )START_STK_SIZE, //任务堆栈大小 (void* )NULL, //传递给任务函数的参数 (UBaseType_t )START_TASK_PRIO, //任务优先级 (TaskHandle_t* )&StartTask_Handler); //任务句柄 vTaskStartScheduler(); //开启任务调度 }
//开始任务任务函数 void start_task(void *pvParameters) { taskENTER_CRITICAL(); //进入临界区 //创建LED0任务 xTaskCreate((TaskFunction_t )led0_task, (const char* )"led0_task", (uint16_t )LED0_STK_SIZE, (void* )NULL, (UBaseType_t )LED0_TASK_PRIO, (TaskHandle_t* )&LED0Task_Handler); //创建LED1任务 xTaskCreate((TaskFunction_t )led1_task, (const char* )"led1_task", (uint16_t )LED1_STK_SIZE, (void* )NULL, (UBaseType_t )LED1_TASK_PRIO, (TaskHandle_t* )&LED1Task_Handler); vTaskDelete(StartTask_Handler); //删除开始任务 taskEXIT_CRITICAL(); //退出临界区 }
//LED0任务函数 void led0_task(void *pvParameters) { while(1) { LED1_Turn(); vTaskDelay(500); } }
//LED1任务函数 void led1_task(void *pvParameters) { while(1) { LED2_ON(); vTaskDelay(800); LED2_OFF(); vTaskDelay(800); } }
2.编译无报错烧录到stm32f103c8t6中查看现象,LED1 和LED2分别以以 500ms 和800 ms为周期交替闪缩
3.项目工程文件 链接: https://pan.baidu.com/s/1CETJBsbNktXku6lo-PeXFA?pwd=1314
提取码: 1314



