前言:

Task.c和Task.h文件内是FreeRTOS的核心内容,所有任务和调度器相关的API函数都在这个文件中,它包括下图这些内容FreeRTOS文件如下:

Task.c和Task.h文件内是FreeRTOS的核心内容,所有任务和调度器相关的API函数都在这个文件中,它包括下图这些内容

在开始介绍函数之前,首先我们先简单了解一下任务状态:

• FreeRTOS的任务5种状态:

  1. 运行状态:当前正在执行的任务的状态,只可能会一个当前正在执行的任务
  2. 就绪状态:随时可以运行的任务的状态,就绪状态任务随时等待调度器调度
  3. 阻塞状态:任务因为某些原因暂时不能被调度状态,一般情况下正在等待某些事件的发生比如调用了xTaskDelay()在一段时间内任务会被阻塞,在这些事件达成后任务会自动回到就绪状态。
  4. 挂起状态:vTaskSuspend()函数会让任务进入挂起状态,这时候这个任务不会执行。调用xTaskResume()函数才能让这些任务回到就绪状态
  5. 删除状态:一个任务被使用vTaskDelete()函数后被删除,处于删除状态。

他们之间的状态切换如下示意图:

这本篇中,主要介绍一下这6个部分:

一、创建任务:

  • 顾名思义,这些函数的作用是创建一个任务,创建的任务会进入就绪状态,如果没其他更高优先级的任务运行,则马上进入运行状态
  • 这些函数可以在调度器启动前或启动后调用

1.1、vTaskCreate()

1.1.1、函数简介

几个比较重要的输入参数介绍一下:

  • pvTaskCode:直接指向函数的本体的指针,可以把任务函数名字直接贴过来
  • usStackDepth:任务内申请的局部变量会使用到任务的堆栈空间,(在32位系统中,这个参数的单位是word=4byte),例如这个参数设置为100,那么这个任务将会申请到400byte的空间。
  • uxPriority:任务优先级,使用这个参数来设置任务优先级(0是最低优先级),在FreeRTOSConfig.h 中调整configMAX_PRIORITIES的定义可以设置最高可用的优先级(最高可设置优先级为configMAX_PRIORITIES-1)。高优先级的任务可以抢断低优先级的任务,(主要:记得高优先级的任务不需要用的时候将其阻塞或挂起或删除,否则低优先级的任务可能永远无法得到运行权)
  • pxCreatedTask:句柄的地址,以后使用其他API功能来索引这个任务时会需要用到(注意:这里传入的是句柄的地址!)

1.1.2、使用简介:

以下是官方例子:

1.2、vTaskCreateStatic()

1.2.1、函数简介

为了方便我们自己管理内存,有了静态创建任务法,任务堆栈的创建和回收都要由编程者来处理,与vTaskCreate()对比,我们可以发现以下不同之处:

  • puxStackBuffer参数:任务需要用到的堆栈数组的地址,我们只需要创建一StackType_t类型个空的数组,然后把数组指针传进来就好了(注意数组的大小要大于ulStackDepth)
  • pxTaskBuffer参数:存放任务数据结构(TCB)的变量,同样的,我们创建一个StaticTask_t类型的变量,然后把他的指针传进来
  • 还有一处不同,输入参数的句柄取消掉了,但是句柄还是存在的,只是变为了返回参数

1.2.2、使用简介
官方例程如下:

  1. 创建一个StaticTask_t 类型的参数,稍后用于存放任务数据结构(TCB)
  2. 创建一个StackType_t类型数组,稍后用于作为任务堆栈
  3. 创建一个句柄,稍后用作vTaskCode任务的句柄
  4. 使用xTaskCreateStatic()创建任务
  5. 使用vTaskSuspend()、并通过传入句柄挂起刚刚创建的任务,目的是展示给我们看这个任务的句柄是可用的

二、删除任务:

2.1、参数简介

2.2、使用简介

下面是官方例子:

  1. 在当前任务中,用xTaskCreate()创建另一个任务B
  2. 如果任务B创建成功,使用vTaskDelete(任务句柄)删除掉任务B。
  3. 用vTaskDelete(NULL)删除掉当前任务,目的是展示给我们看通过传入NULL可以删除当前任务

三、延时函数:

3.1、vTaskDelay()

3.1.1、函数简介

xTaskDelay()

  • 让调用这个函数的任务在一定时间内进入阻塞状态,时间到达后会切换回来这个任务。
  • 如果输入参数为0,那么这个任务不会阻塞,但是会切换

*这个函数只有一个输入参数,但需要注意一下它是以tick时钟的中断次数为单位的(并不是以毫秒为单位):

3.1.2、使用简介

下面是官方的例子
其中两处vTaskDelay()

  1. 延时20个tick时间片
  2. 延时20ms。(pdMS_TOTICKS()可以把ms时间换成tick为单位)

3.2、vTaskDelayUntil()

3.2.1、函数简介

  • 让任务进入阻塞状态等待实际那到达,是精确的绝对时间
  • 周期性任务能够使用vTaskDelayUntil()来达到连续的执行频率

3.2.2、使用简介

