FreeRTOS操作系统(详细速通篇)——— 第三章

        本专栏将对FreeRTOS进行快速讲解,带你了解并使用FreeRTOS的各部分内容。适用于快速了解FreeRTOS并进行开发、突击面试、对新手小白非常友好。期待您的后续关注和订阅!

目录

FreeRTOS系统移植

1.1 FreeRTOS源码

1.2 FreeRTOS移植步骤

1.2.1 集成FreeRTOS源代码

1.2.2 文件添加

1.2.3 文件内容修改

FreeRTOS系统移植

        建议采用内存管理实验、定时器实验等进行FreeRTOS系统移植

1.1 FreeRTOS源码

        FreeRTOS源码获取途径非常多,可以从其官网、或者从其他 FreeRTOS工程中获取,下面主要讲述以下如何从FreeRTOS的官网获取文件。

        FreeRTOS官网:https://www.freertos.org/

next

文件下载完成后会有一个压缩包,此压缩包即为我们需要的系统。如下所示

内部文件内容如下

        对于这些文件夹里的内容,现在我们只需知道大体装的哪些文件即可,下面文件讲解内容只需简单知道就好。

名称

描述

FreeRTOS

FreeRTOS内核

FreeRTOS-Plus

FreeRTOS组件

tools

工具

GitHub-FreeRTOS-Home

FreeRTOSGitHub仓库链接

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移植步骤程序移植主要分为以下几步:

  1. 集成FreeRTOS源代码:将FreeRTOS的源代码集成到基础工程中,并配置相应的头文件路径,确保代码能够正确编译和链接。

  2. 创建FreeRTOS配置文件:在工程中添加名为FreeRTOSConfig.h的配置文件,该文件将包含FreeRTOS所需的特定配置选项。

  3. 调整系统文件:对SYSTEM目录下的sys.cdelay.cusart.c文件进行必要的修改,以确保它们与FreeRTOS的运行环境兼容。

  4. 优化中断处理文件:对Systick中断、SVC中断和PendSV中断的处理逻辑进行调整,以适应FreeRTOS的中断管理机制。

  5. 开发应用程序:编写并添加应用程序代码,用于验证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的各部分内容。期待诸君的关注点赞!

  • 14
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值