FreeRTOS
系统的核心是任务管理,
学习
RTOS
系统的工程师是为了使用 RTOS
的多任务处理功能,初步上手
RTOS
系统首先必须掌握的是任务的创建、删除、挂起和恢复等操作。
1.单任务系统(前后台系统)
回想一下我们以前在使用
51
、
AVR
、
STM32
单片机裸机
(
未使用系统
)
的时候一般都是在main 函数里面用
while(1)做一个大循环来完成所有的处理,即应用程序是一个无限的循环,循环中调用相应的函数完成所需的处理。有时候我们也需要中断中完成一些处理。相对于多任务系统而言,这个就是单任务系统,也称作前后台系统,中断服务函数作为前台程序,大循环while(1)作为后台程序,前后台系统的实时性差,前后台系统各个任务(应用程序)都是排队等着轮流执行,不管你这个程序现在有多紧急,没轮到你就只能等着!相当于所有任务(应用程序)的优先级都是一样的。前后台系统简单啊,资源消耗也少!但是在稍微大一点的嵌入式应用中前后台系统就明显力不从心了,此时就需要多任务系统出马了。
2.多任务系统
多任务系统会把一个大问题
(
应用
)
“分而治之”,把大问题划分成很多个小问题,逐步的把小问题解决掉,大问题也就随之解决了,这些小问题可以单独的作为一个小任务来处理。这些小任务是并发处理的,注意,并不是说同一时刻一起执行很多个任务,而是由于每个任务执行的时间很短,导致看起来像是同一时刻执行了很多个任务一样。多个任务带来了一个新的问题,究竟哪个任务先运行,哪个任务后运行呢?完成这个功能的东西在 RTOS
系统中叫做任务调度器。不同的系统其任务调度器的实现方法也不同,比如 FreeRTOS
是一个抢占式的实时多任务系统,那么其任务调度器也是抢占式的,运行过程如下图
高优先级的任务可以打断低优先级任务的运行而取得
CPU
的使用权,这样就保证了那些紧急任务的运行。这样我们就可以为那些对实时性要求高的任务设置一个很高的优先级,比如自动驾驶中的障碍物检测任务等。高优先级的任务执行完成以后重新把 CPU
的使用权归还给低优先级的任务,这个就是抢占式多任务系统的基本原理。
3.
任务
(Task)
的特性
在使用
RTOS
的时候一个实时应用可以作为一个独立的任务。每个任务都有自己的运行环境,不依赖于系统中其他的任务或者RTOS
调度器。任何一个时间点只能有一个任务运行,具体运行哪个任务是由 RTOS
调度器来决定的,
RTOS
调度器因此就会重复的开启、关闭每个任务。任务不需要了解 RTOS
调度器的具体行为,
RTOS
调度器的职责是确保当一个任务开始执行的时候其上下文环境(
寄存器值,堆栈内容等
)
和任务上一次退出的时候相同。为了做到这一点,每个任务都必须有个堆栈,当任务切换的时候将上下文环境保存在堆栈中,这样当任务再次执行的时候就可以从堆栈中取出上下文环境,任务恢复运行。
任务特性:
1
、简单。
2
、没有使用限制。
3
、支持抢占
4
、支持优先级
5
、每个任务都拥有堆栈导致了
RAM
使用量增大。
6
、如果使用抢占的话的必须仔细的考虑重入的问题。
4.
协程
(Co-routine)
的特性
协程是为那些资源很少的
MCU
而做的,但是随着
MCU
的飞速发展,性能越来越强大,现在协程几乎很少用到了!但FreeRTOS
目前还没有把协程移除的计划,但是
FreeRTOS
是绝对不会再更新和维护协程了,因此协程大家了解一下就行了。在概念上协程和任务是相似的,但是有如下根本上的不同:
1、堆栈使用
所有的协程使用同一个堆栈
(
如果是任务的话每个任务都有自己的堆栈
)
,这样就比使用任
务消耗更少的
RAM
。
2、调度器和优先级
协程使用合作式的调度器,但是可以在使用抢占式的调度器中使用协程。
3、宏实现
协程是通过宏定义来实现的。
4、使用限制
为了降低对
RAM
的消耗做了很多的限制。
5.
任务状态
FreeRTOS
中的任务永远处于下面几个状态中的某一个:
● 运行态
当一个任务正在运行时,那么就说这个任务处于运行态,处于运行态的任务就是当前正在使用处理器的任务。如果使用的是单核处理器的话那么不管在任何时刻永远都只有一个任务处于运行态。
● 就绪态
处于就绪态的任务是那些已经准备就绪
(
这些任务没有被阻塞或者挂起
)
,可以运行的任务,但是处于就绪态的任务还没有运行,因为有一个同优先级或者更高优先级的任务正在运行!
● 阻塞态
如果一个任务当前正在等待某个外部事件的话就说它处于阻塞态,比如说如果某个任务调用了函数 vTaskDelay()
的话就会进入阻塞态,直到延时周期完成。任务在等待队列、信号量、事件组、通知或互斥信号量的时候也会进入阻塞态。任务进入阻塞态会有一个超时时间,当超过这个超时时间任务就会退出阻塞态,即使所等待的事件还没有来临!
● 挂起态
像阻塞态一样,任务进入挂起态以后也不能被调度器调用进入运行态,但是进入挂起态的任务没有超时时间。任务进入和退出挂起态通过调用函数 vTaskSuspend()
和
xTaskResume()
。
任务状态之间的转换如图
6.任务优先级
每 个 任 务 都 可 以 分 配 一 个 从
0~(configMAX_PRIORITIES-1)
的 优 先 级 ,configMAX_PRIORITIES 在文件
FreeRTOSConfig.h
中有定义,前面我们讲解
FreeRTOS
系统配置的时候已经讲过了。如果所使用的硬件平台支持类似计算前导零这样的指令(
可以通过该指令选择下一个要运行的任务 ,Cortex-M
处 理 器 是 支 持 该 指 令 的
)
,并且宏 configUSE_PORT_OPTIMISED_TASK_SELECTION 也设置为了1 , 那 么 宏 configMAX_PRIORITIES 不能超过 32
!也就是优先级不能超过
32
级。其他情况下宏configMAX_PRIORITIES 可以为任意值,但是考虑到
RAM
的消耗,宏
configMAX_PRIORITIES最好设置为一个满足应用的最小值。优先级数字越低表示任务的优先级越低,0
的优先级最低,
configMAX_PRIORITIES-1
的优先级最高。空闲任务的优先级最低,为 0
。FreeRTOS调度器确保处于就绪态或运行态的高优先级的任务获取处理器使用权,换句话说就是处于就绪态的最高优先级的任务才会运行。当宏 configUSE_TIME_SLICING
定义为
1
的时候多个任务可以共用一个优先级,数量不限。默认情况下宏 configUSE_TIME_SLICING
在文件FreeRTOS.h 中已经定义为
1
。此时处于就绪态的优先级相同的任务就会使用时间片轮转调度器获取运行时间。