FreeRTOS—初识RTOS、移植

前言

本专栏基于正点原子的《FreeRTOS开发指南_V1.10》所编写,使用的开发板型号是精英型STM32f103zet6。

一、RTOS介绍

1.1.什么是 FreeRTOS

“RTOS”全称是 Real Time Operating System,中文名就是实时操作系统,RTOS 并不是值某一特定的操作系统,而是指一类操作系统,例如,µC/OS,FreeRTOS,RTX,RT-Thread 等这些都是 RTOS 类的操作系统。因此,从 FreeRTOS 的名字中就能看出,FreeROTS 是一款免费的实时操作系统,也正因FreeRTOS开源免费,全国的FreeRTOS的使用量也非常的靠前。

1.2.操作系统的工作

操作系统是允许多个任务“同时运行”的,操作系统的这个特性被称为多任务。然而实际上,一个 CPU 核心在某一时刻只能运行一个任务,而操作系统中任务调度器的责任就是决定在某一时刻 CPU 究竟要运行哪一个任务,任务调度器使得 CPU 在各个任务之间来回切换并处理任务,由于切换处理任务的速度非常快,因此就给人造成了一种同一时刻有多个任务同时运行的错觉。

1.3.FreeRTOS 的特点

  • 可移植性强
  • 可裁剪
  • 支持多种任务通讯、同步机制
  • 高效的软件定时器
  • 任务数量、优先级数量不限
  • 运行效率高
  • 支持抢占式、合作式调度
  • 开源、免费、可商用

二、FreeRTOS的移植

2.1.基本工程

以正点原子标准例程-HAL 库版本的内存管理的实验工程为基础工程进行 FreeRTOS的移植。由于内存管理实验例程的 BSP 文件夹中可能不包含定时器的驱动文件,因此如果内存管理试验力撑的 BSP 文件夹如果不包含 TIMER 文件夹的话,需要从定时器相关实验的 BSP 文件夹中拷贝一份 TIMER 到 FreeRTOS 移植基础工程当中。

2.2.FreeRTOS源码获取

在 FreeRTOS 官方网站下载即可,里面的文件夹为这个样子:

在这里插入图片描述

FreeRTOS 的源码存放在 FreeRTOS 文件夹里面的 Source 文件夹里:

在这里插入图片描述

下图是各个文件的解释:

在这里插入图片描述

2.3.创建FreeRTOS的文件夹

在HAL 库版本的内存管理的实验工程里的 Middleware 文件夹下创建一个名字为 FreeRTOS 的文件夹,用于存放上一步骤的源码:

在这里插入图片描述

里面存放的代码有一些用不着的需要删除,删成下图所示,特别是 portable文件夹里面的编译器,本实验只用到 keil5,因此其他的编译器可以删除减少内存的使用:

在这里插入图片描述

  • Keil 文件夹是在 MDK 中使用 ARMCC 编译器(AC5)时使用的。
  • MemMang 中的文件是 FreeRTOS 提供的用于内存管理的文件,该文件夹包含了五个 C 源文件,这五个 C 源文件对应了五种内存管理的方法。
  • FreeRTOS 提供了 ARM Cortex-M0、ARM Cortex-M3、ARM Cortex-M4、ARM Cortex-M7 等内核芯片的移植文件,本实验是基于STM32F103的,属于Cortex-M3内核,因此使用的部分源码需要在ARM_CM3文件夹里。

在这里插入图片描述

2.4.将文件添加到工程

本专栏是学习FreeRTOS,为了更贴合标题,把工程名称改成FreeRTOS,再新建两个文件夹,分别是图中右边框里的两个文件夹:

在这里插入图片描述

Middlewares/FreeRTOS_CORE文件夹用于存放FreeRTOS 的内核 C 源码文件,将FreeRTOS文件夹里面所有的 .c 文件全都选上:

在这里插入图片描述

