freeRTOS中文实用教程1--任务
1.前言
FreeRTOS是小型多任务嵌入式操作系统,硬实时性。本章主要讲述任务相关特性及调度相关的知识。
2. 任务的总体特点
- 任务的状态
(1)任务有两个状态,运行态和非运行态
(2)任务由非运行态转入运行态为切入,相反为切出
- 设置优先级
(1)最高优先级在FreeRTOSConfig.h 中 设 定 的 编 译 时 配 置 常 量configMAX_PRIORITIES中进行设置。
注:FreeRTOS 本身并没有限定这个常量的最大值,但这个值越大,则内核花销的内存空间就越多。建议将此常量设为能够用到的最小值(2)任意数量的任务可以共享同一个优先级也可以为每个任务唯一指定一个优先级
(3)低优先级号表示任务的优先级低
(4)有效的优先级号范围从 0 到(configMAX_PRIORITES – 1)
(5)调度器保证总是在所有可运行的任务中选择具有最高优先级的任务,并使其进入运行态
(6)如果被选中的优先级上具有不止一个任务,调度器会让这些任务轮流执行(7)调度器总是选择所有能够进入运行态的任务中具有最高优先级的任务
- 改变任务优先级
可以通过vTaskPrioritySet() 来改变任务的优先级
- 任务时间片
(1)两个任务被创建在同一个优先级上,并且一直是可运行的。所以每个任务都执行一个”时间片”,任务在时间片起始时刻进入运行态,在时间片结束时刻又退出运行态
(2)调度器需要在每个时间片结束时能够调度自己, tick中断可以完成此目的
(3)tick中断频率可以通过FreeRTOSConfig.h 中的编译时配置常量configTICK_RATE_HZ 进行配置,如设为100HZ,则时间片长度为10ms
3.任务状态机
3.1 任务状态机

图 完整的任务状态机
- 阻塞态(blocked)
(1)如果一个任务正在等待某个事件,则称这个任务处于”阻塞态(blocked)”。阻塞态是非运行态的一个子状态。
(2)任务进入阻塞态一般等待以下两种事件:定时事件和同步事件
(3)任务可以在进入阻塞态等待同步事件时指定一个等待超时时间,这样可以有效地实现阻塞状态下同时等待两种类型的事件,
比如说,某个任务可以等待队列中有数据到来,但最多只等10ms。如果10ms 内有数据到来,或是10ms 过去了还没有数据到来,这两种情况下该任务都将退出阻塞态。
- 挂起状态(suspended)
(1)处于挂起状态的任务对调度器而言是不可见的
(2)让一个任务进入挂起状态的唯一办法就是调用vTaskSuspend() API 函数
(3)把一个挂起状态的任务唤醒的唯一途径就是调用vTaskResume() 或TaskResumeFromISR() API 函数
(4)大多数应用程序中都不会用到挂起状态
- 就绪状态(ready)
(1)如果任务处于非运行状态,但既没有阻塞也没有挂起,则这个任务处于就绪(ready,准备或就绪)状态
(2)处于就绪态的任务能够被运行,但只是”准备(ready)”运行,而当前尚未运行
3.2.利用阻塞态实现延迟
void vTaskDelay( portTickType xTicksToDelay );
调用上面的函数的任务会进入阻塞态,xTicksToDelay表示delay的tick周期数,portTICK_RATE_MS代表每毫秒有多少个tick周期
4. 空闲任务
- 空闲任务的特点
(1)在调度器启动的时候vTaskStartScheduler会自动创建一个空闲任务
(2)空闲任务具有最低的优先级0,保证不会影响其它更高优先级的任务进入就绪态
(3)运行在最低优先级可以保证一旦有更高优先级的任务进入就绪态,空闲任务就会立即切出运行态
(4)空间任务可以获得的执行时间量,是系统处理能力裕量的一个度量指
- 空闲任务钩子函数
(1)通过空闲任务钩子函数(或称回调,hook, or call-back),可以直接在空闲任务中添加应用程序相关的功能,空闲任务钩子函数会被空闲任务每循环一次就自动调用一次
(2)空闲任务钩子函数被用于:
---执行低优先级,后台或需要不停处理的功能代码。
---测试系统处理裕量
---将处理器配置到低功耗模式——提供一种自动省电方法,使得在没有任何应用功能需要处理的时候,系统自动进入省电模式。
- 空闲任务钩子函数必须遵从以下规则
(1)绝不能阻塞或挂起。
空闲任务只会在其它任务都不运行时才会被执行(除非有应用任务共享空闲任务优先级)。
以任何方式阻塞空闲任务都可能导致没有任务能够进入运行态!
(2)如果应用程序用到了vTaskDelete() 函数,则空闲钩子函数必须能够尽快返回。因为在任务被删除后,空闲任务负责回收内核资源。如果空闲任务一直运行在钩子函数中,则无法进行回收工作。
5.任务的调度
- 优先级抢占式调度
每个任务都被赋予了一个优先级,这个优先级不能被内核本身改变(只能被任务修改)。
”抢占式”是指当任务进入就绪态或是优先级被改变时,如果处于运行态的任务优先级更高,则该任务总是抢占当前运行的任务
单调速率调度
单调速率调度(Rate Monotonic Scheduling, RMS)是一种常用的优先级分配技术。其根据任务周期性执行的速率来分配一个唯一的优先级。
具有最高周期执行频率的任务赋予高最优先级;具有最低周期执行频率的任务赋予最低优先级。这种优先级分配方式被证明了可以最大化整个应用程序的可调度性(schedulability),但是运行时间不定以及并非所有任务都具有周期性,会使得对这种方式的全面计算变得相当复杂
协作式调度
只可能在运行态任务进入阻塞态或是运行态任务显式调用 taskYIELD()时,才会进行上下文切换。
任务永远不会被抢占,而具有相同优先级的任务也不会自动共享处理器时间。协作式调度的这作工作方式虽然比较简单,但可能会导致系统响应不够快
- 混合调度
这需要在中断服务例程中显式地进行上下文切换,从而允许同步事件产生抢占行为,但时间事件却不行。
这样做的结果是得到了一个没有时间片机制的抢占式系统。或许这正是所期望的,因为获得了效率,并且这也是一种常用的调度器配置
6.任务调度举例
- 两个优先级相同的任务时间片执行图如下:

