FreeRTOS-基本介绍和STM32移植
一、裸机开发和操作系统开发介绍
- 裸机:前后台系统,前台系统指的是中断服务函数,后台系统指的是大循环,即应用程序
- 特点:实时性差、delay(浪费资源)、结构臃肿(实现功能都放在无限循环)
- FreeRTOS开发:实时操作系统,强调的是实时性
- 特点:分而治之(实现功能划分为多个任务)、延时函数(不会空等待,会让出CPU的使用权给其他任务,即任务调度)、抢占式(高优先级任务抢占低优先级)、任务堆栈(每个任务都有自己的栈空间,用于保存局部变量以及任务的上下文信息)
二、任务调度和任务状态介绍
2.1 任务调度
- 任务调度器就是决定在某一个时刻调用哪一个任务,切换速度很快,造成在同一时刻有多个任务在运行的错觉
- 抢占式调度:针对优先级不同的任务,优先级高的可以抢占低优先级的任务
- 时间片调度:针对优先级相同的任务,在每一次系统时钟节拍到的时候切换任务
- 协程式调度:当前正在执行任务一直在执行,同时高优先级的任务不会抢占低优先级任务(不常用)
2.1.1 抢占式调度
- 运行条件:三个任务Task1、Task2和Task3,在FreeRTOS中任务设置的数值越大,优先级越高
高优先级任务,优先执行。高优先级任务不停止,低优先级任务无法执行。被抢占的任务会进入就绪态
2.1.2 时间片调度
- 同优先级任务轮流地享有相同的CPU时间(可设置),叫时间片,在FreeRTOS中,一个时间片就等于SysTick中断周期
同等优先级任务,轮流执行,时间片流转。一个时间片大小,取决为滴答定时器中断周期。注意没有用完的时间片不会再使用(阻塞-直接切换到下一个任务),下次任务Task3得到执行还是按照一个时间片的时钟节拍运行
2.2 任务状态
-
FreeRTOS中任务共存在4种状态:运行态、就绪态、阻塞态和挂起态
-
运行态:正在执行的任务,该任务就处于运行态,注意在STM32种,同一时间仅一个任务处于运行态
-
就绪态:如果该任务已经能够被执行,但当前还未被执行,那么该任务处于就绪态
-
阻塞态:如果一个任务因延时或者等待外部事件发生,那么这个任务就处于阻塞态
-
挂起态:类似暂停,调用函数vTaskSuspend()进入挂起态,需要调用解挂函数vTaskResume()才可以进入就绪态
-
下图为四种任务状态间的转换图
-
仅就绪态可以转变为运行态。其他状态想运行,必须先转变为就绪态
- 四种状态中,除了运行态,其他三种任务状态的任务都有其对应的任务状态列表(链表)
- 就绪列表:pxReadyTaskList[x],其中x代表任务优先级数值0-31
- 阻塞列表:pxDelayTaskList
- 挂起列表:xSuspendedTaskList
调度器总是在所有处于就绪列表的任务中,选择具有最高优先级的任务来执行。如果优先级一致,那么相同优先级的任务会连接在同一个就绪列表上,按照时间片轮流执行
三、FreeRTOS源码和移植STM32
3.1 FreeRTOS源码
- 从官网下载FreeRTOS源码,文件夹内容如下所示
- 打开内核文件夹
- 打开FreeRTOS源码文件夹
- FreeRTOS操作系统归根结底是一个软件层面的东西,FreeRTOS是如何跟硬件联系在一起,portable文件夹里的东西就是接口文件,使用Keil-MDK开发,需要使用Keil、RVDS和MemMang文件夹部分内容
3.2 FreeRTOS移植STM32
3.2.1 代码移植
-
以STM32F103C8T6单片机为例移植FreeRTOS,移植步骤如下
-
将STM32工程文件全部复制到FreeRTOS目录下,并新建FreeRTOS文件夹存放源码
- 将FreeRTOS源码文件夹复制到移植模板内
- 删除源码中多余的文件,保留接口3个文件夹
- 在FreeRTOS文件夹内新建FreeRTOS_core、FreeRTOS_port文件夹,分别用于存放FreeRTOS内核文件和接口文件(不同的平台文件不一样)
- 如下文件添加到FreeRTOS_core内核文件夹中,包括.c和所有.h文件
- 如下文件添加到FreeRTOS_port接口文件夹中
- STM32F103系列单片机为M3内核
- 在Keil里面包含头文件所在路径
- 将官方demo里面的FreeRTOSConfig.h添加到FreeRTOS_core内核文件夹中
- FreeRTOSConfig.h作用:对FreeRTOS进行功能配置和裁剪(config),以及API函数(INCLUDE)的使能,其他配置项(PendSV、SVC宏定义)
- 最后保留FreeRTOS_core、FreeRTOS_port文件夹即可
3.2.2 时钟中断配置
- SysTick是FreeRTOS的心跳时钟,驱动FreeRTOS运行,在SysTick时钟的节拍下进入中断函数,每次中断都会引发任务调度
- 在stm32f10x_it.c里的SysTick_Handler()中断里添加函数内容,并加上头文件
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
xPortSysTickHandler();
}
- 在FreeRTOSConfig.h里添加函数宏定义,使用官方的中断函数,
- 注释掉stm32f10x_it.c里的PendSV_Handler()函数和SVC_Handler()函数,避免重定义
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
- 如果遇到xTaskGetSchedulerState()函数未定义或其他可选函数未编译的情况下,需要改其宏定义为1,或者在FreeRTOSConfig.h里添加宏定义为1
- xTaskGetSchedulerState()函数是一个可选函数,当宏定义为1时可以编译