STM32之FreeRTOS移植(重点)
- RTOS的基本概念
实时操作系统(Real Time Operating System)的简称就叫做RTOS,是指具有实时性、能支持实时控制系统工作的操作系统,RTOS的首要任务就是调度所有可以利用的资源来完成实时控制任务的工作,其次才是提高工作效率。
绝大多数比较简单的产品(中小型产品)是直接在单片机上“裸奔”的,也就是产品不需要搭载RTOS的,但是产品的各个功能想要正常工作都需要主程序来进行调度。
其实RTOS就是一段嵌入在程序中的代码,在系统上电复位后首先被执行,可以理解为用户的主程序,只不过用户把产品的其他功能(子程序)都建立在RTOS之上,在RTOS中可以调用API函数为每个子程序都创建一个任务(也可以叫做线程),用户只需要调用RTOS内核中的相关的API函数接口就可以控制子程序,而且可以为每个任务设置不同的优先级,通过RTOS的调度器进行调度,这样就可以合理的使用CPU。
这里就涉及到产品的设计思路(裸机开发 or RTOS)以及程序的运行方式,可以分为三种:
- 轮询式
轮询系统指的是程序运行时,先初始化各种硬件,初始化硬件之后程序进入一个死循环中,按照事件的顺序进行执行,该系统的结构非常简单,只适用于按照顺序执行事件并且没有外部事件来打断的情况,轮询系统就非常可靠,但是一旦有外部事件或者外部需要检测的信号来打断,则会造成外部事件的缺失。
int main(){//硬件的初始化while(1){//事件1 LED//事件2 BEEP//....... KEY}}
- 前后台
前后台系统就是在轮询系统的基础上增加了中断,进行外部事件检测的时候就在中断中实现,所以中断也被称为前台,而其他事件还是在主程序的死循环中按照顺序执行,一旦中断发生,则会暂停执行后台的while(1),然后去执行前台的中断服务函数,如果事件简短,直接在中断中实现,如果事件复杂,则返回主程序的死循环实现,该方案可以提高程序的实时响应能力。
int main(){//硬件的初始化//注册中断,设置中断的触发条件while(1){//事件1//事件2.....}}//中断服务函数void XXX_IRQ (void){//执行中断的事件//执行完成返回main函数}
- 多任务
多任务系统指的是在前后台系统的基础上执行外部事件,只不过外部事件是放在任务中执行,不在中断服务函数中执行,一旦某个外部事件满足触发条件,就在中断服务函数中设置事件标志,然后在跳转到任务中执行事件,任务分优先级的,优先级高的任务就先执行,所以程序就会被分割为一个个的任务(不能退出),每个任务都有一个独立的函数来执行的功能。更大程序提高程序的实时性。
void task1(void *arg){while(1){//LED}}void task2(void *arg){while(1){//BEEP}}int main(){//硬件的初始化//注册中断,设置中断的触发条件//注册任务,根据任务调度器进行调度}
- RTOS的种类
RTOS是实时操作系统的统称,不意味着是某一种确定的操作系统,而是指某一类操作系统,比如最常用的uC/OSII、uC/OSIII、FreeRTOS、RTX、RT-Thread、Huawei LiteOS........每种RTOS各有特色,所以大家可以根据实际需要选择对应的RTOS进行学习。
- uC/OS
uC/OS是Micrium公司推出的RTOS实时操作系统,分为两个版本: uC/OSII 和 uC/OSIII,该RTOS的特点是开源的、可裁剪的、具有可剥夺型内核,uC/OSII可以支持创建最多255个任务,而uC/OSIII对任务数量没有限制。
uC/OS的发布时间是较早的,所以中文资料是最多的,并且代码例程比较丰富,但是想要在商业中进行使用,需要取得正版授权(花钱),所以大家可以把UCOS作为RTOS的入门。关于uC/OS的资料和源码都可以去官网下载 官网地址:www.micrium.com
- FreeRTOS
FreeRTOS也是RTOS的一种,在2003年发布,是免费的,虽然起步比UCOS晚,但是由于可以在商业中免费使用,所以目前的市场占有率是最高的,并且很多的半导体公司都和FreeRTOS有很紧密的合作关系,这些半导体公司的评估板绝大多数都是采用FreeRTOS进行程序设计。比如半导体公司发布的SDK(开发工具包)一般也采用FreeRTOS,另外,像蓝牙、WIFI等带协议栈的芯片或者模块也是采用FreeRTOS。
相比于UCOS而言,FreeRTOS的文件数量更少,占用内存空间更少,所以在移植到不同硬件平台的时候更加轻松,FreeRTOS对于任务数量也是没有限制的,而是对于任务的优先级也没有限制。
FreeRTOS支持抢占式、时间片调度等算法,而且FreeRTOS是完全免费的,这也是FreeRTOS的核心竞争力。
FreeRTOS可以用在商业领域,不具有版权问题,如果在产品中使用FreeRTOS时没有修改原码,则产品不需要开源,如果使用FreeRTOS的过程修改了原码,则需要把修改的那部分代码进行开源,遵循MIT开源协议。
大家可以去FreeRTOS的官网下载源码以及其他的资料,比如FreeRTOS提供了若干本书籍,比如关于RTOS的API函数的参考手册以及新手教程。 官网地址:www.freertos.org
- RT-Thread
长期作业:自行观看RT-Thread的相关视频和教程,要求大家可以自行完成Rt-thread的移植。
- RTOS的源码下载
想要真正掌握RTOS,则必须要去阅读RTOS的源码,才能理解RTOS是如何对任务进行调度
可以去FreeRTOS的官网下载源码。
- 点击选项链接跳转GitHub托管网站,下载FreeRTOS以前的发行源码包, 比如 V9.0.0
- 点击GitHub的标签tags,显示所有的FreeRTOS的源码发行版,搜索到V9.0.0版本即可
注意:如果浏览器在登录GitHub网站时等待时间过长,或者无法登录界面,则可以使用其他的代码托管网站进行源码下载,比如Sourceforge代码托管网站 ,搜索FreeRTOS即可。
- RTOS源码结构
解压好的源码包内部有一个叫做FreeRTOS的文件夹,该文件夹内部包含FreeRTOS的源码以及许可和通用的头文件,并且还提供丰富的案例供用户在不同的硬件平台使用。
Demo中提供了很多个半导体公司的评估板的代码例程,用户可以参考甚至直接使用。而License文件夹中包含了FreeRTOS的许可文件,大家可以在商业软件中进行参考,在Source文件夹中包含通用的头文件以及针对不同硬件平台的移植文件供用户使用。
五、FreeRTOS的移植
如果想要在项目中利用RTOS对任务进行调度,则需要把RTOS的源码移植到自己的项目中,移植的步骤如下:
- 去FreeRTOS的官网下载源码包,源码包的版本可以是V9.0.0或更新的版本 (比较稳定)
- 把源码包解压到本地,分析源码包中哪些文件需要移植,可以浏览源码包的readme.txt
- 把FreeRTOS源码包中需要移植的文件拷贝到自己工程中对应的文件夹,操作如下所示:
- 打开自己的工程,把拷贝过来文件添加到KEIL5工程中,编辑文件夹的结构,如下所示
- 配置KEIL5工程的头文件的路径,确保编译器可以找到关于FreeRTOS的头文件,如下:
- 编译工程,如果编译之后报错,根据错误原因解决错误,直到编译通过为止,如下所示
- 提示:__ICCARM__宏定义是和开发工具相关的,该宏定义是IAR软件需要使用的,而目前采用的开发工具是KEIL,KEIL软件需要使用其他的宏定义。
再次编译,发现有函数出现重复定义的情况,port.c和stm32f4xx_it.c中出现,所以可以选择分别进行分析,可以把stm32f4xx_it.c中的函数名称删除即可。
再次编译,发现有5个函数未定义,命名规则是有规律的,都是HooK结尾,Hook是钩子函数,其实属于回调函数的一种,目前由于不知道是否需要使用,可以选择不去定制。
由于FreeRTOS是高度可定制的,定制的功能是由FreeRTOSConfig.h决定,所以需要配置该头文件,裁剪掉这几个功能即可。
再次编译,发现没有出现任何错误和任何警告,则说明FreeRTOS实时操作系统移植成功!!
五、FreeRTOS的任务管理
- 任务的概念
FreeRTOS是一个支持多任务的实时操作系统,如之前裸机开发时采用的轮询系统而言,主程序是一个死循环,CPU按照死循环中的流程执行代码,而在多任务系统中,用户可以把整个系统分割为多个独立的且不能返回(死循环)的函数,这些函数就被称为任务。
应用程序中的任务都是由FreeRTOS的调度器进行调度,同时每个任务具有独立的栈空间,栈空间其实就是单片机中RAM的一段空间,通常可以提前定义一个全局数组,或者在创建任务的时候对任务的栈空间进行动态的分配,可以参考FreeRTOS的官方资料。
- 任务的状态
对于FreeRTOS中的任务而言,FreeRTOS的调度器会根据任务的状态决定运行哪个任务,任务的状态一共有四种:运行态、就绪态、挂起态、阻塞态。 可以参考FreeRTOS的官网资料。
- 任务优先级
FreeRTOS可以为每一个创建的任务分配一个优先级,当然也可以让多个任务共用一个优先级,这里就涉及到调度器的调度算法,有抢占式、时间片一共2种算法。
- 任务的创建
刚才提到过任务都是独立的,并且每个任务都需要占用一部分RAM空间,单片机中的RAM是有限的,所以FreeRTOS就提供了两种方案为每个任务分配栈空间:静态分配 + 动态分配,而且FreeRTOS提供了不同的函数接口给用户去申请任务的空间。两种分配方案的区别如下:
一般情况下采用动态分配的方案,所以需要调用API函数,名字叫做xTaskCreate(),如下图
- 启动调度器
- 任务的删除
FreeRTOS中的任务是可以删除的,如果用户创建的任务只打算运行一次就可以删掉,调用函数接口 vTaskDelete() ,调用该函数就可以把动态创建或者静态创建的任务从任务表中删掉。
- 任务的挂起
在某些情况下,某些任务可能只运行一段时间,然后让任务暂停运行,过一段时间继续运行,如果采用反复删除和反复创建的方案,就会导致任务之前的数据丢失,FreeRTOS提供一个函数可以把任务挂起,该函数为vTaskSuspend() 。
一旦任务被挂起,则不管任务的优先级是否为最高,都不会获得CPU资源,也就是说处于挂起态的任务永远不能进入运行态,除非该任务被恢复,如果想要恢复一个任务,则需要调用vTaskResume()。
- 任务的恢复
FreeRTOS提供了一个恢复函数,可以让处于挂起态的任务恢复,注意只有被挂起的任务才可以被恢复。