本专栏将对FreeRTOS进行快速讲解,带你了解并使用FreeRTOS的各部分内容。适用于快速了解FreeRTOS并进行开发、突击面试、对新手小白非常友好。期待您的后续关注和订阅!
目录
FreeRTOS系统移植
建议采用内存管理实验、定时器实验等进行FreeRTOS系统移植
1.1 FreeRTOS源码
FreeRTOS源码获取途径非常多,可以从其官网、或者从其他 FreeRTOS工程中获取,下面主要讲述以下如何从FreeRTOS的官网获取文件。
FreeRTOS官网:https://www.freertos.org/
next
文件下载完成后会有一个压缩包,此压缩包即为我们需要的系统。如下所示
内部文件内容如下
对于这些文件夹里的内容,现在我们只需知道大体装的哪些文件即可,下面文件讲解内容只需简单知道就好。
名称 | 描述 |
FreeRTOS | FreeRTOS内核 |
FreeRTOS-Plus | FreeRTOS组件 |
tools | 工具 |
GitHub-FreeRTOS-Home | FreeRTOS的GitHub仓库链接 |
Quick_Start_Guide | 快速入门指南官方文档链接 |
Upgrading-to-FreeRTOS-xxx | 升级到指定FreeRTOS版本官方文档链接 |
History.txt | FreeRTOS历史更新记录 |
其他 | 其他 |
FreeRTOS中有四个文件,分别如下:
名称 | 描述 |
Demo | FreeRTOS演示例程 |
License | FreeRTOS相关许可 |
Source | FreeRTOS源码 |
Test | 公用以及移植层测试代码 |
最重要的为Demo这个文件,进入Demo文件具备以下例程代码,对应自己使用的开发板和平台找到相应的文件。举例来说:我所使用的是STM32F103和Keil开发平台。进入Demo文件,找到如下文件夹。
点击进入文件夹,可以找到我们需要的FreeRTOSConfig.h文件
1.2 FreeRTOS移植步骤
FreeRTOS移植步骤程序移植主要分为以下几步:
-
集成FreeRTOS源代码:将FreeRTOS的源代码集成到基础工程中,并配置相应的头文件路径,确保代码能够正确编译和链接。
-
创建FreeRTOS配置文件:在工程中添加名为
FreeRTOSConfig.h
的配置文件,该文件将包含FreeRTOS所需的特定配置选项。 -
调整系统文件:对
SYSTEM
目录下的sys.c
、delay.c
和usart.c
文件进行必要的修改,以确保它们与FreeRTOS的运行环境兼容。 -
优化中断处理文件:对Systick中断、SVC中断和PendSV中断的处理逻辑进行调整,以适应FreeRTOS的中断管理机制。
-
开发应用程序:编写并添加应用程序代码,用于验证FreeRTOS的移植是否成功,并确保系统能够按照预期运行。
1.2.1 集成FreeRTOS源代码
(1)
在基础工程的 Middlewares文件夹中新建一个 文件夹中新建一个 FreeRTOS子文件夹,接着将 FreeRTOS 中的Source源代码添加到刚刚新建的 FreeRTOS 子文件中。如下图所示:
source文件:
移动到FreeRTOS中(此处删除了一些不用的文件,可以不删):
(2)
我们还需要heap_x.c和 port.c文件。此文件在portable文件夹中存在,打开portable文件夹,打开文件后找到这三个文件保存,其余全部删除。
heap_x.c文件在MemMang文件夹中,读者在进行FreeRTOS移植的时候可以根据需求选择合适的方法,具体这五种内存管理的算法,在后续FreeRTOS内存管理章节会具体分析,这里就先使用heap_4.c。
port.c文件RVD文件夹中,根据不同型号选择不同文件夹中的文件,具体对应表如下:
举例来说,我采用的是F1系列,则采用ARM_CM3中的port.c文件。
开发芯片类型 | port.c所在文件夹 |
STM32F1系列 | ARM_CM3 |
STM32F4系列 | ARM_CM4F |
STM32F7系列 | ARM_CM7/r0p1 |
STM32H7系列 | ARM_CM7/r0p1 |
1.2.2 文件添加
(1) port.c文件和 heap_4.c文件
将 port.c文件和 heap_4.c文件添加到工程中
(2)添加头文件路径
接下来,我们需要添加 FreeRTOS 源码的头文件路径。这需要添加两个头文件路径,其中一个是 FreeRTOS/include,另一个是 port.c 文件的路径。完成后的配置如下图所示(这里以正点原子的 STM32F1 系列开发板为例,其他类型的开发板操作类似)。
(3)添加 FreeRTOSConfig.h 文件
上文已经展示了FreeRTOSConfig.h 文件的文件路径我们需要将其拷贝到user路径中。
1.2.3 文件内容修改
SYSTEM 文件夹中的文件最初是为 UCOS 编写的,因此如果使用 FreeRTOS,需要对其进行相应的修改。虽然曾考虑让 SYSTEM 文件夹同时支持 UCOS 和 FreeRTOS,但这样会使文件过于复杂,不利于初学者学习。因此,这里专门针对 FreeRTOS 修改了 SYSTEM 文件夹中的文件。
1、修改 sys.h 文件
sys.h 文件修改很简单,在 sys.h 文件里面用宏SYSTEM_SUPPORT_OS 来定义是否使用OS,我们使用了FreeRTOS,所以应该将宏SYSTEM_SUPPORT_OS 改为 1。
//0,不支持os
//1,支持 os
#define SYSTEM_SUPPORT_OS 1 //定义系统文件夹是否支持 OS
2、修改 usart.c 文件
usart.c 文件的修改也很简单,一共有两个地方需要修改,首先就是串口的中断服务函数,原本在使用 µC/OS 的时候,进入和退出中断需要添加 OSIntEnter()和 OSIntExit()两个函数,这是µC/OS 对于中断的相关处理机制,而 FreeRTOS 中并没有这种机制,因此将这两行代码删除,修改后串口的中断服务函数如下所示:
SMT32F1系列修改:
void USART_UX_IRQHandler(void)
{
HAL_UART_IRQHandler(&g_uart1_handle); /* 调用 HAL 库中断处理公用函数 */
while (HAL_UART_Receive_IT( &g_uart1_handle,
(uint8_t *)g_rx_buffer,
RXBUFFERSIZE) != HAL_OK)/* 重新开启中断并接收数据 */
{
/* 如果出错会卡死在这里 */
}
}
3、修改 delay.c 文件
接下来修改 SYSTEM 文件夹中的最后一个文件——delay.c,delay.c 文件需要改动的地方比较多,大致可分为三个步骤:删除适用于 µC/OS 但不适用于 FreeRTOS 的相关代码、添加FreeRTOS 的相关代码、修改部分内容。
(1) 删除适用于 μC/OS但不适用于 FreeRTOS的相关代码(需要删除的代码内容如下)
/* 定义 g_fac_ms 变量, 表示 ms 延时的倍乘数,
* 代表每个节拍的 ms 数, (仅在使能 os 的时候,需要用到)
*/
static uint16_t g_fac_ms = 0;
/*
* 当 delay_us/delay_ms 需要支持 OS 的时候需要三个与 OS 相关的宏定义和函数来支持
* 首先是 3 个宏定义:
* delay_osrunning :用于表示 OS 当前是否正在运行,以决定是否可以使用相关函数
* delay_ostickspersec :用于表示 OS 设定的时钟节拍,
* delay_init 将根据这个参数来初始化 systick
* delay_osintnesting :用于表示 OS 中断嵌套级别,因为中断里面不可以调度,
* delay_ms 使用该参数来决定如何运行
* 然后是 3 个函数:
* delay_osschedlock :用于锁定 OS 任务调度,禁止调度
* delay_osschedunlock :用于解锁 OS 任务调度,重新开启调度
* delay_ostimedly :用于 OS 延时,可以引起任务调度.
*
* 本例程仅作 UCOSII 和 UCOSIII 的支持,其他 OS,请自行参考着移植
*/
/* 支持 UCOSII */
#ifdef OS_CRITICAL_METHOD /* OS_CRITICAL_METHOD 定义了
* 说明要支持 UCOSII
*/
#define delay_osrunning OSRunning /* OS 是否运行标记,0,不运行;1,在运行 */ #define delay_ostickspersec
OS_TICKS_PER_SEC /* OS 时钟节拍,即每秒调度次数 */ #define delay_osintnesting OSIntNesting /*
中断嵌套级别,即中断嵌套次数 */ #endif
/* 支持 UCOSIII */
#ifdef CPU_CFG_CRITICAL_METHOD /* CPU_CFG_CRITICAL_METHOD 定义了
* 说明要支持 UCOSIII
*/
#define delay_osrunning OSRunning /* OS 是否运行标记,0,不运行;1,在运行 */ #define delay_ostickspersec
OSCfg_TickRate_Hz /* OS 时钟节拍,即每秒调度次数 */ #define delay_osintnesting OSIntNestingCtr /*
中断嵌套级别,即中断嵌套次数 */ #endif
/**
* @brief us 级延时时,关闭任务调度(防止打断 us 级延迟)
* @param 无
* @retval 无
*/
static void delay_osschedlock(void)
{
#ifdef CPU_CFG_CRITICAL_METHOD /* 使用 UCOSIII */
OS_ERR err;
OSSchedLock(&err); /* UCOSIII 的方式,禁止调度,防止打断 us 延时 */ #else /* 否则
UCOSII */
OSSchedLock(); /* UCOSII 的方式,禁止调度,防止打断 us 延时 */ #endif
}
/**
* @brief us 级延时时,恢复任务调度
* @param 无
* @retval 无
*/
static void delay_osschedunlock(void)
{
#ifdef CPU_CFG_CRITICAL_METHOD /* 使用 UCOSIII */
OS_ERR err;
OSSchedUnlock(&err); /* UCOSIII 的方式,恢复调度 */ #else /* 否则 UCOSII */
OSSchedUnlock(); /* UCOSII 的方式,恢复调度 */ #endif
}
/**
* @brief us 级延时时,恢复任务调度
* @param ticks: 延时的节拍数
* @retval 无
*/
static void delay_ostimedly(uint32_t ticks)
{
#ifdef CPU_CFG_CRITICAL_METHOD
OS_ERR err;
OSTimeDly(ticks, OS_OPT_TIME_PERIODIC, &err); /* UCOSIII 延时采用周期模式 */
#else
OSTimeDly(ticks); /* UCOSII 延时 */
#endif
}
(2) 添加 FreeRTOS的相关代码
进行改写:只 需 要 在 delay.c 文 件 中 使 用 extern 关 键 字 导 入 一 个 FreeRTOS 函数 xPortSysTickHandler()即可,这个函数是用于处理 FreeRTOS 系统时钟节拍的,本教程是使用SysTick 作为FreeRTOS 操作系统的心跳,因此需要在SysTick 的中断服务函数中调用这个函数,因此将代码添加到SysTick 中断服务函数之前,代码修改如下:
extern void xPortSysTickHandler(void);
/**
* @brief systick 中断服务函数,使用 OS 时用到
* @param ticks: 延时的节拍数
* @retval 无
*/
void SysTick_Handler(void)
{
/* 代码省略 */
}
(3) 修改部分内容
最后要修改的内容包括两个,分别是包含头文件和 4 个函数。首先来看需要修改的 4 个函数,分别是 SysTick_Handler()、delay_init()、delay_us()和delay_ms()。
(a) SysTick_Handler()
这个函数是 SysTick 的中断服务函数,需要在这个函数中重复调用上个步骤中导入的函数xPortSysTickHandler(),代码修改后如下:
/**
* @brief systick 中断服务函数,使用 OS 时用到
* @param ticks: 延时的节拍数
* @retval 无
*/
void SysTick_Handler(void)
{
HAL_IncTick();
/* OS 开始跑了,才执行正常的调度处理 */
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
{
xPortSysTickHandler();
}
}
(b) delay_init()
STM32F1系列中:
void delay_init(uint16_t sysclk)
{
#if SYS_SUPPORT_OS
uint32_t reload;
#endif
SysTick->CTRL = 0; HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8);
g_fac_us = sysclk / 8; #if SYS_SUPPORT_OS
reload = sysclk / 8;
/* 使用 configTICK_RATE_HZ 计算重装载值
* configTICK_RATE_HZ 在 FreeRTOSConfig.h 中定义
*/
reload *= 1000000 / configTICK_RATE_HZ;
/* 删除不用的 g_fac_ms 相关代码 */ SysTick->CTRL |= 1 << 1; SysTick->LOAD = reload; SysTick->CTRL |= 1 << 0;
#endif
}
(c) delay_us()
void delay_us(uint32_t nus)
{
uint32_t ticks;
uint32_t told, tnow, tcnt = 0;
uint32_t reload = SysTick->LOAD;
/* 删除适用于 µC/OS 用于锁定任务调度器的自定义函数 */
ticks = nus * g_fac_us; told = SysTick->VAL;
while (1)
{
tnow = SysTick->VAL; if (tnow != told)
{
if (tnow < told)
{
tcnt += told - tnow;
}
else
{
tcnt += reload - tnow + told;
}
told = tnow;
if (tcnt >= ticks)
{
break;
}
}
}
/* 删除适用于 µC/OS 用于解锁任务调度器的自定义函数 */
}
(d) delay_ms()
void delay_ms(uint16_t nms)
{
uint32_t i;
for (i=0; i<nms; i++)
{
delay_us(1000);
}
}
(e) 包含头文件
根据上述步骤的修改,delay.c 文件中使用到了 FreeRTOS 的相关函数,因此就需要在delay.c文件中包含 FreeRTOS 的相关头文件,并且移除掉原本存在的 µC/OS 相关头文件。先看一下修改前 delay.c 文件中包含的µC/OS 相关的头文件:
/* 添加公共头文件 ( ucos 需要用到) */ #include "includes.h"
修改成如下内容:
/* 添加公共头文件 (FreeRTOS 需要用到) */ #include "FreeRTOS.h"
#include "task.h"
(f)修改相关中断文件
在 FreeRTOS 的移植过程中,会涉及到三个重要的中断:FreeRTOS 系统时基定时器的中断(SysTick 中断)、SVC 中断和 PendSV 中断。这三个中断的中断服务函数在 HAL 库提供的文件中都有定义。对于不同的 STM32 开发板,对应了不同的文件,STM32F1系列对应中断服务函数为:stm32f1xx_it.c。
其中,SysTick 的中断服务函数已经在 delay.c 文件中定义,并且 FreeRTOS 也提供了 SVC 和 PendSV 的中断服务函数。因此,需要将 HAL 库提供的这三个中断服务函数注释掉。这里采用宏开关的方式,使 HAL 库中的这三个中断服务函数不被编译。宏定义在 sys.h 文件中,因此还需要导入 sys.h 头文件。请读者按照表 2.1.4.1 找到对应的文件进行修改,修改后的代码如下:
/* 仅展示修改部分,其余代码未修改、不展示 */
/* Includes --------------------------------------*/
/* 导入 sys.h 头文件 */
#include "./SYSTEM/SYS/sys.h"
/**
* @brief This function handles SVCall exception.
* @param None
* @retval None
*/
/* 加入宏开关 */
#if (!SYS_SUPPORT_OS)
void SVC_Handler(void)
{
}
#endif
/**
* @brief This function handles PendSVC exception.
* @param None
* @retval None
*/
/* 加入宏开关 */
#if (!SYS_SUPPORT_OS)
void PendSV_Handler(void)
{
}
#endif
/**
* @brief This function handles SysTick Handler.
* @param None
* @retval None
*/
/* 加入宏开关 */
#if (!SYS_SUPPORT_OS)
void SysTick_Handler(void)
{
HAL_IncTick();
}
#endif
最后一个要修改的地方为:FreeRTOSConfig.h
#define NVIC_PRIO_BITS 4U
修改为:
#define NVIC_PRIO_BITS 4
到这里移植已经完成,移植完成的项目放在我发布的文件里
本专栏将对FreeRTOS进行快速讲解,带你了解并使用FreeRTOS的各部分内容。期待诸君的关注点赞!