一文了解 | FreeRTOS移植到stm32流程

本文详细介绍了FreeRTOS实时操作系统如何移植到STM32平台,强调了其提供可预测的任务调度、多任务支持和资源管理的优势,包括基于优先级的抢占式调度算法和内存管理。
摘要由CSDN通过智能技术生成

前言     

       FreeRTOS实时操作系统移植到STM32平台的优点

     (1)FreeRTOS是一个实时操作系统,提供了可预测的任务调度和响应时间。这对于需要实时性能的应用程序至关重要。

     (2)FreeRTOS允许您在STM32上同时运行多个任务,这些任务可以并行执行。可以更好地组织和管理代码,提高系统的模块化和可维护性。

     (3)FreeRTOS提供了任务、队列、信号量等机制,使操作人员更有效地管理STM32的资源。可以防止资源竞争和死锁等常见问题,提高系统的稳定性和可靠性。

       上述众多优点表明,移植可以给STM32平台提供可靠的实时性能、多任务支持和资源管理。

正文

01-FreeRTOS简介
        1、RTOS 简介

        实时操作系统(RTOS)是一种专为实时应用程序设计的操作系统,它能够确保任务在特定的时间约束内完成,并提供可预测的响应时间。RTOS 通常用于嵌入式系统,其中任务的时间敏感性非常重要。实时操作系统分为硬实时和软实时两种类型,硬实时要求任务必须在规定的时间内完成,而软实时则允许偶尔的任务延迟。

        2、FreeRTOS 简介

        FreeRTOS 是一个流行的实时操作系统,专为嵌入式系统设计。它提供了轻量级的内核,适用于资源有限的设备,并具有高度可移植性。FreeRTOS 的内核提供了任务调度、信号量、消息队列等基本功能,同时也支持实时内存管理和软件定时器等扩展功能。

        3、多任务操作系统简介

        FreeRTOS 是一个流行的实时操作系统,专为嵌入式系统设计。它提供了轻量级的内核,适用于资源有限的设备,并具有高度可移植性。FreeRTOS 的内核提供了任务调度、信号量、消息队列等基本功能,同时也支持实时内存管理和软件定时器等扩展功能。

        4、FreeRTOS 能够同时多任务执行的原理

        a、FreeRTOS 使用基于优先级的抢占式调度算法。每个任务都有一个优先级,并且具有最高优先级的任务将始终运行,直到它阻塞、让出 CPU,或者被更高优先级的任务抢占。这种调度算法确保了高优先级任务的及时响应,同时也允许低优先级任务在必要时执行。

        b、当任务被阻塞时,调度器会选择下一个最高优先级的就绪任务来执行。这种方式实现了任务之间的并发执行,从而提供了多任务操作系统的功能。任务的状态转换由任务调度器负责管理,确保任务的执行顺序符合预期。

02-下载FreeRTOS数据包

        FreeRTOS移植首先需要从官网下载FreeRTOS数据包,对于一下多余的文件进行删除,仅使用所需文件,减少内存使用,官网链接如下。FreeRTOS - Free RTOS Source Code Downloads, the official FreeRTOS zip file release download