Middlewares/FreeRTOS_PORT文件夹用于存放 FreeRTOS 内核的移植文件,需要添加两类文件到这个分组,分别为 heap_x.c (读者在进行 FreeRTOS 移植的时候可以根据需求选择合适的方法,具体这五种内存管理的算法本实验就选择 heap_4.c 即可)和 port.c 文件,heap_x.c 在路径 FreeRTOS/portable/MemMang 下面;port.c的路径在FreeRTOS/portable/RVDS/ARM_CM3里面,port 文件是 FreeRTOS 这个软件与 MCU 这个硬件连接的桥梁,因此对于正点原子的 STM32 系列不同的开发板,所使用的 port 文件是不同的。

在这里插入图片描述

最后在User文件夹里添加 FreeRTOSConfig.h 配置文件:
在这里插入图片描述
在 FreeRTOSv202112.00\FreeRTOS\Demo\CORTEX_STM32F103_IAR 路径里,找到STM32F103型号的Demo文件夹,里面就有适合该型号的配置文件,或者直接在正点原子的例程里复制过来。

2.5.添加头文件路径

如下图所示:

在这里插入图片描述

2.6.修改 SYSTEM 文件

2.6.1.sys.h 文件

sys.h文件的修改很简单,在sys.h文件中使用了宏SYS_SUPPORT_OS来定义是否支持OS,因为要支持 FreeRTOS,因此应当将宏 SYS_SUPPORT_OS 定义为 1,如下面代码所示:

在这里插入图片描述

2.6.2.usart.c 文件

原本在使用 µC/OS 的时候,进入和退出中断需要添加 OSIntEnter()和 OSIntExit()两个函数,这是 µC/OS 对于中断的相关处理机制,而 FreeRTOS 中并没有这种机制,因此将这两行代码删除,如下面代码所示:(以F1为例)

在这里插入图片描述

接下来 usart.c 要修改的第二个地方就是导入的头文件,因为在串口的中断服务函数当中已经删除了 µC/OS 的相关代码,并且也没有使用到 FreeRTOS 的相关代码,因此将 usart.c 中包含的关于 OS 的头文件删除,要删除的代码如下图所示:

在这里插入图片描述

2.6.3.delay.c 文件

  • 删除适用于 µC/OS 但不适用于 FreeRTOS 的相关代码,一共需要删除 1 个全局变量、3 个宏定义、3 个函数,这些要删除的代码在使用 µC/OS 的时候会使用到,但是在使用 FreeRTOS 的时候无需使用,需要删除的代码如下所示:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

2.7.添加 FreeRTOS 的相关代码

在使用 ARMCC(AC5)的情况下只需要在 delay.c 文件中使用 extern 关键字导入一个 FreeRTOS 函数——xPortSysTickHandler() 即可,这个函数是用于处理 FreeRTOS 系统时钟节拍的,本实验是使用 SysTick 作为 FreeRTOS操作系统的心跳,因此需要在 SysTick 的中断服务函数中调用这个函数,因此将代码添加到 SysTick 中断服务函数之前,代码修改如下:

在这里插入图片描述

2.8.修改部分内容

最后要修改的内容包括两个,分别是包含头文件和 4 个函数。首先来看需要修改的 4 个函数,分别是 SysTick_Handler()、delay_init()、delay_us() 和 delay_ms() 。

2.8.1.SysTick_Handler( )

对于使用 ARMCC(AC5)的情况,只需在这个函数中不断调用上个步骤中导入的函数 xPortSysTickHandler(),代码修改后如下图所示:
在这里插入图片描述

2.8.2.delay_init( )

函 数 delay_init() 主要用于初始化 SysTick 。这里要说明的是,在后续调用函数 TaskStartScheduler() 的时候,FreeRTOS 会按照 FreeRTOSConfig.h 文件的配置对 SysTick 进行初始化,因此 delay_init()函数初始化的 SysTick 主要使用在 FreeRTOS 开始任务调度之前。函数 delay_init()要修改的部分主要为 SysTick 的重装载值以及删除不用的代码,STM32F1 系列的函数delay_init()将 SysTick 的时钟频率设置为 CPU 时钟频率的 1/8,代码修改如下:

在这里插入图片描述

2.8.3.delay_us( )

函数 delay_us()用于微秒级的 CPU 忙延时,原本的函数 delay_us()延时的前后加入了自定义函数 delay_osschedlock()和 delay_osschedunlock()用于锁定和解锁 µC/OS 的任务调度器,以此来让延时更加准确。