以下是官方的例子:

  1. 创建一个TickType_t类型的变量,用于记录上一次系统时间
  2. 用pdMS_TO_TICKS()函数把50ms转换为tick为单位,方便等下给vTaskDelayUntil调用
  3. 初始化第一步中的变量,在这一步后,这个变量不用再手动更新(vTaskDelayUntil()会更新它)
  4. 使用vTaskDelayUntil()、传入刚刚的参数,制造50ms固定时间的循环

3.3、重要对比

vTaskDelay()和vTaskDelayUntil()的不同之处
我们可以直接翻译一下官方手册的描述:

举个例子:
以下两个任务分别用vTaskDelay()和vTaskDelayUntil()来实现延时功能:
思考一个问题: 任务A 和任务B都能实现LED闪烁,那么A 和 B任务的LED端口多少毫秒翻转一次 ?
任务A:

任务B:

  • 任务A中,LED端口15毫秒翻转一次
  • 任务B中,LED端口10毫秒翻转一次

*注意:Delay_MS()是一个自定义的函数,用来模拟任务中处理其他东西浪费了5ms。
两个任务都是 TaskDelay(10毫秒) ,但是任务A中使用vTaskDelay(),在任务B中使用vTaskDelayUntil()。
在任务A中:vTaskDelay()是从调用的那一刻开始算,那么这个任务本身在Delay_MS中占用了5MS,LED翻转的时间忽略不计,那么加上vTaskDelay()的10MS,就是15MS。
在任务B中:vTaskDelayUntil()和任务本身执行时间无关,只要任务每次循环执行的总时间少于10ms,那么这个任务就是10ms执行一次了。

最后提一下xTaskAbortDelay()这个函数,根据描述,他能让正在阻塞状态等待延时的函数马上切出,进入就绪状态。但由于我的库版本比较旧,没有这个函数,所以就不作更多的介绍了。

四、开启调度器

4.1、函数简介:

这个函数作用是开启调度器,调用这个函数后任务就会开始执行。所以在整个程序中只需要调用一次,一般在main函数中调用就可以了。开启成功的话,系统由调度器接管了,main函数中vTaskStartScheduler()后面的代码都不会被执行。

4.2、使用简介:

官方的例子:

  1. 创建任务
  2. 开启调度器,开启后程序会跳转到vATask()任务中

五、任务的挂起和恢复

5.1、vTaskSuspend() 和 vTaskResume()

5.1.1、函数简介:

挂起/解除挂起单个任务:

  • vTaskSuspend的函数是让指定的任务进入挂起状态
  • xTaskResume的函数是让指定的任务从挂起状态换为就绪状态
  • xTaskResumeFromISR()是xTaskResume()适合在中断中调用的版本

5.1.2、使用简介
使用很简单,当不需要用某个任务的时候用vTaskResume(句柄) 把那个任务挂起,需要用的时候再打开就行了,下面是官方的例程,实现了这三步:

  1. 使用xTaskCreate()创建任务
  2. 创建成功的话使用vTaskSuspend()把刚刚创建的任务转换为挂起状态(该任务将不会再得到执行)
  3. 使用vTaskResume()让刚刚挂起的任务转为就绪状态

5.2、vTaskSuspendAll()和vTaskResumeAll()

5.2.1、函数简介:

vTaskSuspendAll()挂起调度器 对应 xTaskResumeAll()解除挂起调度器:
• vTaskSuspendAll()挂起调度器后,只有当前任务在继续执行,不会发生任务切换了。
• xTaskResumeAll()对应vTaskSuspendAll()恢复调度器。
这个函数的作用之一在于,可以保证一些不能被分的程序执行,因为挂起调度器保证了不会被高优先级的任务强调(注意调度器挂起后中断还是可以运行的,如果要保证时效,还得把中断关闭)

注意:vTaskSuspendAll()是可以递归调用的,这意味着调用了多少次vTaskSuspendAll(),就必须有多少此vTaskResumeAll()的调用才能让调度器恢复。这个情况以下的例子中很好地体现了。

5.2.2、使用简介

  1. 在任务vTask1中第一此调用vTaskSuspendAll(),此时调度器被挂起,不会发生任务切换
  2. 调用另一个用作例子的vDemoFunction()
  3. 第二次调用vTaskSuspendAll(),此时调度器再次被挂起,而且挂起计数增加到2
  4. 第一次调用vTaskResumeAll(),此时调度器挂起计数减少为1,但是调度器仍然处于挂起状态
  5. 第二次调用vTaskResumeAll(),调度器计数为0,调度器恢复运行,后面会发生任务切换了

六、任务切换