03-FreeRTOS移植过程
        1、解压数据包

        从官网下载得到的FreeRTOS数据包,需要进行解压,以Keil工具下STM32F103芯片为例,解压之后,它的FreeRTOS的目录如下:

     (1)可以获得一个内核文件Source,也就是源代码文件,里面包含了include、portable等文件夹,还有task.c-用于任务操作文件,list.c-用于使用列表,queue-用于使用对列以及信号量操作。portable文件夹里包含RVDS文件-可以选择架构、MemMang文件-用于内存管理。

        (2)还有一个Demo文件,里面包含了一个STM32F103的工程实例,CORTEX_STM32F103_Keil,已经移植完成的,里面包含一个FreeRTOSConfig.h配置文件,移植时也会用到。

        2、创建FreeRTOS文件目录

     (1)经过解压之后,就可以进行复制所需文件,首先在自己需要移植的项目文件中创建一个FreeRTOS文件目录,然后需要将解压之后的内核文件Source中的7个.c文件和include、portable文件复制到该文件夹下,如下图所示。

     (2)对于portable文件夹下,仅保留MemMang和RVDS文件夹,其中MemMang里有5个内存管理模块,heap_1.c至heap_5.c五个文件,其中heap_4.c可以动态分配内存,使相邻空间内存合并处理,其余内存删除,解决了碎片化问题。因此,仅保留heap_4.c文件。对于RVDS文件夹,保留需要的ARM系列即可,仅保留ARM-CM3即可。

        3、创建FreeRTOS分组文件

     (1)在项目文件中创建分组文件,都是属于FreeRTOS的,一个是Source文件用于存放源文件,一个是other文件用于存放heap_4.c和port.c文件,port.c文件在ARM_CM3中,如图所示

      (2)接下来就是如何操作,导入这些文件,以Keil软件为例,下图是导入文件的步骤。

      (3)导入文件之后,需要包含各文件的头文件,如下图所示,按照步骤操作即可。

      

      此时直接编译之后,将会报错,主要是因为缺少配置文件FreeRTOSConfig.h

       4、添加FreeRTOS配置文件

       在解压之后的工程实例CORTEX_STM32F103_Keil,包含一个FreeRTOSConfig.h配置文件,需要将其添加到FreeRTOS文件夹下,并在USER文件夹中添加该.h文件,然后包含头文件FreeRTOS,因为这是放在该文件夹中,添加步骤与上述一致。

       

       此时直接编译之后,不会出现错误 !

       4、修改部分宏定义

       此时虽然运行之后,并没有出现编译错误,但是还有一些与中断有关的重要函数需要修改,在FreeRTOSConfig.h添加① #define xPortPendSVHandler ② #define xPortSysTickHandler #define vPortSVCHandler三个宏定义,这三个分别对应 PendSV_Handler-用于出发任务切换操作SysTick_Handler-用于实现定时功能SVC_Handler-用于实现系统用调用三个中断函数,当运行之后,会出现函数重定义错误,因为在stm32f10x_it.c文件中已经包含了这三个函数,需要进行删除如下图所示。

          注意:一般经过上面修改之后,就相当于移植成功,可以直接使用了,但是,有的可能并没有实现自己需要的功能,因为上面的中断函数有一些小问题。可以通过下面方法进行改进。

       5、FreeRTOS改进

       上述的三个宏定义中③可以直接使用port.c中自带的中断函数,其实上面的原理就是使用的port.c自带的函数,此时但是运行结果并不理想,可以采用自定义第②个函数的方式解决这个问题,具体代码如下。就是在stm32f10x_it.c文件中的函数里自动修改即可。

        这样便可以实现程序正常运行。

extern void xPortSysTickHandler(void);
 
//systick中断服务函数
void SysTick_Handler(void)
{	
    #if (INCLUDE_xTaskGetSchedulerState  == 1 )
      if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
      {
    #endif  /* INCLUDE_xTaskGetSchedulerState */  
        xPortSysTickHandler();
    #if (INCLUDE_xTaskGetSchedulerState  == 1 )
      }
    #endif  /* INCLUDE_xTaskGetSchedulerState */
}

总结

        通过上述步骤之后,便可以使用实时操作系统(FreeRTOS)实现多任务运行,下面代码适用于实现LED灯循环执行的两个任务,可以将程序烧录到开发板查看效果。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"   // 使用队列的头文件
#include "stdio.h"   // c函数标准库的头文件

int task1flagrun = 0;
int task2flagrun = 0;

void vTask1(void *pvParameters)
{
	for(;;)
	{
		task1flagrun = 1;
		task2flagrun = 0;
		GPIO_SetBits(GPIOA,GPIO_Pin_1);
		vTaskDelay(1000);
		GPIO_ResetBits(GPIOA,GPIO_Pin_1);
		vTaskDelay(1000);
		
	}
}

void vTask2(void *pvParameters)
{
	for(;;)
	{
		task1flagrun = 0;
		task2flagrun = 1;
		GPIO_ResetBits(GPIOB,GPIO_Pin_1);
		vTaskDelay(500);
		GPIO_SetBits(GPIOB,GPIO_Pin_1);
		vTaskDelay(500);
	}
}



int main(void){

	
	LED_Init();
	
	
	
	xTaskCreate(vTask1,"LED1",128,NULL,1,NULL);
	xTaskCreate(vTask2,"LED2",128,NULL,1,NULL);
	
	//启动任务调度器
	vTaskStartScheduler();
	
	// 4、设置低电平,LED灯亮起
//	GPIO_ResetBits(GPIOA,GPIO_Pin_1);
	// 5、也可以GPIO_WriteBit()函数设置高低电平
	// 前两个参数和Set和Reset一样,第三个参数用于清除端口值,和设置端口值
	// 如果参数=Bit_RESET,清除端口值,设置为低电平,灯亮;反之参数=Bit_SET,为高电平,灯灭
//	GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
	
	// 6、若是需要实现LED灯闪烁的命令,就需要在While死循环中进行一些设置
	while(1){
		// 点亮 两个函数都可以
//		GPIO_ResetBits(GPIOA,GPIO_Pin_0);
//		Delay_ms(500);  // 延时函数直接调用即可
//	    GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
//		GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)0);  // 0为低电平
		// 7、这里加延时函数
//		Delay_ms(500);
		
		// 熄灭 
//		GPIO_SetBits(GPIOA,GPIO_Pin_0);
//		Delay_ms(500);
//	    GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET); 如果这里想要直接使用自己定义的参数代替第三个参数,
//		GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)1);  // 1为高电平
	//  (BitAction)0 需要加
		
//	    Delay_ms(500);
	
	}

}

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一伦明悦

感谢,您的支持是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值