在这里插入图片描述

2.8.4.delay_ms( )

函数 delay_ms() 用于毫秒级的 CPU 忙延时,原本的函数 delay_ms()会判断 µC/OS 是否运行,如果 µC/OS 正在运行的话,就使用 µC/OS 的 OS 延时进行毫秒级的延时,否则就调用函数delay_us()进行毫秒级的 CPU 忙延时。在 FreeRTOS 中,可以将函数 delay_ms()定义为只进行CPU 忙延时,当需要 OS 延时的时候,调用 FreeRTOS 提供的 OS 延时函数 vTaskDelay() 进行系统节拍级延时,函数 delay_ms()修改后的代码如下所示:

在这里插入图片描述

2.8.5.包含头文件

根据上述步骤的修改,delay.c 文件中使用到了 FreeRTOS 的相关函数,因此就需要在 delay.c文件中包含 FreeRTOS 的相关头文件,并且移除掉原本存在的 µC/OS 相关头文件。原来的delay.c 文件中包含的 µC/OS 相关的头文件:
在这里插入图片描述

修改过后:

在这里插入图片描述

2.9.修改中断相关文件

在 FreeRTOS 的移植过程中会这几到三个重要的中断,分别是 FreeRTOS 系统时基定时器的中断(SysTick 中断)、SVC 中断PendSV 中断,这三个中断的中断服务函数在 HAL 库提供的文件中都有定义,F1系列的中断服务函数所在 stm32f1xx_it.c 文件里。其中,SysTick 的中断服务函数在 delay.c 文件中已经定义了,并且 FreeRTOS 也提供了 SVC 和 PendSV 的中断服务函数,因此需要将 HAL 库提供的这三个中断服务函数注释掉,这里采用宏开关的方式让 HAL 库中的这三个中断服务函数不加入编译(如果使用操作系统就失能该函数),使用的宏在 sys.h 中定义,因此还需要导入 sys.h 头文件。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.10.修改stm32f103xe.h

最后修改 __NVIC_PRIO_BITS 这个宏定义的值为4,修改之前4u这个值也是正确的,但是 keil5 在编译 FreeRTOS 工程的时候会报错。
在这里插入图片描述

三、实验

3.1.添加定时器驱动

由于在后续的实验中需要使用到 STM32 的基本定时器外设,因此需要向工程中添加定时器的相关驱动文件,也可在后续实验需要用到定时器的时候再进行添加。将定时器的相关驱动文件添加到工程的 Drivers/BSP 文件分组中,如下图所示:
在这里插入图片描述
在正点原子的 FreeRTOS实验例程2 FreeRTOS 移植实验的User文件夹里面,复制下图两个文件,到自己的工程的User文件夹里面:
在这里插入图片描述
最后,在工程文件里添加 freertos_demo.c 文件,并运行代码,得到屏幕闪烁的同时,LED也跟着闪烁,以下是 freertos_demo.c 代码:


#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"

#include "FreeRTOS.h"
#include "task.h"


#define START_TASK_PRIO 1                  
#define START_STK_SIZE  128               
TaskHandle_t            StartTask_Handler;  
void start_task(void *pvParameters);       

#define TASK1_PRIO      2                   
#define TASK1_STK_SIZE  128              
TaskHandle_t            Task1Task_Handler; 
void task1(void *pvParameters);           

#define TASK2_PRIO      3                  
#define TASK2_STK_SIZE  128                
TaskHandle_t            Task2Task_Handler;  
void task2(void *pvParameters);             

uint16_t lcd_discolor[11] = {WHITE, BLACK, BLUE, RED,
                             MAGENTA, GREEN, CYAN, YELLOW,
                             BROWN, BRRED, GRAY};

void freertos_demo(void)
{
    lcd_show_string(10, 10, 220, 32, 32, "STM32", RED);
    lcd_show_string(10, 47, 220, 24, 24, "FreeRTOS Porting", RED);
    lcd_show_string(10, 76, 220, 16, 16, "ATOM@ALIENTEK", RED);
    
    xTaskCreate((TaskFunction_t )start_task,          
                (const char*    )"start_task",         
                (uint16_t       )START_STK_SIZE,      
                (void*          )NULL,                 
                (UBaseType_t    )START_TASK_PRIO,      
                (TaskHandle_t*  )&StartTask_Handler);   
    vTaskStartScheduler();
}

