在keil工程中新建FreeRTOS文件夹
将freertos源码文件里的sourse文件夹中的全部文件全部拷贝到第一步创建文件夹下
图中的protable文件夹下只留下以下三个文件夹
Keil和RVDS相当于一个文件夹,MemMang是内存管理相关,里面有五个heap.c文件
在移植时必须使用其中的一个,heap.c文件里是一些类似malloc,free函数的函数,freertos有自己的内存管理函数,它没有去使用c语言的库函数malloc,free等。因为FreeRTOS在创建对象的时候使用的是动态内存分配,而这些动态内存分配的函数则在这几个文件里面实现,不同的分配算法导致不同的效率和结果,一般用heap4.c
RVDS文件夹下是Cortex-M0、M3、M4、M7等内核的单片机接口文件,根据使用的单片机内核选择对应的文件,这里选择M3内核(其他的可以删除),M3文件夹下有两个文件分别是port.c接口文件,portmacro.h头文件,主要是一些数据类型和宏定义
用keil打开工程文件,点击所示图标新建两个分组FreeRTOS_CORE和FreeRTOS_PORTABLE然后向这两个分组中添加文件,如图添加相应的头文件路径,添加完FreeRTOS源码中的C文件以后还要添加FreeRTOS源码的头文件路径,头文件路径如图所示:
拷贝FreeRTOSConfig.h文件到User文件夹,FreeRTOSConfig.h是FreeRTOS的配置文件,他是freertos的核心,每个demo都必定含有FreeRTOSConfig.h
打开FreeRTOSv9.0.0源码,在“FreeRTOSv9.0.0\FreeRTOS\Demo”文件夹下面找到“CORTEX_STM32F103_Keil”这个文件夹,在其根目录下找到这个“FreeRTOSConfig.h”文件,然后拷贝到我们工程的User文件夹下即可
一般的操作系统都有裁剪、配置功能,而这些裁剪及配置都是通过一个文件来完成的,基本都是通过宏定义来完成对系统的配置和裁剪的。
该头文件对裁剪整个FreeRTOS所需的功能的宏均做了定义,里面的一堆宏主要分为两类,以config开头的宏多是与任务相关的参数、系统工作方式等相关,也有少部分与函数使能和除能相关,以INCLUDE为开头的宏几乎都是与函数使能失能相关的。一开始我们只需要配置最简单的功能即可。要想随心所欲的配置FreeRTOS的功能,必须对这些宏定义的功能有所掌握。
修改stm32f10x_it.c,注释掉SysTick_Handler函数,PendSV_Handler函数与SVC_Handler函数
FreeRTOS开发者已经帮我们实现了这三个中断函数,这三个函数非常很重要
修改sys.h文件,在sys.h文件里面用宏SYSTEM_SUPPORT_OS来定义是否使用OS,我们使用了FreeRTOS,所以应该将宏SYSTEM_SUPPORT_OS改为1。
修改usart.c文件,usart.c文件有两部分要修改,一个是添加FreeRTOS.h头文件,默认是添加的UCOS中的includes.h头文件,另外一个就是USART1的中断服务函数,在使用UCOS的时候进出中断的时候需要添加OSIntEnter()和OSIntExit(),使用FreeRTOS的话就不需要了,所以将这两行代码删除掉,修改以后如下
修改delay.c文件,delay.c文件里面有5个函数的定义,分别是
SysTick_Handler函数是滴答定时器的中断服务函数,FreeRTOS的心跳就是由滴答定时器产生的,它使用定时器产生固定间隔的中断,它的任务是1.选择下一个要运行的任务,2.执行完中断处理函数后,切换到新的任务。两次中断之间的时间被称为时间片,时间片的长度由一个宏configTICK_RATE_HZ决定,假设configTICK_RATE_HZ为100,那么时间片长度就是10ms,计算方法为1/100秒
delay_init()是用来初始化滴答定时器和延时函数。
delay_us()是us级延时函数,delay_ms和delay_xms()都是ms级的延时函数,delay_us()和delay_xms()不会导致任务切换。delay_ms()其实就是对FreeRTOS中的延时函数vTaskDelay()的简单封装,所以在使用delay_ms()的时候就会导致任务切换。
以上五个函数的代码如下:
#include "delay.h"
#include "sys.h"
//
//如果使用OS,则包括下面的头文件即可
#if SYSTEM_SUPPORT_OS
#include "FreeRTOS.h" //FreeRTOS使用
#include "task.h"
#endif
static u8 fac_us=0; //us延时倍乘数
static u16 fac_ms=0; //ms延时倍乘数,在os下,代表每个节拍的ms数
extern void xPortSysTickHandler(void);
//systick中断服务函数,使用OS时用到
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
{
xPortSysTickHandler();
}
}
//初始化延迟函数
//SYSTICK的时钟固定为AHB时钟,基础例程里面SYSTICK时钟频率为AHB/8
//这里为了兼容FreeRTOS,所以将SYSTICK的时钟频率改为AHB的频率!
//SYSCLK:系统时钟频率
void delay_init(u8 SYSCLK)
{
u32 reload;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
fac_us=SYSCLK; //不论是否使用OS,fac_us都需要使用
reload=SYSCLK; //每秒钟的计数次数 单位为M
reload*=1000000/configTICK_RATE_HZ; //根据delay_ostickspersec设定溢出时间
//reload为24位寄存器,最大值:16777216,在168M下,约合0.0998s左右
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)
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=ticks)break; //时间超过/等于要延迟的时间,则退出.
}
};
}
//延时nms
//nms:要延时的ms数
//nms:0~65535
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数
void delay_xms(u32 nms)
{
u32 i;
for(i=0;i
至此freertos的简单移植就差不多就完成了