FreeRTOS笔记-移植STM32F103
振袖秋风问紅叶
编辑于 2024年04月09日 01:06
收录于文集
共15篇

FreeRTOS移植

资料链接: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"下方添加

代码块
JavaScript
自动换行
复制代码
#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为:


代码块
clike
自动换行
复制代码
#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为:


代码块
JavaScript
自动换行
复制代码
#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
复制成功