当前位置:   article > 正文

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

freertos移植到stm32

前言     

       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文件中的函数里自动修改即可。

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

  1. extern void xPortSysTickHandler(void);
  2. //systick中断服务函数
  3. void SysTick_Handler(void)
  4. {
  5. #if (INCLUDE_xTaskGetSchedulerState == 1 )
  6. if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
  7. {
  8. #endif /* INCLUDE_xTaskGetSchedulerState */
  9. xPortSysTickHandler();
  10. #if (INCLUDE_xTaskGetSchedulerState == 1 )
  11. }
  12. #endif /* INCLUDE_xTaskGetSchedulerState */
  13. }

总结

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

  1. #include "stm32f10x.h" // Device header
  2. #include "Delay.h"
  3. #include "LED.h"
  4. #include "FreeRTOS.h"
  5. #include "task.h"
  6. #include "queue.h" // 使用队列的头文件
  7. #include "stdio.h" // c函数标准库的头文件
  8. int task1flagrun = 0;
  9. int task2flagrun = 0;
  10. void vTask1(void *pvParameters)
  11. {
  12. for(;;)
  13. {
  14. task1flagrun = 1;
  15. task2flagrun = 0;
  16. GPIO_SetBits(GPIOA,GPIO_Pin_1);
  17. vTaskDelay(1000);
  18. GPIO_ResetBits(GPIOA,GPIO_Pin_1);
  19. vTaskDelay(1000);
  20. }
  21. }
  22. void vTask2(void *pvParameters)
  23. {
  24. for(;;)
  25. {
  26. task1flagrun = 0;
  27. task2flagrun = 1;
  28. GPIO_ResetBits(GPIOB,GPIO_Pin_1);
  29. vTaskDelay(500);
  30. GPIO_SetBits(GPIOB,GPIO_Pin_1);
  31. vTaskDelay(500);
  32. }
  33. }
  34. int main(void){
  35. LED_Init();
  36. xTaskCreate(vTask1,"LED1",128,NULL,1,NULL);
  37. xTaskCreate(vTask2,"LED2",128,NULL,1,NULL);
  38. //启动任务调度器
  39. vTaskStartScheduler();
  40. // 4、设置低电平,LED灯亮起
  41. // GPIO_ResetBits(GPIOA,GPIO_Pin_1);
  42. // 5、也可以GPIO_WriteBit()函数设置高低电平
  43. // 前两个参数和Set和Reset一样,第三个参数用于清除端口值,和设置端口值
  44. // 如果参数=Bit_RESET,清除端口值,设置为低电平,灯亮;反之参数=Bit_SET,为高电平,灯灭
  45. // GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
  46. // 6、若是需要实现LED灯闪烁的命令,就需要在While死循环中进行一些设置
  47. while(1){
  48. // 点亮 两个函数都可以
  49. // GPIO_ResetBits(GPIOA,GPIO_Pin_0);
  50. // Delay_ms(500); // 延时函数直接调用即可
  51. // GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
  52. // GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)0); // 0为低电平
  53. // 7、这里加延时函数
  54. // Delay_ms(500);
  55. // 熄灭
  56. // GPIO_SetBits(GPIOA,GPIO_Pin_0);
  57. // Delay_ms(500);
  58. // GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET); 如果这里想要直接使用自己定义的参数代替第三个参数,
  59. // GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)1); // 1为高电平
  60. // (BitAction)0 需要加
  61. // Delay_ms(500);
  62. }
  63. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/730318
推荐阅读
相关标签
  

闽ICP备14008679号