(一)多任务系统
1. 单任务系统
在使用C51系列、STM32等单片机进行裸机编程时,大都在main函数中写一个while或者for死循环函数,用来无限轮询任务函数。很多时候会加入硬件中断来完成一些功能处理。相对于多任务系统来说,这种轮询系统就是单任务系统,也称作前后台系统。中断服务函数为前台系统,轮询为后台系统。
前后台系统的缺点:实时性差;除中断之外的所有任务都排队轮流执行,处理器的性能好的话,轮询的速度就会快些,要是处理器性能比较差并且代码很多的话,系统就会比较慢。优点:系统简单、消耗资源小。
2. 多任务系统
多任务系统会将任务并发处理(不意味着同一时刻能够多任务一起执行,并且MCU就一个核),由于每个任务所占用的CPU时间很短,可以看做是多任务在一起执行。在RTOS中任务调度器起了关键性的作用,负责任务的调度。FreeRTOS是一个抢占式的实时多任务系统,其任务调度器也是抢占式的。具体运行过程如下图所示:
3. FreeRTOS任务与协程
在FreeRTOS中任务和协程均可使用,但两者使用的是不同的API函数,因此不能通过队列(或信号量)将数据从任务发送给协程,反之依然。协程是专门为资源很少的MCU准备的。
(1)任务特性
在RTOS中,每一个任务都有自己的运行环境,不依赖于系统中的其它任务或者RTOS调度器。任何一个时间点,只能同时运行一个任务。任务调度器的主要任务是决定哪个任务运行。任务调度器确保一个任务的开始执行时的系统环境(寄存器值,堆栈内容等)和上一次任务退出时保持一致。因此,每个任务都有堆栈,用于保存任务切换时的上下文环境。
任务特性:
- 简单。
- 没有使用限制。
- 支持抢占。
- 支持优先级。
- 每个任务都拥有堆栈导致RAM使用量增大。
- 如果使用抢占的话,必须仔细考虑重入问题。
(2)协程特性
协程与任务在概念上是相似的,但存在一下几点不同:
- 堆栈的使用 -
所有的协程使用同一个堆栈,比任务消耗更小的RAM。 - 调度器和优先级
协程使用合作式调度器,但可以在抢占式调度其中使用协程。 - 宏实现
协程是通过宏定义来实现的。 - 使用限制
为了降低对RAM的消耗做了很多的限制。
(3)任务状态
- 运行态
任务正在运行的状态。
- 就绪态
处于就绪态的任务(没有被阻塞或挂起)是已经准备就绪、可以运行的任务,但还没有正式运行,主要由于当前系统正在运行的同一优先级或者更高优先级的任务。
- 阻塞态
任务当前正在等待某个外部事件时,就处于阻塞态。例如,某任务调用vTaskDelay()函数,进入阻塞态,等待延时完成。任务在等待队列、信号量、事件组、通知或互斥信号量时也会进入阻塞态。任务进入阻塞态会有一个超时时间,当超过这个超时时间,任务就会退出阻塞态,即使等待的事件还没有触发。
- 挂起态
任务进入挂起态后不能被任务调度器调用进入运行态,且没有超时时间。任务进入和退出挂起态通过调用函数vTaskSuspend()和xTaskResume()。
任务状态之间的转换如下图所示:
(4)任务优先级
每个任务都可以分配一个从 0 ~ (configMAX_PRIORITIES - 1) 的优先级。configMAX_PRIORITIES 宏定义在FreeRTOSConfig.h头文件中有定义。一般情况下configMAX_PRIORITIES 可以设置为任意值,但是考虑到RAM的消耗,最好设置为一个满足应用的最小值。
注意:如果硬件平台支持类似计算前导零这样的指令(可以通过该指令选择下一个要运行的任务),并且宏configUSE_PORT_OPTIMISED_TASK_SELECTION也设置为1后,那么宏configMAX_PRIORITIES 不能超过32,即优先级不能超过32级。
优先级数字越小表示的优先级越