HAL库版FreeRTOS(上)

目录

  • FreeRTOS 简介
    • 初识FreeRTOS
      • 什么是FreeRTOS?
      • 为什么选择FreeRTOS?
      • FreeRTOS 的特点
      • 商业许可
    • 磨刀不误砍柴工
      • 查找资料
      • FreeRTOS 官方文档
      • Cortex-M 架构资料
    • FreeRTOS 源码初探
      • FreeRTOS 源码下载
      • FreeRTOS 文件预览
  • FreeRTOS 移植
    • FreeRTOS 移植
      • 移植前准备
      • 添加FreeRTOS 文件
      • 修改SYSTEM 文件

FreeRTOS 简介

从本章开始,我们就踏入了FreeRTOS 的大门,FreeRTOS 是一个RTOS 类的嵌入式实时操
作系统。在学习和使用FreeRTOS 之前,需要先了解什么是FreeRTOS?为什么选择学习
FreeRTOS?以及FreeRTOS 的特点,这也是本章的目的。
本章分为如下几部分:
1.1 初始FreeRTOS
1.2 磨刀不误砍柴工
1.3 FreeRTOS 源码初探

初识FreeRTOS

什么是FreeRTOS?

首先看一下FreeRTOS 的名字,可以分为两部分:“Free”和“RTOS”,“Free”就是免费的、
自由的、不受约束的意思,“RTOS”全称是Real Time Operating System,中文名就是实时操作
系统,要注意的是,RTOS 并不是值某一特定的操作系统,而是指一类操作系统,例如,µC/OS,
FreeRTOS,RTX,RT-Thread 等这些都是RTOS 类的操作系统。因此,从FreeRTOS 的名字中就
能看出,FreeROTS 是一款免费的实时操作系统。
操作系统是允许多个任务“同时运行”的,操作系统的这个特性被称为多任务。然而实际
上,一个CPU 核心在某一时刻只能运行一个任务,而操作系统中任务调度器的责任就是决定在
某一时刻CPU 究竟要运行哪一个任务,任务调度器使得CPU 在各个任务之间来回切换并处理
任务,由于切换处理任务的速度非常快,因此就给人造成了一种同一时刻有多个任务同时运行
的错觉。
操作系统的分类方式可以由任务调度器的工作方式决定,比如有的操作系统给每个任务分
配同样的运行时间,时间到了就切换到下一个任务,Unix 操作系统就是这样的。RTOS 的任务
调度器被设计为可预测的,而这正是嵌入式实时操作系统所需要的。在实时环境中,要求操作
系统必须实时地对某一个事件做出响应,因此任务调度器的行为必须是可预测的。像FreeRTOS
这种传统的RTOS 类操作系统是由用户给每个任务分配一个任务优先级,任务调度器就可以根
据此优先级来决定下一刻应该运行哪个任务。
FreeRTOS 是众多RTOS 类操作系统中的一种,FreeRTOS 十分的小巧,可以在资源有限的
微控制器中运行,当然了,FreeRTOS 也不仅仅局限于在微控制器中使用。就单从文件数量上来
看FreeRTOS 要比µC/OS 少得多。

为什么选择FreeRTOS?

