记录一下,方便以后翻阅~
1. 准备工作
1)FreeRTOS源码(选择所需要的即可)。
2. FreeRTOS移植
2.1 添加FreeRTOS源码
在案例文件夹中新建一个FreeRTOS文件夹,以后将FreeRTOS的源码添加至该文件夹里。根据前一章的知识点,portable文件夹里只需留下keil、MemMang和RVDS三个文件夹,其余都可以删除。
2.2 在工程分组中添加文件
打开案例工程,新建分组FreeRTOS_CORE和FreeRTOS_PORTABLE,然后添加文件。 FreeRTOS_PORTABLE分组中,port.c是RVDS文件夹下ARM_CM3中的文件;heap_4.c是MemMang文件夹里的。MemMang文件夹里有heap_1.c、heap_2.c、heap_3.c、heap_4.c和heap_5.c,表示五种不同的内存管理方法。
2.3 添加头文件路径
如下图所示添加头文件路径:
头文件路径添加完成后编译一下,有如下错误,提示打不开“FreeRTOSConfig.h”。
这个文件可以在FreeRTOSv9.0.0–>FreeRTOS–>Demo–>CORTEX_STM32F103_Keil文件里找到。
3. 修改SYSTEM文件夹里的文件
SYSTEM文件夹里有三个文件:sys、delay和usart三个源文件和头文件,这是正点原子团队开发的,但不仅限于战舰v3开发板。
3.1 修改sys.h文件
sys.h文件里面用宏SYSTEM_SUPPORT_OS来定义是否使用OS,具体代码如下:
#define SYSTEM_SUPPORT_OS 1 // 定义系统文件夹是否支持OS,0,不支持;1,支持
3.2 修改usart.c文件
usart.c文件有两个修改地方:
一是添加FreeRTOS.h头文件:
#if SYSTEM_SUPPORT_OS
#include "FreeRTOS.h"
#endif
二是USART1的中断服务函数:
void USART1_IRQHandler(void)
{
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.3 修改delay.c文件
delay.c文件修改地方比较多,因为涉及FreeRTOS系统时钟:
1)SysTick_Handler()函数
extern void xPortSysTickHandler(void); // systick 中断服务函数,使用OS时用到
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED) // 系统已经运行
{ xPortSysTickHandler(); }
}
FreeRTOS的心跳是由滴答定时器产生的,根据FreeRTOS的系统时钟节拍设置好滴答定时器的周期,就会周期触发滴答定时器中断。其滴答定时器中断服务函数中调用FreeRTOS的API函数xPortSysTickHandler()。
2)delay_init()函数
void delay_init()
{
u32 reload;
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); // 选择外部时钟HCLK
fac_us=SystemCoreClock/1000000;
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_CRTL_ENABLE_Msk; // 开启SYSTICK
}
delay_init()用来初始化滴答定时器和延时函数,根据FreeRTOS的系统时钟节拍初始化滴答定时器,其节拍由configTICK_RATE_HZ来设置,其值可自由设置。
接来下是三个延迟函数:
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<told) tcnt+=told-tnow;
else tcnt+=reload-tnow+old;
told=tnow;
if(tcnt>=ticks) break; // 超时
}
};
}
void delay_ms(u32 nms)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED) // 系统已经运行
{
if(nms>=fac_ms) { vTaskDelay(nms/fac_ms); }
nms%=fac_ms; // OS已经无法提供这么小的延时了,采用普通方式延时
}
delay_us((u32)(nms*1000));
}
void delay_xms(u32 nms)
{
u32 i;
for(i=0;i<nms;i++) delay_us(1000);
}
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中将这三个函数注释掉。
至此,SYSTEM文件夹修改完成。