本教程只针对移植实操,关于理论部分请另行百度学习。
本教程移植实操基于正点原子源码、教程手册进程移植。
FreeRTOSv202112.00\FreeRTOS\Source
分组 FreeRTOS_CORE 中的文件在什么地方就不说了,打开 FreeRTOS 源码一目了然。重点来说说 FreeRTOS_PORTABLE 分组中的 port.c 和 heap_4.c 是怎么来的,port.c 是 RVDS 文件夹下的ARM_CM3 中的文件,因为 STM32F103 是 Cortex-M3 内核的,因此要选择 ARM_CM3中的 port.c 文件。heap_4.c 是 MemMang 文件夹中的,MemMang 是跟内存管理相关的,里面有 5 个 c 文件:heap_1.c、heap_2.c、heap_3.c、heap_4.c 和 heap_5.c。这 5 个 c 文件是五种不同的内存管理方法,就像从北京到上海你可以坐火车、坐飞机,如果心情好的话也可以走路,反正有很多种方法,只要能到上海就行。这里也一样的,这 5 个文件都可以用来作为FreeRTOS 的内存管理文件,只是它们的实现原理不同,各有利弊。这里就先选择 heap_4.c,毕竟本章的重点是 FreeRTOS 的移植。
果然!官方的移植工程中有这个文件,我们可以使用这个文件,但是建议大家使用我们例程中的 FreeRTOSConf.h 文件,这个文件是 FreeRTOS 的系统配置文件,不同的平台其配置不同。这个文件复制到什么地方大家可以自行决定,这里我为了方便放到了 FreeRTOS 源码中的 include 文件夹下。
FreeRTOSConfig.h 是何方神圣?看名字就知道,他是 FreeRTOS 的配置文件,一般的操作
系统都有裁剪、配置功能,而这些裁剪及配置都是通过一个文件来完成的,基本都是通过宏定
义来完成对系统的配置和裁剪的。
因为我是基于正点原子的源码进行FreeRTOS的移植,所以需要修改
原子手册原话:
SYSTEM 文件夹里面的文件一开始是针对 UCOS 而编写的,所以如果使用 FreeRTOS 的话
就需要做相应的修改。本来打算让 SYSTEM 文件夹也支持 FreeRTOS,但是这样的话会导致
SYSTEM 里面的文件太过于复杂,这样非常不利于初学者学习,所以这里就专门针对 FreeRTOS
修改了 SYSTEM 里面的文件。
1、修改 sys.h 文件
sys.h 文件修改很简单,在 sys.h 文件里面用宏 SYSTEM_SUPPORT_OS 来定义是否使用 OS,
我们使用了 FreeRTOS,所以应该将宏 SYSTEM_SUPPORT_OS 改为 1。
//0,不支持 os
//1,支持 os
#define SYSTEM_SUPPORT_OS 1
//定义系统文件夹是否支持 OS
2、修改 usart.c 文件
usart.c 文件修改也很简单,usart.c 文件有两部分要修改,一个是添加 FreeRTOS.h 头文件,
默认是添加的 UCOS 中的 includes.h 头文件,修改以后如下:
//如果使用 os,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "FreeRTOS.h"
//os 使用
#endif
另外一个就是 USART1 的中断服务函数,在使用 UCOS 的时候进出中断的时候需要添加
OSIntEnter()和 OSIntExit(),使用 FreeRTOS 的话就不需要了,所以将这两行代码删除掉,修改
以后如下:
void USART1_IRQHandler(void) //串口 1 中断服务程序
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(USART1); //读取接收到的数据
if((USART_RX_STA&0x8000)==0) //接收未完成
{
if(USART_RX_STA&0x4000) //接收到了 0x0d
{
if(Res!=0x0a)USART_RX_STA=0; //接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到 0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
}
}
}
}
}
3、修改 delay.c 文件
delay.c 文件修改的就比较大了,因为涉及到 FreeRTOS 的系统时钟,delay.c 文件里面有 4
个函数,先来看一下函数 SysTick_Handler(),此函数是滴答定时器的中断服务函数,代码如下:
extern void xPortSysTickHandler(void);
//systick 中断服务函数,使用 OS 时用到
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
{
xPortSysTickHandler();
}
}
FreeRTOS 的心跳就是由滴答定时器产生的,根据 FreeRTOS 的系统时钟节拍设置好滴答定
时器的周期,这样就会周期触发滴答定时器中断了。在滴答定时器中断服务函数中调用
FreeRTOS 的 API 函数 xPortSysTickHandler()。
delay_init()是用来初始化滴答定时器和延时函数,代码如下:
//初始化延迟函数
//SYSTICK 的时钟固定为 AHB 时钟,基础例程里面 SYSTICK 时钟频率为 AHB/8
//这里为了兼容 FreeRTOS,所以将 SYSTICK 的时钟频率改为 AHB 的频率!
//SYSCLK:系统时钟频率
void delay_init()
{
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
}
前面我们说了 FreeRTOS 的系统时钟是由滴答定时器提供的,那么肯定要根据 FreeRTOS 的
系统时钟节拍来初始化滴答定时器了,delay_init()就是来完成这个功能的。FreeRTOS 的系统时
钟节拍由宏 configTICK_RATE_HZ 来设置,这个值我们可以自由设置,但是一旦设置好以后我
们就要根据这个值来初始化滴答定时器,其实就是设置滴答定时器的中断周期。在基础例程中
滴答定时器的时钟频率设置的是 AHB 的 1/8,这里为了兼容 FreeRTOS 将滴答定时器的时钟频
率改为了 AHB,也就是 72MHz!这一点一定要注意!
接下来的三个函数都是延时的,代码如下:
//延时 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)
{
//这里注意一下 SYSTICK 是一个递减的计数器就可以了.
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
delay_us()是 us 级延时函数,delay_ms 和 delay_xms()都是 ms 级的延时函数,delay_us()和
delay_xms()不会导致任务切换。delay_ms()其实就是对 FreeRTOS 中的延时函数 vTaskDelay()的
简单封装,所以在使用 delay_ms()的时候就会导致任务切换。
delay.c 修改完成以后编译一下,会提示如图 所示错误:
该错误上面也有提到,对应修改即可
如图的错误提示表示在 port.c、delay.c 和 stm32f10x_it.c 中三个重复定义的函数:
SysTick_Handler()、SVC_Handler()和 PendSV_Handler(),这三个函数分别为滴答定时器中断服
务函数、SVC 中断服务函数和 PendSV 中断服务函数,将 stm32f10x_it.c 中的三个函数屏蔽掉,
修改完成后整个delay.c文件内容如下:
#include "delay.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延时倍乘数,在ucos下,代表每个节拍的ms数
extern void xPortSysTickHandler(void);
//systick中断服务函数,使用ucos时用到
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
{
xPortSysTickHandler();
}
}
//初始化延迟函数
//当使用OS的时候,此函数会初始化OS的时钟节拍
//SYSTICK的时钟固定为HCLK时钟的1/8
//SYSCLK:系统时钟
void delay_init()
{
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数.
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数
void delay_ms(u16 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)); //普通方式延时
}
再次编译代码,应该没有错误了,如果还是错误的话自行根据错误类型修改!至此,SYSTEM
文件夹就修改完成了,至此FreeRTOS的移植实操到此结束了。
链接:https://pan.baidu.com/s/1SwB48r0Bh9vyGxfIKswP1w
提取码:yoak