上面我们说了RTOS 类操作系统有很多,那为什么要选择FreeRTOS 呢?在µC/OS 教程中,
我们说过学习RTOS 首选µC/OS,因为µC/OS 的资料很多,尤其是中文资料!相比之下FreeRTOS
的资料少,而且大多数是英文的,那为什么还要选择学习和使用FreeRTOS 呢?主要原因有以
下的几点:
1.免费。这是很重要的一点,因为在做产品的时候是要考虑产品的成本的,显而易见的
FreeRTOS 操作系统就是一个很好的选择,当然了,也可以选择其他免费的RTOS 操作系统。
2.简单。这一点单从FreeRTOS 操作系统的文件数量上,就能感觉到,这个在我们后面的具体学习中就会看到,和µC/OS 操作系统系统相比要少很多!
3.使用广泛。许多半导体厂商和软件厂商都在其产品中使用了FreeRTOS 操作系统。比如,
许多的半导体厂商都会在其产品的SDK 包中使用FreeRTOS 操作系统,尤其是涉及Wi-Fi、蓝
牙等这些带协议栈的芯片或模块;著名的GUI 设计软件库TouchGFX 在其软件的应用例程中使
用了FreeRTOS 操作系统;ST 公司也在其STM32Cube 生态系统中加入了对FreeRTOS 操作系
统的支持。
4.资料齐全。在FreeRTOS 操作系统的官网(https://www.freertos.org/)上,提供了大量的
FreeRTOS 操作系统的相关文档及例程源码。但是美中不足的是,提供的文档都是英文文档,查
看这些资料要求有一定的英语功底。
5.可移植性强。FreeRTOS 操作系统支持多种不同架构的不同型号的处理器,比如STM32
系列的F1、F4、F7 和H7 等都可以移植FreeRTOS,这极大的方便了我们学习和使用FreeRTOS
操作系统。

FreeRTOS 的特点

FreeRTOS 操作系统是一个功能强大的RTOS 操作系统,并且能够根据需求进行功能裁剪,
以满足各种环境的要求,FreeRTOS 的特点如下图所示:
HAL库版FreeRTOS(上)_第1张图片

商业许可

FreeRTOS 采用了MIT 开源许可,这允许将FreeRTOS 操作系统用于商业应用,并且不需
要公开源代码。此外,FreeRTOS 还衍生出了另外两个操作系统:OpenRTOS 和SafeRTOS,其
中OpenRTOS 使用了和FreeRTOS 相同的代码,只是OpenRTOS 受商业授权保护,OpenRTOS
的商业许可和FreeRTOS 的MIT 开源许可对比如下表所示:
HAL库版FreeRTOS(上)_第2张图片
SafeRTOS 同样是FreeRTOS 的衍生版本,SafeRTOS 符合工业、医疗、汽车和其他国际安
全标准的严格要求,具有更高的安全性。

磨刀不误砍柴工

查找资料

不管学习什么,第一件事情就是查找资料,可能有的朋友会说“查找资料还不容易吗?打
开搜索引擎直接搜索不就行了。”,虽然这样搜索出来的资料会包含许多不错的内容,比如各种
博客和论坛上的经验贴,但是要从众多资料中找到精华部分,还是需要耗费大量时间的,并且
这些资料也不够权威、不够及时。由于FreeRTOS 的更新速度很快,许多第三方的资料都无法
做到实时更新,顺带一提的是,在笔者编写此教程的时候,FreeRTOS 内核的最新版本是V10.4.6,
本文和本文配套的例程源码都是基于FreeRTOS 内核的V10.4.6 这个版本。因此获取FreeRTOS
最权威、最实时的资料,FreeRTOS 官网是最好的地方,FreeRTOS 的官网网址是
https://www.freertos.org/,打开后如下图所示:
HAL库版FreeRTOS(上)_第3张图片
可以看到FreeRTOS 的官网是全英文的,由此可见英语对一个嵌入式工程师的重要性。
引入眼帘的是底下的两个按钮,分别是“Download FreeRTOS”和“Getting Started”,通过
“Download FreeRTOS”就能够下载到最新发布的FreeRTOS,而右侧的“Getting Started”就是
在FreeRTOS 官网查看在线资料的入口。通过点击“Getting Started”,再点击“Getting started with the FreeRTOS kernel”底下的“Learn More”就能够查看到有关FreeRTOS 内核的在线资料文档了。同时在页面的左侧可以看到FreeRTOS 在线资料的导航栏,如下图所示:

HAL库版FreeRTOS(上)_第4张图片
从上图可以看到,FreeRTOS 的官网提供了大量的在线资料,其中包括了入门FreeRTOS、
FreeRTOS 的官方书籍、FreeRTOS 内核的相关内容、开发文档、次要文档、FreeRTOS 支持的设
备、FreeRTOS API 参考手册、FreeRTOS 的授权说明。“Developer Docs”和“Secondary Docs”
即“开发文档”和“次要文档”是FreeRTOS 官方提供的FreeRTOS 在线文档。在FreeRTOS API
参考手册中详细地介绍了FreeRTOS 中各个API 的使用说明,包括API 函数的参数说明、返回
值说明以及API 用法举例,任意打开一个创建任务的API 函数,如下图所示:
HAL库版FreeRTOS(上)_第5张图片
在这个页面下方,就可以看到“xTaskCreate”这个API 函数详细的用法说明和用法举例,
用法举例的代码如下所示:

/* 被创建的任务*/
void vTaskCode(void * pvParameters) {
        /* 确保传入的参数是1 */
        configASSERT(((uint32_t) pvParameters) == 1);
        for (;;) {
            /* 任务代码*/
        }
    }
    /* 用来创建任务的函数*/
void vOtherFunction(void) {
    BaseType_t xReturned;
    TaskHandle_t xHandle = NULL;
    /* 创建任务*/
    xReturned = xTaskCreate(
        vTaskCode, /* 任务函数*/
        "NAME", /* 任务名*/
        STACK_SIZE, /* 任务堆栈大小,单位:字*/ (void * ) 1, /* 传递给任务函数的参数*/
        tskIDLE_PRIORITY, /* 任务优先级*/ & xHandle); /* 任务句柄*/
    if (xReturned == pdPASS) {
        /* 任务创建完成,使用任务句柄来删除任务*/
        vTaskDelete(xHandle);
    }
}

FreeRTOS 官方文档

如果有接触过µC/OS 的应该都会知道,µC/OS 官方的文档和书籍做得非常好,可以打开
µC/OS 的官网看一下,µC/OS 官网文档和书籍的网址为:https://micrium.atlassian.net/wiki/,打
开后如下图所示:
HAL库版FreeRTOS(上)_第6张图片
从上图可以看到,uC/OS 官方不仅仅提供了uC/OS 的文档和书籍,还提供了各种组件的文
档和书籍,其中就包括uC/CAN、uC/USB-Device、uC/TCP-IP 等,并且大多数书籍都有出售,
具体读者可自行搜索有关在售书籍。
那么问题来了,FreeRTOS 官方的文档和教程怎么样呢?点击刚刚导航栏中的“FreeRTOS
Books”,就能够看到FreeRTOS 的官方文档和配套的源代码,如下图所示:
HAL库版FreeRTOS(上)_第7张图片
从上图可以看到,FreeRTOS 官方提供了两份PDF 文档和一份文档配套的源代码,其中一
份PDF 是FreeRTOS 的教程指南,另一份PDF 是FreeRTOS 的参考手册。相比于uC/OS,
FreeRTOS 官方提供的文档确实有点少。FreeRTOS 官方还提供了两份在线文档,就是刚刚提到
的“Developer Docs”和“Secondary Docs”,以“Developer Docs”为例,在导航栏中点击
Developer Docs,就能看到文档的目录,如下图所示:
HAL库版FreeRTOS(上)_第8张图片

Cortex-M 架构资料

本书是以正点原子的STM32 系列板卡为例,讲解FreeRTOS,在FreeRTOS 的移植,任务
切换的原理中会涉及芯片结构的相关知识,因此需要了解ARM Cortex-M 架构的相关知识。有
本详细地介绍了ARM Cortex-M3 和ARM Cortex-M4 的书籍叫做《The Definitive Guide to ARM Cortex M3 and Cortex M4 Processors, 3rd Edition》,这本书的中文翻译版本为《ARM Cortex-M3
与Cortex-M4 权威指南(第3 版)》,这本书对ARM Cortex-M3 和ARM Cortex-M4 作了非常详
细的介绍,强烈建议想深入了解ARM Cortex 的读者阅读此书,英文原版可以在ARM 官方免费
下载。此书的中文版本如下图所示:
HAL库版FreeRTOS(上)_第9张图片
后面的学习中涉及到ARM Cortex-M 架构的知识均参考自这本书。

FreeRTOS 源码初探

FreeRTOS 源码下载

在上述的几小节中大致地了解了FreeRTOS,知道了什么是FreeRTOS 以及如何获取
FreeRTOS 的官方文档资料。接下来就来看一下FreeRTOS 的源码,在笔者编写此教程的时候,
FreeRTOS 最新发布的版本是v202112.00,FreeRTOS 内核的最新版本是V10.4.6,这里要注意的
是FreeRTOS 和FreeRTOS 内核是两个不同的东西,FreeRTOS 包含了FreeRTOS 内核以及其他
的一些FreeRTOS 组件,v202112.00 版本的FreeRTOS 对应的FreeRTOS 内核版本就是V10.4.6,
本教程主要讲解的是FreeRTOS 内核,因此本教程以及本教程配到的例程源码全部基于
FreeRTOS 内核的V10.4.6 这个版本,为了方面讲解,下文中所有的FreeRTOS 内核都将简称为
FreeRTOS。在FreeRTOS 官网的主页点击“Download FreeRTOS”,即可进入到FreeRTOS 的下
载页面,如下图所示:
HAL库版FreeRTOS(上)_第10张图片
从上图可以看到,FreeRTOS 提供两个版本的FreeRTOS 下载链接,分别为FreeRTOS 和
FreeRTOS LTS,其中FreeRTOS LTS 是FreeRTOS Long Time Support,这个版本的FreeRTOS 会
受官方长期的支持和维护,如果是做产品的话,当然优先选择FreeRTOS LTS,但是就我们学习
而言,当让是选择最新的发布版本FreeRTOS,因此点击图1.3.1.1 中绿色的Download 按钮进行
FreeRTOS 的下载。当然,也可以通过Github 下载,或单独下载V10.4.6 版本的FreeRTOS 内核,
这里为了方便读者理解,下载包含了FreeRTOS 组件的FreeRTOS v202112.00。下载解压后得到
的文件,如下图所示:
HAL库版FreeRTOS(上)_第11张图片
上图展示的就是FreeRTOS 的根目录。各子文件和子文件的的描述如下表所示:
HAL库版FreeRTOS(上)_第12张图片
打开图1.3.1.2 中的FreeRTOS 子文件夹,就能够看到FreeRTOS 内核的文件,如下图所示:
HAL库版FreeRTOS(上)_第13张图片
上图展示的就是FreeRTOS 内核的根目录。接下来就开始介绍FreeRTOS 内核中的文件。

FreeRTOS 文件预览

在1.3.1 小节中,已经获取到了FreeRTOS 的文件,如图1.3.1.3 所示。接下来,在本小节中
就来初步地预览一下FreeRTOS 的文件,大致地看一下FreeRTOS 中都包含了哪些东西。

  1. Demo 文件夹
    Demo 文件夹里面就是FreeRTOS 的演示工程,打开以后如下图所示:
    HAL库版FreeRTOS(上)_第14张图片
    限于篇幅,图1.3.2.1 仅展示了Demo 文件夹中的部分演示工程。从Demo 文件夹中可以看
    出,FreeRTOS 支持多种芯片架构的多种不同型号的芯片,其中就包括了ST 的F1、F4、F7 和
    H7 系列的相关FreeRTOS 演示工程,这对于入门学习FreeRTOS 是十分有帮助的,在学习移植
    FreeRTOS 的过程中就可以参考这些演示工程。
  2. License 文件夹
    License 文件夹中包含了FreeRTOS 的相关许可信息,如果是要使用FreeRTOS 做产品的话,
    就得仔细地看看这个文件夹中的内容。
  3. Source 文件夹
    这个文件夹中的内容就是FreeRTOS 的源代码了,这就是学习和使用FreeRTOS 的重中之重,Source 文件夹打开后如下图所示:
    HAL库版FreeRTOS(上)_第15张图片

图1.3.2.2 中的文件就是FreeRTOS 的源文件了。可以看到,就文件数量而言,FreeRTOS 的
文件数量相对与µC/OS 而言少了不少。Source 文件夹中各文件和文件夹的描述如下表所示:
HAL库版FreeRTOS(上)_第16张图片
可以看到,Source 文件夹中的portable 内包含了FreeRTOS 的移植文件,这些移植文件是
针对不同芯片架构的。FreeRTOS 操作系统归根到底是一个软件层面的东西,那FreeRTOS 是如
何跟硬件联系在一起的呢?portable 文件夹里面的东西就是连接软件层面的FreeRTOS 操作系
统和硬件层面的芯片的桥梁。打开protable 文件夹后,可以看到FreeRTOS 针对不同的芯片架构
和不同的编译器提供了不同的移植文件,由于本文是使用MDK 开发正点原子的STM32 系列板
卡,因此这里只重点介绍其中的部分移植文件,如下图所示:
HAL库版FreeRTOS(上)_第17张图片
首先来看一下Keil 文件夹,打开Keil 文件夹后可以看到,Keil 文件夹中之后一个文件,文
件名为:“See-also-the-RVDS-directory.txt”,看文件名就知道要转到RVDS 文件夹了。接下来打开RVDS 文件夹,如下图所示:

HAL库版FreeRTOS(上)_第18张图片
从图1.3.2.5 中可以看出,FreeRTOS 提供了ARM Cortex-M0、ARM Cortex-M3、ARM Cortex-
M3、ARM Cortex-M7 等内核芯片的移植文件,这里就不再深入了,下文讲解到FreeRTOS 移植
部分的时候再进行详细分析。
最后再来看一下图1.3.2.4 中的MemMang 文件夹,打开MemMang 文件夹后如下图所示:
HAL库版FreeRTOS(上)_第19张图片
MemMang 中的文件是FreeRTOS 提供的用于内存管理的文件,从图1.3.2.6 中可以看到,
MemMang 文件夹中包含了五个C 源文件,这五个C 源文件对应了五种内存管理的方法。这里
暂不对FreeRTOS 提供的内存管理进行深究,下文讲解到FreeRTOS 内存管理的时候再进行详
细分析。

FreeRTOS 移植

在上一章中介绍了FreeRTOS 并获取了FreeRTOS 的源码,接着介绍了FreeRTOS 源码的目
录结构,本章就正式踏上FreeRTOS 的学习之旅。在学习FreeRTOS 之前,需要先做好FreeRTOS
的移植,本文就以正点原子的STM32 系列开发板为例,进行FreeRTOS 的移植。
本章分为如下几部分:
2.1 FreeRTOS 移植
2.2 FreeRTOS 移植实验

FreeRTOS 移植

移植前准备

在开始移植FreeRTOS 之前,需要提前准备好一个用于移植FreeRTOS 的基础工程,和
FreeRTOS 的源码。

  1. 基础工程
    由于本文的后续一些实验当中需要用到LED、LCD、定时器、串口、内存管理等外设及功
    能,因此就以正点原子标准例程-HAL 库版本的内存管理的实验工程为基础工程进行FreeRTOS
    的移植。由于内存管理实验例程的BSP 文件夹中可能不包含定时器的驱动文件,因此如果内存
    管理试验力撑的BSP 文件夹如果不包含TIMER 文件夹的话,需要从定时器相关实验的BSP 文
    件夹中拷贝一份TIMER 到FreeRTOS 移植基础工程当中。
  2. FreeRTOS 源码
    本教程所使用的FreeRTOS 内核源码的版本V10.4.6,即FreeRTOS v202112.00。在第一章
    中已经详细的介绍了如何从FreeRTOS 的官网获取FreeRTOS 的源码,同样的,开发板资料盘中
    也提供了本教程所使用的FreeRTOS 源码,即FreeRTOS v202112.00(FreeRTOS 内核V10.4.6),
    路径为:软件资料→FreeRTOS 学习资料→FreeRTOSv202112.00.zip。

添加FreeRTOS 文件

在准备好基础工程和FreeRTOS 的源码后,接下来就可以开始进行FreeRTOS 的移植了。

  1. 添加FreeRTOS 源码
    在基础工程的Middlewares 文件夹中新建一个FreeRTOS 子文件夹,如下图所示:

HAL库版FreeRTOS(上)_第20张图片

图2.1.2.1 中的FreeRTOS 就是新建的文件夹,这里要说明的是图2.1.2.1 中的其他文件夹为
内存管理实验工程中原本就存在的,对于正点原子的不同STM32 开发板图2.1.2.1 中的文件可
能有所不同,但只需新建一个FreeRTOS 子文件即可。
接着就需要将FreeRTOS 的源代码添加到刚刚新建的FreeRTOS 子文件中了。将FreeRTOS
内核源码的Source 文件夹下的所有文件添加到工程的FreeRTOS 文件夹中,如下图所示:
HAL库版FreeRTOS(上)_第21张图片
图2.1.2.2 中各文件和文件夹的描述在1.3.2 小节中已经说明,对于在正点原子的STM32 系
列开发板上移植FreeRTOS,portable 文件夹中的文件只需要使用到图1.3.2.3 中的三个文件夹,
其余用不到的文件,读者可以自行决定删除与否。
2. 将文件添加到工程
打开基础工程,新建两个文件分组,分别为Middlewares/FreeRTOS_CORE 和
Middlewares/FreeRTOS_PORT,如下图所示:
在这里插入图片描述
Middlewares/FreeRTOS_CORE 分组用于存放FreeRTOS 的内核C 源码文件,将“1. 添加
FreeRTOS 源码”步骤中的FreeRTOS 目录下所有的FreeRTOS 的内核C 源文件添加到
Middlewares/FreeRTOS_CORE 分组中。
Middlewares/FreeRTOS_PORT 分组用于存放FreeRTOS 内核的移植文件,需要添加两个文
件到这个分组,分别为heap_x.c 和port.c。
首先是heap_x.c,在路径FreeRTOS/portable/MemMang 下有五个C 源文件,这五个C 源文
件对应了五种FreeRTOS 提供的内存管理算法,读者在进行FreeRTOS 移植的时候可以根据需
求选择合适的方法,具体这五种内存管理的算法,在后续FreeRTOS 内存管理章节会具体分析,
这里就先使用heap_4.c,将heap_4.c 添加到Middlewares/FreeRTOS_PORT 分组中。
接着是port.c,port.c 是FreeRTOS 这个软件与MCU 这个硬件连接的桥梁,因此对于正点
原子的STM32 系列不同的开发板,所使用的port.c 文件是不同的。port.c 文件的路径在
FreeRTOS/portable/RVDS 下。进入到FreeRTOS/portable/RVDS,可以看到FreeRTOS 针对不同
的MCU 提供了不同的port.c 文件,具体正点原子的STM32 系列开发板与不同port.c 的对应关
系如下表所示:
HAL库版FreeRTOS(上)_第22张图片
只需将开发板芯片对应的port.c 文件添加到Middlewares/FreeRTOS_PORT 分组中即可。
将所有FreeRTOS 相关的所需文件添加到工程后,如下图所示:
HAL库版FreeRTOS(上)_第23张图片
3. 添加头文件路径
接下来添加FreeRTOS 源码的头文件路径,需要添加两个头文件路径,毋庸置疑,其中一
个头文件路径就是FreeRTOS/include,另外一个头文件路径为port.c 文件的路径,根据表2.1.2.4
中不同类型开发板与port.c 文件的对应关系进行添加即可。添加完成后如下图所示(这里以正
点原子的STM32F1 系列开发板为例,其他类型的开发板类似):
HAL库版FreeRTOS(上)_第24张图片
4. 添加FreeRTOSConfig.h 文件
FreeRTOSConfig.h 是FreeRTOS 操作系统的配置文件,FreeRTOS 操作系统是可裁剪的,用
户可以根据需求对FreeRTOS 进行裁剪,裁剪掉不需要用到的FreeRTOS 功能,以此来节约MCU
中寸土寸金的内存资源。那么FreeRTOSConfig.h 文件从哪里来呢?主要有三个途径:
(1) FreeRTOSConfig.h 获取途径一
第一种途径就是用户自行编写,用户可以根据自己的需求编写FreeRTOSConfig.h 对
FreeRTOS 操作系统进行裁剪。FreeRTOS 官网的在线文档中就详细地对FreeRTOSConfig.h 中各个配置项进行了描述,网页链接:https://www.freertos.org/a00110.html。当然,对于FreeRTOS 新
手来说,笔者是不建议自行编写的。
(2) FreeRTOSConfig.h 获取途径二
第二种途径就是FreeRTOS 内核的演示工程,在“1.3.2 FreeRTOS 文件预览”这一小节中,
介绍了Demo 文件夹,Demo 文件夹中包含了FreeRTOS 官方提供的演示工程,在这些演示工程
当中就包含了每个演示工程对应的FreeRTOSConfig.h 文件,需要注意的是,有些演示工程使用
的是老版本的FreeRTOS,因此部分演示工程的FreeRTOSConfig.h 文件并不能够很好的适用于
新版本的FreeRTOS。任意打开其中一个演示工程,如下图所示:

HAL库版FreeRTOS(上)_第25张图片
读者可以在Demo 文件夹中找到与自己所使用芯片相似的演示工程中的FreeRTOSConfig.h
文件,并根据自己的需求,稍作修改。
(3) FreeRTOSConfig.h 获取途径三
第三种途径,也是笔者推荐的。可以从本套教程配套例程“FreeRTOS 移植实验”的User 子
文件夹下找到FreeRTOSConfig.h 文件,这个文件就是参考FreeRTOS 官网中对FreeRTOSConfig.h
文件的描述,并针对正点原子的STM32 系列开发板编写的。这里要说明的是,本套教程是用于
学习FreeRTOS 的,因此在FreeRTOSConfig.h 文件中并没有对FreeRTOS 的功能作过多的裁剪,
大部分的功能都保留了,只不过在后续的部分实验中还需要对FreeRTOSConfig.h 文件作相应的
修改,以满足实验的需求。
本教程就以途径三进行讲解,只需将本套教程配套例程“FreeRTOS 移植实验”User 子文件
夹下的FreeRTOSConfig.h 文件添加到基础工程的User 子目录下即可。这里要注意的是,正点
原子的STM32 系列开发板对应的FreeRTOSConfig.h 文件是不通用的,具体原因在后续分析
FreeRTOSConfig.h 文件的时候会具体地讲解。

修改SYSTEM 文件

SYSTEM 文件夹中的文件一开始是针对µC/OS 编写的,因此使用FreeRTOS 的话,就需要作相应的修改。SYSTEM 文件夹中一共需要修改三个文件,分别是sys.h、usart.c、delay.c。

  1. sys.h 文件
    sys.h文件的修改很简单,在sys.h文件中使用了宏SYS_SUPPORT_OS 来定义是否支持OS,
    因为要支持FreeRTOS,因此应当将宏SYS_SUPPORT_OS 定义为1,具体修改如下所示:
/**
* SYS_SUPPORT_OS用于定义系统文件夹是否支持OS
* 0,不支持OS
* 1,支持OS
*/
#define SYS_SUPPORT_OS 1
  1. usart.c 文件
    usart.c 文件的修改也很简单,一共有两个地方需要修改,首先就是串口的中断服务函数,
    原本在使用µC/OS 的时候,进入和退出中断需要添加OSIntEnter()和OSIntExit()两个函数,这
    是µC/OS 对于中断的相关处理机制,而FreeRTOS 中并没有这种机制,因此将这两行代码删除,
    修改后串口的中断服务函数如下所示:
    正点原子STM32F1 系列:
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) /* 重新开启中断并接收数据*/ {
        /* 如果出错会卡死在这里*/
    }
}

