基于STM32的FreeRTOS学习之FreeRTOS移植(二)

记录一下,方便以后翻阅~

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文件夹修改完成。

猜你喜欢

转载自blog.csdn.net/Leisure_ksj/article/details/114680150