资料链接:https://pan.baidu.com/s/16N2-sdZ-sow4fnRoNrLCyw 提取码:mprb 可以直接使用资料内的FreeRTOS移植模板工程,可以跳过下面的步骤。
视频链接:【FreeRTOS实时操作系统--基于STM32】 网页链接
1、创建一个工程,创建完毕后在工程文件内新建一个文件夹,可命名为FreeRTOS。

2、打开 FreeRTOS文件位置\FreeRTOS\Source 文件夹,复制里面所有的文件到工程文件的FreeRTOS的文件夹当中。

3、在上一步骤复制进来的文件当中,打开portable文件夹,里面包含了所有嵌入式开发平台的所需配置文件,根据需要留下所需文件即可,其余删掉。
使用keil编辑,留下Keil、MemMang、RVDS这三个文件即可,readme是注意事项,可删可不删。

4、打开工程,新建两个分组,分别命名为FreeRTOS_CORE和FreeRTOS_PORTABLE,用来导入FreeRTOS的内核源文件和内存管理文件等。

5、导入内核源文件到FreeRTOS_CORE分组当中。

选择FreeRTOS文件夹内的c类型文件,添加。

添加成功。

6、添加内存管理方法及ARM文件到FreeRTOS_PORTABLE分组当中。

添加内存管理方法。
打开 \FreeRTOS\portable\MemMang 文件夹,里面包含有5种内存管理方法文件,任选一个添加即可。

添加ARM文件。
打开 \FreeRTOS\portable\RVDS 文件夹,里面包含多个ARM内核的文件,根据使用的板子的内核即可,使用STM32F103系列的芯片,内核为Core-M3,所以选择ARM_CM3文件夹内的文件,点击添加。

添加成功。

7、添加头文件路径。
一共需要添加两处头文件路径,也就是上一步骤当中导入的.c文件对应的.h文件位置。

首先在FreeRTOS内选择include文件夹,点击确定,添加进去。

继续添加,选择\FreeRTOS\portable\RVDS\ARM_CM3 文件夹,添加进去。

添加成功,点击OK确定更改。

8、添加FreeRTOSConfig.h配置文件
在freeRTOS源码中的“FreeRTOS\Demo”文件夹下面找到“CORTEX_STM32F103_Keil”这个文件夹,双击打开,在其根目录下找到这个“FreeRTOSConfig.h”文件,将其复制到工程的USER文件夹当中。
也可以使用其他模板工程当中的FreeRTOSConfig.h配置文件,不同工程内的FreeRTOSConfig.h可能是有差别的,可能需要根据报错进行修改。

9、点击编译,到这一步可能会出现错误。
在编译的时候出现Error: L6218E: Undefined symbol xTaskGetCurrentTaskHandle (referred from stream_buffer.o)
解决方法:打开FreeRTOS.h文件,按Ctrl+F搜索xTaskGetCurrentTaskHandle,将里面的文件0改为1

编译时出现 error: #268: declaration may not appear after executable statement in block QueueRegistryItem_t * pxEntryToWrite = NULL;
变量的声明必须在函数可执行语句的前面。
解决方法:双击错误跳转到错误语句,将 QueueRegistryItem_t * pxEntryToWrite = NULL;语句向上移动。

编译时出现Error: L6200E: Symbol PendSV_Handler multiply defined (by port.o and stm32f10x_it.o).
和Error: L6200E: Symbol SVC_Handler multiply defined (by port.o and stm32f10x_it.o).
在port.h 和stm32f10x_it.h这两个文件当中有定义冲突,(port.o 和stm32f10x_it.o为port.h 和stm32f10x_it.h当编译后的文件)。
解决方法:打开stm32f10x_it.h,找到PendSV_Handler 函数和SVC_Handler 函数注释掉,因为stm32f10x_it.h内的这两个函数没有可执行语句,所有优先使用port.h的函数。

10、更改stm32f10x_it.h内的滴答定时器中断函数,在滴答定时器的中断函数内运行FreeRTOS系统的系统定时器中断函数。
首先在#include "stm32f10x_it.h"下方添加
#include "FreeRTOS.h"
#include "task.h" 分别引入FreeRTOS.h和task.h这两个头文件。
在130行之后找到void SysTick_Handler(void)这个函数,此时该函数的函数体内是空白的,将该函数改为:
extern void xPortSysTickHandler(void); //声明一下函数在别的地方有定义 void SysTick_Handler(void) { if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED){ //判断FreeRTOS系统是否正常运行 xPortSysTickHandler(); //执行FreeRTOS系统的系统时钟中断函数 } }
使其在滴答定时器进入中断时同时运行FreeRTOS的系统定时器中断函数。
点击编译,此时应该是0错误。
11、修改SysTick.c和SysTick.h的内容
为了使STM32的滴答定时器能够兼容FreeRTOS的系统时钟,需要对SysTick.c和SysTick.h的内容进行修改。
一步步修改较为麻烦,建议直接全选文件内容进行替换。
修改后的SysTick.c为:
#include "SysTick.h"
#include "FreeRTOS.h" //FreeRTOS使用
#include "task.h"
static u8 fac_us=0; //us延时倍乘数
static u16 fac_ms=0; //ms延时倍乘数
//初始化延迟函数
//SYSTICK的时钟固定为AHB时钟,基础例程里面SYSTICK时钟频率为AHB/8
//SYSCLK:系统时钟频率
__weak void SysTick_Init(u8 SYSCLK)
{
u32 reload;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//选择外部时钟 HCLK
fac_us=SystemCoreClock/1000000; //不论是否使用OS,fac_us都需要使用
reload=SystemCoreClock/1000000; //每秒钟的计数次数 单位为M
reload*=1000000/configTICK_RATE_HZ; //根据configTICK_RATE_HZ设定溢出时间
//reload为24位寄存器,最大值:16777216,在72M下,约合0.233s左右
fac_ms=1000/configTICK_RATE_HZ; //代表OS可以延时的最少单位
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断
SysTick->LOAD=reload; //每1/configTICK_RATE_HZ秒中断一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
}
//延时nus
//nus:要延时的us数.
//nus:0~204522252(最大值即2^32/fac_us@fac_us=168)
__weak void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD; //LOAD的值
ticks=nus*fac_us; //需要的节拍数
told=SysTick->VAL; //刚进入时的计数器值
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{
if(tnow<told)tcnt+=told-tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了.
else tcnt+=reload-tnow+told;
told=tnow;
if(tcnt>=ticks)break; //时间超过/等于要延迟的时间,则退出.
}
};
}
//延时nms
//nms:要延时的ms数
//nms:0~65535
__weak void delay_ms(u32 nms)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
{
if(nms>=fac_ms) //延时的时间大于OS的最少时间周期
{
vTaskDelay(nms/fac_ms); //FreeRTOS延时
}
nms%=fac_ms; //OS已经无法提供这么小的延时了,采用普通方式延时
}
delay_us((u32)(nms*1000)); //普通方式延时
}
//延时nms,不会引起任务调度
//nms:要延时的ms数
__weak void delay_xms(u32 nms)
{
u32 i;
for(i=0;i<nms;i++) delay_us(1000);
}
修改后的SysTick.h为:
#ifndef _SysTick_H
#define _SysTick_H
#include "system.h"
void SysTick_Init(u8 SYSCLK);
void delay_ms(u32 nms);
void delay_us(u32 nus);
void delay_xms(u32 nms);
#endif