前言:

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. (网页)JS去掉字符串前后空格或去掉所有空格的用法(转)

    转自脚本之家: 这篇文章主要介绍了JS去掉字符串前后空格或去掉所有空格的用法,需要的朋友可以参考下: 代码如下: function Trim(str) { return str.replace(/(^ ...

  2. MySQL--eq_range_index_dive_limit参数学习,MYSQL 5.6 5.7处理数据分布不均的问题

    官方文档如下描述:This variable indicates the number of equality ranges in an equality comparison condition w ...

  3. Win10更换电脑,又不想重装系统的解决方法

    问题描述: 在公司因为两年前用的i3的电脑很卡,然后想换i5的电脑,但是又不想重装系统,因为安装的东西太多了,重装很麻烦 Windows to go介绍: Windows To Go是Windows ...

  4. 解决eclipse启动慢

    每次启动eclipse时都要等待半分钟左右,对于追求效率的程序员来说,等待每一秒都是一种折磨,出于高效开发的精神,这个问题必须解决掉.方案如下: ①在工具栏中的help中找到about eclipse ...

  5. tkinter内嵌Matplotlib系列(一)之解读官网教材

    目录 目录 前言 (一)小目标 1.首页卷面: 2.绘制一条函数曲线: 3.绘制多条曲线: (二)官方教材 1.对GUI框架的支持: 2.内嵌于tkinter的说明文档: (三)对官方教程的解读 目录 ...

  6. ccf-20160903--炉石传说

    本题思路如下图: 题目和代码如下: 问题描述 试题编号: 201609-3 试题名称: 炉石传说 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 <炉石传说:魔兽英雄传& ...

  7. Linux 小知识翻译 - 「packet」(网络数据包)

    用手机接收邮件或者访问网页的时候,一般会说有「packet费用」(这是日本的说法,在中国好像一般都说 “流量费”),即使对网络不太熟悉的人也知道「packet」这个词(这里也是日本的情况). 那么,「 ...

  8. 设计 MySQL 数据表的时候一般都有一列为自增 ID,这样设计原因是什么,有什么好处?

    知乎采集: MyISAM/InnoDB默认用B-Tree索引(可理解为"排好序的快速查找结构"). InnoDB中,主索引文件上直接存放该行数据,称为聚簇索引.次索引指向对主键的引 ...

  9. WeakHashMap源码解读

    1. 简介 本文基于JDK8u111的源码分析WeakHashMap的一些主要方法的实现. 2. 数据结构 就数据结构来说WeakHashMap与HashMap原理差不多,都是拉链法来解决哈希冲突. ...

  10. GUI概述与Frame演示

    java 图形化界面的对象存在这两个包中: java.awt :Abstract WindowsToolkit(抽象窗口工具包)需要调用本地系统方法实现功能,属重量级控件 javax.swing:在a ...