图 优先级相同的两个任务的时间片执行序列
- 加入了tick中断及tick中断调度器调度下个任务图示如下:

图 对执行流程进行扩展以显示tick中断的执行
- 由于task2比task1优先级高,因此task1永远得不到执行:

图 Task2比Task1优先级高时的任务运行序列
- 用vTaskDelay()代替空循环后的执行流程,task1得到了执行,如下图:

图 用vTaskDelay()代替空循环后的执行流程
- continuous 1与continuous 2具有优先级1,periodic具有优先级2,periodic使用vTaskDelayUntil,调度图如下(注意心跳中断在t5时刻实际是时间片到时调度器执行):

- 开始任务1具有最高优先级,任务1结束前将任务2设为最高优先级,任务2在结束时将自身设为最低优先级,执行序列如下:

- idle在任务1进入阻塞态后,会执行对任务2的内存清除工作

- 三个任务(事件唤醒)的抢占执行过程

6. 一些重要的API
| API | 含义 | 重要参数说明 | 返回值 |
| void ATaskFunction( void *pvParameters ); | 任务的原型 | 参数必须是void * | 返回值必须是void |
portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, |
创建任务 |
表示任务的优先级,最好设置成实际任务需要的最小值,以避免浪费 |
|
void vTaskStartScheduler( void ) |
开始调度一个任务执行,第一次调度时会自动创建一个空闲任务 | ||
void vTaskDelete( TaskHandle_t xTaskToDelete ) |
删除一个任务 |
要删除任务的句柄 |
|
void vTaskDelay( const TickType_t xTicksToDelay ) |
让当前任务进入阻塞态,并保持多少个tick |
用来指定任务在调用vTaskDelay()到切出阻塞态整个过程包含多少个tick |
|
void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, |
用于实现一个固定执行周期的需求求(当你需要让你的任务以固定频率周期性执行的时候) |
保存了任务上一次离开阻塞态(被唤醒)的时刻这个时刻被用作一个参考点来计算该任务下一次离开阻塞态的时刻。pxPreviousWakeTime 指向的变量值会在API 函数vTaskDelayUntil()调用过程中自动更新,应用程序除了该变量第一次初始化外(通过调用xTaskGetTickCount()初始化),通常都不要修改它的值
此参数命名时同样是假定vTaskDelayUntil()用于实现某个任务以固定频率周期性执行 —— 这个频率就是由xTimeIncrement 指定的。xTimeIncrement 的单位是心跳周期, 可以使用常量 portTICK_RATE_MS 将毫秒转换为心跳周期。 |
|
void vApplicationIdleHook( void ) |
空闲钩子函数 | ||
void vTaskPrioritySet( xTaskHandle pxTask, |
改变任务优先级 |
被修改优先级的任务句柄(即目标任务)
目标任务将被设置到哪个优先级上。如果设置的值超过了最大可用优 |
|
unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask ); |
用于查询一个任务的优先级 |
被查询任务的句柄(目标任务) |
返回值 被查询任务的当前优先级 |
void vTaskDelete( xTaskHandle pxTaskToDelete ) |
删除任务 |
被删除任务的句柄(目标任务) 。任务可以通过传入 NULL 值来删除自己 |
|
taskYIELD |
调用此函数的任务转入就绪态,同时另一个任务转入运行态 |
7.参考文档
[1] FreeRTOS中文实用教程
freeRTOS中文实用教程1--任务的更多相关文章
- freeRTOS中文实用教程6--错误排查
1.前言 本章主要是为刚接触FreeRTOS 的用户指出那些新手通常容易遇到的问题.这里把最主要的篇幅放在栈溢出以及栈溢出侦测上 2.printf-stdarg.c 当调用标准C 库函数时,栈空间使用 ...
- freeRTOS中文实用教程5--内存管理
1.前言 不同的嵌入式系统具有不同的内存配置和时间要求.所以单一的内存分配算法只可能适合部分应用程序. FreeRTOS 将内存分配作为可移植层面(相对于基本的内核代码部分而言).这使得不同的应用程序 ...
- freeRTOS中文实用教程4--资源管理互斥
1.前言 访问一个被多任务共享,或是被任务与中断共享的资源时,需要采用”互斥”技术以保证数据在任何时候都保持一致性.这样做的目的是要确保任务从开始访问资源就具有排它性,直至这个资源又恢复到完整状态 F ...
- freeRTOS中文实用教程4--资源管理概述
1.前言 多任务系统中存在一种潜在的风险.当一个任务在使用某个资源的过程中,即还没有完全结束对资源的访问时,便被切出运行态,使得资源处于非一致,不完整的状态 2.并发抢占导致错误的场景 (1)访问外设 ...
- freeRTOS中文实用教程3--中断管理之中断嵌套
1.前言 最新的 FreeRTOS 移植中允许中断嵌套.中断嵌套需要在 FreeRTOSConfig.h 中设置configKERNEL_INTERRUPT_PRIORITY 和configMAX_S ...
- freeRTOS中文实用教程3--中断管理之计数信号量
1.前言 在中断不频繁的系统中,使用二值信号量没有问题,但是中断频繁发生时,则会有中断丢失的问题. 因为中断发生时延迟任务执行,延迟任务执行的过程中,如果又来了两次中断,则只会处理第一次,第二次将会丢 ...
- freeRTOS中文实用教程2--队列
1.前言 freeRTOS中所有任务的通信和同步机制都是基于队列来实现. 2.队列的特点 图 队列的读写操作 队列的数据存储 (1)队列可以保存有限个具有确定长度的数据单元,队列可以保存的最大单元数目 ...
- freeRTOS中文实用教程3--中断管理之中断服务例程中使用队列
1.前言 消息队列不仅可以用于事件通信,还可以用来传递数据 2.实例说明消息队列的执行过程 3.主要API API名称 说明 参数 返回值 xQueueSendFromISR()完全等同于 xQueu ...
- freeRTOS中文实用教程3--中断管理之延迟中断处理
1.前言 嵌入式实时操作系统需要对整个系统环境产生的事件作出响应.可以采用中断方式也可以采用轮询方式来进行处理.如果采用中断方式,则希望ISR(中断服务例程)的处理时间越短越好. 注:必须说明的是,只 ...
随机推荐
- 自学Linux Shell3.3-列表命令ls
点击返回 自学Linux命令行与Shell脚本之路 3.3-列表命令ls ls命令用于显示文件目录列表,和Windows系统下DOS命令dir类似.当执行ls命令时,默认显示的只有非隐藏文件的文件名. ...
- 引入springboot的两种方式以及springboot容器的引入
一.在项目中引入springboot有两种方式: 1.引入spring-boot-starter-parent 要覆盖parent自带的jar的版本号有两种方式: (1)在pom中重新引入这个jar, ...
- 四个修改Docker默认存储位置的方法
方法一.软链接 默认情况下Docker的存放位置为:/var/lib/docker 可以通过下面命令查看具体位置: sudo docker info | grep "Docker Root ...
- SVN 错误:Error validating server certificate for 'https://xxxxxxx':443... Mac os svn客户端证书验证缓存 解决
mac上的SVN今天突然间 不好使了 在进行SVN操作是报出警告信息 Error validating server certificate for 'https://xxxxxxx':443 - T ...
- 何谓SQL Server参数嗅探
大家听到"嗅探"这个词应该会觉得跟黑客肯定有关系吧,使用工具嗅探一下参数,然后截获,脱裤o(∩_∩)o . 事实上,我觉得大家太敏感了,其实这篇文章跟数据库安全没有什么关系,实际上 ...
- js(=>) 箭头函数 详细解说 案例大全
ES6标准新增了一种新的函数:Arrow Function(箭头函数). 为什么叫Arrow Function?因为它的定义用的就是一个箭头: x => x * x 上面的箭头函数相当于: fu ...
- python爬虫 bs4_4select()教程
http://www.w3.org/TR/CSS2/selector.html 5 Selectors Contents 5.1 Pattern matching 5.2 Selector synta ...
- pubmed_cookie 自动获取
Python爬虫视频教程零基础小白到scrapy爬虫高手-轻松入门 https://item.taobao.com/item.htm?spm=a1z38n.10677092.0.0.482434a6E ...
- printf()格式化输出详解
% - 0 m.n l或h 格式字符 下面对组成格式说明的各项加以说明: ①%:表示格式说明的起始符号,不可缺少. ②-:有-表示左对齐输出,如省略表示右对齐输出. ③0:有0表示指定空位填0,如省略 ...
- Python基础【day03】:集合入门(三)
本节内容 1.集合常用方法总结2.定义3.关系测试 集合是无序的,天生不重复的数据组合,它的作用如下: 去重,即:把一个列表变成集合,就去重了 关系测试,即:测试两组集合的交集.并集和差集等 一.集合 ...