void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();          
    xTaskCreate((TaskFunction_t )task1,
                (const char*    )"task1",
                (uint16_t       )TASK1_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK1_PRIO,
                (TaskHandle_t*  )&Task1Task_Handler);

    xTaskCreate((TaskFunction_t )task2,
                (const char*    )"task2",
                (uint16_t       )TASK2_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK2_PRIO,
                (TaskHandle_t*  )&Task2Task_Handler);
    vTaskDelete(StartTask_Handler); 
    taskEXIT_CRITICAL();            
}

void task1(void *pvParameters)
{
    uint32_t task1_num = 0;
    
    while(1)
    {
        lcd_clear(lcd_discolor[++task1_num % 14]);                     
        lcd_show_string(10, 10, 220, 32, 32, "STM32", RED);
        lcd_show_string(10, 47, 220, 24, 24, "FreeRTOS Porting", RED);
        lcd_show_string(10, 76, 220, 16, 16, "ATOM@ALIENTEK", RED);
        LED0_TOGGLE();                                                 
        vTaskDelay(1000);                                           
    }
}

void task2(void *pvParameters)
{
    float float_num = 0.0;
    
    while(1)
    {
        float_num += 0.01f;                        
        printf("float_num: %0.4f\r\n", float_num);  
        vTaskDelay(1000);                        
    }
}
### FreeRTOSRTOS的区别及关系 #### 定义与特性 实时操作系统(Real-Time Operating System, RTOS)是一类专门设计用于满足严格的时间约束的操作系统。这类系统确保任务能够在规定时间内完成执行,这对于嵌入式设备尤其重要[^1]。 FreeRTOS是一个特定类型的RTOS,专注于小型多线程实时操作系统的实现。基于FreeRTOS内核构建的应用程序可以部署到Arduino兼容板等多种硬件平台上。这表明FreeRTOS不仅具备RTOS的核心功能——如提供可预测的任务调度机制和支持中断管理等功能——还特别针对资源受限环境进行了优化。 #### 功能对比 - **规模大小** 相较于其他可能更为复杂庞大的RTOS解决方案而言,FreeRTOS以其小巧轻便著称。这种紧凑的设计使得其非常适合应用于微控制器单元(MCU)等计算能力有限但又需要高效能表现的小型装置中。 - **开源许可** FreeRTOS采用修改版GPL许可证发布,在某些版本下允许商业用途而无需公开源码。相比之下,并不是所有的RTOS都会采取如此开放的态度对待版权问题;一些专有的RTOS可能会施加更加严格的授权条款限制使用者权利。 - **社区支持与发展活力** 自由/开源软件性质赋予了FreeRTOS强大的社群基础和技术交流平台。活跃的开发者群体不断贡献新特性和修复漏洞,促进了该RTOS生态系统的健康发展。然而,这也意味着稳定性方面或许不如那些经过长期商用验证的产品可靠[^2]。 #### 关系说明 尽管存在上述差异,FreeRTOS本质上仍然属于RTOS范畴之内。两者之间主要区别体现在具体应用场景下的性能参数调整以及适应不同开发需求所做出的技术取舍之上。例如,在面对多处理器架构时,部分高级别的RTOS能够更好地处理跨CPU核心间的通信协调工作,从而提高整体效率;而对于单片机级别的简单控制逻辑来说,则没有必要追求过分复杂的并发模型,此时像FreeRTOS这样简洁高效的方案反而更具优势。 ```c // 示例:创建两个任务并启动调度器 void vTaskFunction(void *pvParameters); BaseType_t xReturned; TaskHandle_t xCreatedTask; xReturned = xTaskCreate( vTaskFunction, /* Task function */ "TASK", /* String with name of task */ configMINIMAL_STACK_SIZE,/* Stack size in words*/ NULL, /* Parameter passed into task */ tskIDLE_PRIORITY, /* Priority at which task is created */ &xCreatedTask); /* Used to pass out the created task's handle index */ vTaskStartScheduler(); // 开始调度 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值