6.1、函数简介

  • 在一个运行的任务中调用taskYIELD(),那么这个任务会被降级为就绪状态,调度器会选择另一个相同优先级的就绪任务执行。(如果没有相同优先级的任务就绪,那么这个任务将不会切换,会继续执行。

6.2、使用简介

我们来看官方例子:

  1. 在调用taskYIELD()后,vATask这个任务会马上"让步",进入就绪状态等待,等待下次得到调度器调度的时候,会执行taskYIELD()下面的代码

在下一节中,我们会继续介绍task中的通知和其他内容

FreeRTOS 任务与调度器(1)的更多相关文章

  1. FreeRTOS 任务与调度器(2)

    在上一篇我们介绍了FreeRTOS任务的一些基本操作和功能,今天我们会介绍一个很好很强大的功能——任务通知 任务通知可以在不同任务之间传递信息,它可以取代二值信号量.计数信号量.事件标志组.深度为1的 ...

  2. FreeRTOS调度器

    FreeRTOS----调度器 调度器的启动流程分析 当创建完任务之后,会调用vTaskStartScheduler()函数,启动任务调度器: void vTaskStartScheduler( vo ...

  3. 【freertos】005-启动调度器分析

    前言 本节主要讲解启动调度器. 这些都是与硬件相关,所以会分两条线走:posix和cortex m3. 原文:李柱明博客:https://www.cnblogs.com/lizhuming/p/160 ...

  4. FreeRTOS --(9)任务管理之启动调度器

    转载自 https://blog.csdn.net/zhoutaopower/article/details/107057528 在使用 FreeRTOS 的时候,一般的,先创建若干任务,但此刻任务并 ...

  5. FreeRTOS - 调度器

    原文地址:http://www.cnblogs.com/god-of-death/p/6942641.html 绝大多数情况下,调度器的配置如下: 下面的说明基于上面的调度器配置: 如果有更高优先级的 ...

  6. 大数据之Yarn——Capacity调度器概念以及配置

    试想一下,你现在所在的公司有一个hadoop的集群.但是A项目组经常做一些定时的BI报表,B项目组则经常使用一些软件做一些临时需求.那么他们肯定会遇到同时提交任务的场景,这个时候到底如何分配资源满足这 ...

  7. [Spring]支持注解的Spring调度器

    概述 如果想在Spring中使用任务调度功能,除了集成调度框架Quartz这种方式,也可以使用Spring自己的调度任务框架. 使用Spring的调度框架,优点是:支持注解(@Scheduler),可 ...

  8. 编写简单的ramdisk(选择IO调度器)

    前言 目前linux中包含anticipatory.cfq.deadline和noop这4个I/O调度器.2.6.18之前的linux默认使用anticipatory,而之后的默认使用cfq.我们在前 ...

  9. Erlang/OTP 17.0-rc1 新引入的"脏调度器"浅析

    最近在做一些和 NIF 有关的事情,看到 OTP 团队发布的 17 rc1 引入了一个新的特性“脏调度器”,为的是解决 NIF 运行时间过长耗死调度器的问题.本文首先简单介绍脏调度器机制的用法,然后简 ...

随机推荐

  1. 关注的Elasticsearch大牛博客

    1.http://wangnan.tech/ 2.https://elasticsearch.cn/people/wood 3.https://www.jianshu.com/u/244399b1d7 ...

  2. 04LaTeX学习系列之---overleafz在线编辑平台的使用

    目录 目录 前言 (一)overleaf的认识 1.由来: 2.优点: 3.界面: (二)编译与查看 1.选择编译器 2.编译 (三)基本的设置与操作 1.基本设置 2.基本操作 目录 本系列是有关L ...

  3. Tomcat 访问页面或服务器异常,请检查这些方面

    若还没有部署网站,请检查 防火墙是否关闭 数据库服务是否打开 浏览器访问的地址和端口是否正确 tomcat 配置文件中的端口是否发生冲突,换一个试试 若出现的是"拒绝连接",检查阿 ...

  4. 【夯实PHP基础】微信小程序开发 2017.02.06

    本文地址 分享提纲 1. 概述 2. 简易教程 1. 概述 1)[小程序是什么] 微信小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验. 2)[快速体验 ...

  5. vue_模板渲染

    渲染 当获取到后端数据后,我们会把它按照一定的规则加载到写好的模板中,输出成在浏览器中显示的HTML,这个过程就称之为渲染. vue.js是在前端(即浏览器内)进行的模板渲染. 前后端渲染对比 前端渲 ...

  6. 全栈JavaScript之路( 二十二 )IE 专有扩展——文档模式

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/hatmore/article/details/37611911 ie8 引入了一个新的概念.&quo ...

  7. golang []byte和string相互转换

    测试例子 package main   import (     "fmt" )   func main() {     str2 := "hello"     ...

  8. Git命令的使用_操作远程仓库——详细教程3

    本博文讲述将本地仓库提交到GIT@OSC(或者是GitHub),故而需要用户首先有一个GIT@OSC(或者是GitHub)帐号. 我的GIT@OSC帐号是:https://git.oschina.ne ...

  9. 【js】++i和i++

    解析: i++ 执行完语句后再加1 ++i 先加1再执行后面的语句 例如 var i=0; ++i 的值为1 i++的值为0 注意:不管前置++还是后置++,i的值都会发生变化,值为1 例子 1.va ...

  10. python中.py和.pyw文件的区别

    :本文为博主原创文章,未经博主允许不得转载. 以下是摘录自百度问题的答案: 严格来说,它们之间的不同就只有一个:视窗运行它们的时候调用不同的执行档案. 视窗用 python.exe 运行 .py ,用 ...