正点原子STM32F4/F7/H7 系列:

void USART_UX_IRQHandler(void) {
    uint32_t timeout = 0;
    uint32_t maxDelay = 0x1FFFF;
    HAL_UART_IRQHandler( & g_uart1_handle); /* 调用HAL库中断处理公用函数*/
    timeout = 0;
    while (HAL_UART_GetState( & g_uart1_handle) != HAL_UART_STATE_READY) /* 等待就绪*/ {
        timeout++; /* 超时处理*/
        if (timeout > maxDelay) {
            break;
        }
    }
    timeout = 0;
    /* 一次处理完成之后,重新开启中断并设置RxXferCount为1 */
    while (HAL_UART_Receive_IT( & g_uart1_handle, (uint8_t * ) g_rx_buffer,
            RXBUFFERSIZE) != HAL_OK) {
        timeout++; /* 超时处理*/
        if (timeout > maxDelay) {
            break;
        }
    }
}

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

/* 如果使用os,则包括下面的头文件即可. */
#if SYS_SUPPORT_OS
#include "includes.h" /* os 使用*/
#endif
  1. delay.c 文件
    接下来修改SYSTEM 文件夹中的最后一个文件——delay.c,delay.c 文件需要改动的地方比
    较多,大致可分为三个步骤:删除适用于µC/OS 但不适用于FreeRTOS 的相关代码、添加
    FreeRTOS 的相关代码、修改部分内容。
    (1) 删除适用于µC/OS 但不适用于FreeRTOS 的相关代码
    一共需要删除1 个全局变量、6 个宏定义、3 个函数,这些要删除的代码在使用µ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()
函数delay_init() 主要用于初始化SysTick 。这里要说明的是,在后续调用函数
vTaskStartScheduler()(这个函数在下文中讲解到FreeRTOS 任务调度器的时候会具体分析)的
时候,FreeRTOS 会按照FreeRTOSConfig.h 文件的配置对SysTick 进行初始化,因此delay_init()
函数初始化的SysTick 主要使用在FreeRTOS 开始任务调度之前。函数delay_init()要修改的部分
主要为SysTick 的重装载值以及删除不用的代码,代码修改如下:
正点原子STM32F1 系列:

你可能感兴趣的:(STM32,stm32,mcu)