【小黑嵌入式系统第十一课】μC/OS-III程序设计基础(一)——任务设计、任务管理(创建基本状态内部任务)、任务调度、系统函数

上一课:
【小黑嵌入式系统第十课】μC/OS-III概况——实时操作系统的特点、基本概念(内核&任务&中断)、与硬件的关系&实现

文章目录

    • 一、任务设计
      • 1.1 任务概述
      • 1.2 任务的类型
        • 1.2.1 单次执行类任务(运行至完成型)
        • 1.2.2.周期执行类任务(无限循环型)
        • 1.2.3 事件触发执行类任务(一种无限循环型)
      • 1.3 任务的划分
        • 1.3.1 任务划分的目标
        • 1.3.2 任务的优先级
    • 二、任务管理
      • 2.1 任务创建
      • 2.2 任务的基本状态
      • 2.3 系统内部任务
        • 2.3.1 空闲任务 `OS_IdleTask()` (`os_core.c`)
        • 2.3.2 时钟节拍任务 `OS_TickTask() `(os_tick.c)
        • 2.2.3 定时器任务 `OS_TmrTask()` (os_tmr.c)
    • 三、任务调度
      • 3.1 任务调度器
      • 3.2 调度点
    • 四、系统函数概述
      • 4.1 基本原则
        • 4.1.1 配对性原则
        • 4.1.2 中断服务程序调用函数的限制
        • 4.1.3 任务必须调用某个系统函数
      • 4.2 系统函数的分类


一、任务设计

1.1 任务概述

在基于实时操作系统的应用程序设计中,通常需要把要完成的工作分成多个任务(也称线程)来实现,每个任务只负责其中的一部分相对独立的工作,它可以认为在独享CPU。

在只有一个CPU时,任何时刻都只能有一个任务得到执行。操作系统通过任务调度将CPU执行时间在不同任务之间快速切换,以达到多任务“同时”运行的效果。

μC/OS-III允许应用程序有任意多个任务(仅受存储器容量限制),任务优先级数量可由用户配置,不同的任务允许拥有相同的优先级。

对于不同优先级的任务,采用抢占式(可剥夺式)任务调度方式;对于相同优先级的任务,采用时间片轮转调度方式。

在基于实时操作系统的应用程序设计中,任务设计是整个应用程序的基础,其它软件设计工作都是围绕任务设计来展开。

在这里插入图片描述


1.2 任务的类型

按照执行方式分类:

在这里插入图片描述

1.2.1 单次执行类任务(运行至完成型)

在这里插入图片描述


1.2.2.周期执行类任务(无限循环型)

在这里插入图片描述


1.2.3 事件触发执行类任务(一种无限循环型)

在这里插入图片描述


无限循环型的任务中,必须调用等待某个事件或延时的系统API函数(而非自己编写的不受操作系统管理的等待函数,如CyDelay() ),否则将会导致其它优先级更低的任务无法得到执行。(原因见“任务调度”部分)

当任务在等待一个事件或延时时,它不会占用CPU时间,此期间CPU可被系统分配给其它任务执行。


1.3 任务的划分

1.3.1 任务划分的目标

在对一个具体的嵌入式应用系统进行任务划分时,可以有不同的任务划分方案。为了选择最佳划分方案,就必须知道任务划分的目标。

  1. 首要目标是满足“实时性”指标:即使在最坏的情况下,系统中所有对实时性有要求的功能都能够正常实现;

  2. 任务数目合理:对于同一个应用系统,合理的合并一些任务,使任务数目适当少一些还是比较有利;但任务数目少并不一定能保证设计是多么优秀或多么有效率。

  3. 简化软件系统:一个任务要实现其功能,除了需要操作系统的调度功能支持外,还需要操作系统的其它服务功能支持,合理划分任务,可以减少对操作系统的服务要求,简化软件系统;

  4. 降低资源需求:合理划分任务,减少或简化任务之间的同步和通信需求,就可以减少相应数据结构的内存规模,从而降低对系统资源的需求。


1.3.2 任务的优先级

任务的优先级安排原则如下:

在这里插入图片描述

  1. 中断关联性:与中断服务程序(ISR)有关联的任务应该安排尽可能高的优先级,以便及时处理异步事件,提高系统的实时性。
    如果优先级安排得比较低,CPU有可能被优先级比较高的任务长期占用,以致于在第二次中断发生时连第一次中断还没有处理,产生信号丢失现象。

  2. 关键性:任务越关键安排的优先级越高,以保障其执行机会;

  3. 频繁性:对于周期性任务,执行越频繁,则周期越短,允许耽误的时间也越短,故应该安排的优先级也越高,以保障及时得到执行;

  4. 快捷性:在前面各项条件相近时,越快捷(耗时短)的任务安排的优先级越高,以使其它就绪任务的延时缩短;

  5. 传递性:信息传递的上游任务的优先级高于下游任务的优先级。如信号采集任务的优先级高于数据处理任务的优先级。


二、任务管理

2.1 任务创建

为了使μC/OS-III知道一个任务的存在,必须先创建该任务,通过调用系统API函数OSTaskCreate()来创建一个任务。

在这里插入图片描述

  • 任务可以在多任务调度开始前建立,也可以在其它任务的执行过程中建立。
  • 在开始多任务调度之前,用户必须至少创建一个用户任务。
  • 任务不能在中断服务程序(ISR)中建立。
  • μC/OS-III通过任务控制块(TCB)对任务进行管理,创建任务实际上就是给任务代码分配一个任务控制块。
  • 任务控制块是一个基于链表的数据结构体,任务控制块主要用于记录任务的堆栈栈顶指针、指向下一个任务控制块的指针、任务等待的延迟时间、任务的当前状态标志与任务的优先级别等一些与任务管理有关的属性。
  • 当任务的CPU使用权被剥夺时,μC/OS-III用任务控制块来保存该任务的状态,从而保证任务重新获得CPU使用权时能从断点处恢复继续执行。

任务的相关资源(图中未含任务控制块):

在这里插入图片描述

  • 任务栈是一个后进先出(LIFO)的线性表。
    每个任务均需有一个栈(任务栈),用于存储局部变量、传递的函数参数、返回地址及CPU寄存器的值。
  • 每个任务均需有一个优先级,取值范围0~OS_CFG_PRIO_MAX-1,用户不能使用最高优先级0和最低优先级 。
  • 任务的具体实现对应于任务函数,任务函数的参数p_arg值由任务创建函数OSTaskCreate()传递而来。
    任务函数由系统择机调用,而不能由用户主动调用。

2.2 任务的基本状态

任务的5种基本状态及转换关系:

在这里插入图片描述

简化地说,任务的状态有5种:休眠态就绪态运行态等待态中断服务态
任务被创建后,将由不受操作系统管理的休眠态转换为就绪态,由任务调度器决定何时使用CPU运行(运行态)。

任务状态的转换由执行了某些特定的OS API函数(或中断进入退出)引起。


2.3 系统内部任务

μC/OS-III共有5个系统内部任务:

  • 空闲任务 OS_IdleTask()
  • 时钟节拍任务 OS_TickTask()
  • 统计任务 OS_StatTask()
  • 定时器任务 OS_TmrTask()
  • 中断服务管理任务 OS_IntQTask()

2.3.1 空闲任务 OS_IdleTask()os_core.c

当所有其它任务都未就绪时,由于CPU仍需执行指令不能停止运行,此时将运行空闲任务。

它是系统创建的第一个任务,必须创建。空闲任务的优先级为最低优先级OS_CFG_PRIO_MAX-1,其它任务不能使用该最低优先级。


2.3.2 时钟节拍任务 OS_TickTask() (os_tick.c)

任务中的延时、等待某事件时的超时,这些都需要依赖一个周期性的时钟源来计时,称为时钟节拍或系统节拍。经历一个周期称为一个时钟节拍。

时钟节拍任务必须创建,其优先级由OS_CFG_TICK_TASK_PRIO(os_cfg_app.h)设定,通常设为只比最重要的用户任务的优先级略低一点。时钟节拍任务负责判定其它任务中的所有延时、超时的结束。

在这里插入图片描述

  • 需配备一个硬件定时器(时钟节拍定时器),工作频率由OS_CFG_TICK_RATE_HZ设定在10~1000(Hz)之间。
  • 时钟节拍任务收到时钟节拍定时器ISR周期发送的信号量时,才开始它的处理工作。否则处于等待态。

2.2.3 定时器任务 OS_TmrTask() (os_tmr.c)

用于向用户提供较粗的定时服务。该任务可选,由OS_CFG_TMR_EN(os_cfg.h)使能。

定时器任务是一个周期运行的任务,它和时钟节拍任务使用相同的硬件定时器。通过软件方式的分频,定时器任务可实现(比时钟节拍定时器)定时精度低的软件定时器(数量仅受存储器容量限制)。

定时器任务提供的(软件)定时器为递减计数器,计数值减为0时,会引发一个操作,该操作由操作系统调用一个用户定义的回调函数(运行在定时器任务环境中)来实现。

定时器任务的优先级一般设置为中等优先级,由宏OS_CFG_TMR_TASK_PRIO(os_cfg_app.h)来设定。

时钟节拍ISR和定时器任务的关系:

在这里插入图片描述
与时钟节拍任务共用时钟节拍硬件定时器。

定时器任务每收到 N个 时钟节拍定时器ISR周期发送的信号量时,才开始它的处理工作。相当于对时钟节拍定时器进行软件分频。

由定时器任务管理的所有定时器都拥有同样的时间分辨率,即1/OS_CFG_TMR_TASK_RATE_HZ秒,其常用推荐值为0.1秒。


三、任务调度

3.1 任务调度器

任务调度器(简称调度器)负责确定CPU下一个要执行的任务。

μC/OS-III支持两种任务调度算法:抢占式(可剥夺式)调度时间片轮转调度

  • 抢占式(可剥夺式)调度:CPU执行进入就绪态的优先级最高的任务(若当前正运行的任务优先级最高,仍执行它)。

当一个事件的发生使得一个更高优先级的任务就绪时,调度器会“立即”将CPU的控制权剥夺,转交给该更高优先级的任务使用,看起来像是高优先级任务“抢占”了CPU。

  • 时间片轮转调度:有多个就绪任务(以及当前正运行的任务)处于同一优先级时,这些任务轮流运行一段指定的时间(又称时间片),一个时间片包含若干个时钟节拍。

默认各任务有相等的时间片,也可用户指定各任务的时间片长度。

抢占式调度中,任务级的任务调度由OS_Sched()函数完成,而中断级的任务调度由ISR结束时的OSIntExt()函数完成。
时间片轮转任务调度由OS_SchedRoundRobin()函数完成。


3.2 调度点

μC/OS-III 任务调度不可能随时都在进行,当程序调用某些系统服务函数时,调度器才会自动启动,这些时间点称为调度点。

由于调度点很多,几乎可以认为“随时”都在进行任务调度。

在这里插入图片描述


四、系统函数概述

4.1 基本原则

4.1.1 配对性原则

对于μC/OS-III来说,大多数API是设计成成对出现的,而且一部分必须配对使用。部分API如延时,不需要配对使用。配对的函数见下表。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


4.1.2 中断服务程序调用函数的限制

中断服务程序不能调用可能会导致任务调度的函数,它们主要是一些等待事件的函数,这些函数见下表。

在这里插入图片描述

注意:未列入表中的函数OSTaskCreate()OSTaskDel()OSTaskResume()OSTaskSuspend()OSTimeDly()OSTimeDlyHMSM()OSTimeResume()都属于在中断服务程序中禁止调用的函数。

一些函数虽然没有明确地规定不能被中断服务程序调用,但因为中断服务程序的特性,一般不会使用。

  • 1.创建事件和删除事件的函数。
  • 2.与任务相关的函数OSTaskChangePrio()OSTaskTimeQuantaSet()OSTaskStkChk()。至于函数OSSchedLock()OSSchedUnlock(),在中断服务程序中使用没有任何意义。

4.1.3 任务必须调用某个系统函数

因为μC/OS-III是完全基于优先级的操作系统,所以在一定的条件下必须出让CPU占有权以便比自己优先级更低的任务能够运行,这是通过调用部分系统函数来实现的,这些函数见下表。一般的任务必须调用表中至少一个函数,只有一种情况例外,即单次执行的任务,因为任务删除后肯定出让CPU,所以可以不调用表中的函数。

在这里插入图片描述


4.2 系统函数的分类

在这里插入图片描述


系统管理函数是一些与μC/OS-III内核或功能相关的一些函数,详见下表:

在这里插入图片描述
μC/OS-III的初始化函数有2个:OSInit()OSStart(),它们不能在任何任务和中断服务程序中使用,仅在main()函数中按照一定的规范被调用,其中OSInit()函数初始化μC/OS-III内部变量,OSStart()函数启动多任务环境。


μC/OS-III具有简单的动态内存管理能力。μC/OS-III的动态内存管理函数见下表:

在这里插入图片描述


任务管理函数是操作与任务相关功能的函数,详见下表:

在这里插入图片描述
μC/OS-III把信号量等都称为事件,管理它们的就是事件管理函数。μC/OS-III具有的事件有普通信号量、互斥信号量、事件标志组和消息队列,这些都是μC/OS-III用于同步与通讯的工具。


一般的操作系统都提供时间管理的函数,最基本的就是延时函数,μC/OS-III也不例外,μC/OS-III所具有的时间管理函数见下表:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/237072.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux调试器gdb的用法

Linux调试器gdb的用法 1. debug/release版本之间的比较2. gdb调试器的基本指令3. 使用展示 1. debug/release版本之间的比较 在之前学习C语言的的时候出过一期vs的调试技巧。 而对于现在的Linux下的调试器gdb其实也是换汤不换药的,基本上的调试思路是不会改变的&am…

FreeSWITCH 1.10 源码阅读(7)-uuid_bridge 命令原理解析

文章目录 1. uuid_bridge 命令执行2. 源码分析3. uuid_bridge 问题处理 1. uuid_bridge 命令执行 uuid_bridge 命令用于将两条腿桥接在一起,以实现双方的通话。下图是该命令在 FreeSWITCH 中的处理流程,大致的流程可以分成以下几个步骤: uui…

手写单链表(指针)(next域)附图

目录 创建文件: 具体实现: 首先是头插。 注意:一定要注意:再定义tmp时,要给它赋一个初始值(推荐使用 new list_next) 接着是尾插: 随后是中间插: 然后是最简单的改值&#xf…

JS - 设计模式持续学习中

通过例子持续学习JS设计模式中,接下来请跟随我的步伐走进我的学习笔记世界~ 什么是设计模式?我们为什么需要学习设计模式? 设计模式是可以更好解决问题的一种方案。 这意味着什么?如果你开发的项目的功能是固定的,永…

Java中的继承

继承 什么是继承继承的特点继承后对象的创建 继承的好处与应用场景继承相关注意事项权限修饰符单继承、Object类方法重写什么是方法重写 子类中访问其他成员的特点子类构造器的特点 什么是继承 Java中提供了一个关键字extends,用这个关键字,可以让一个类…

【自用】Ubuntu20.4从Vivado到ddr200t运行HelloWorld

【自用】Ubuntu20.4新系统从输入法到ddr200t运行HelloWorld 一、编辑bashrc二、Vivado2022.2安装三、编译蜂鸟E203自测样例1. 环境准备2. 下载e203_hbirdv2工程文件3. 尝试编译自测案例1. 安装RISC-V GNU工具链2. 编译测试样例 4. 用vivado为FPGA生成mcs文件1.准备RTL2.生成bit…

对大学生创新创业某赛事目前存在的烂尾楼现象的一些研究的分享(1)

经过对”某某网”大学生创新创业大赛国赛第五届-第八届部分金奖项目的研究,进行较为充分的信息溯源、穿透调查,我发现不少项目存在赛事材料画大饼,严重不切合实际,参赛人员并非真正创新创业,赛后迅速销声匿迹、烂尾切割…

图论 | 网络流的基本概念

文章目录 流网路残留网络增广路径割最大流最小割定理最大流Edmonds-Karp 算法算法步骤程序代码时间复杂度 流网路 流网络: G ( V , E ) G (V, E) G(V,E) 有向图,不考虑反向边s:源点t:汇点 c ( u , v ) c(u, v) c(u,v)&#xff…

你以为出现NoClassDefFoundError错误会是什么原因?

你以为出现NoClassDefFoundError错误会是什么原因? 1、概述2、事情经过3、总结 1、概述 大家好,我是欧阳方超,可以关注我的公众号“欧阳方超”,后续内容将在公众号首发。 同样的错误,非一样的解决方式。NoClassDefFou…

【智慧校园】基于国标GB28181协议EasyCVR视频技术的高校宿舍智能监管方案

现如今,各大学校不乏众多住校生,但由于很多学生年龄较小 ,又缺乏独自生活的经历,如何给在校住宿生做到安全与生活双重保障?旭帆科技校园智能视频监控通过人工智能技术对住宿区域进行智能监管,确保学生住宿安…

【HCIP学习记录】OSPF Hello报文及状态机

字段长度含义Version1字节版本,OSPF的版本号。对于OSPFv2来说,其值为2。Type1字节类型,OSPF报文的类型,有下面几种类型: 1:Hello报文;● 2:DD报文;● 3:LSR报…

【终极教程】cocos2dx-js 分批次混淆压缩js文件

​ 说明: 1> 由于我们当前游戏框架的结构是平台形式的就是一个大厅里面有若干个子游戏,所以在发布的时候得区分子游戏和大厅了解了一下 project.json 里面有一个 jsList 可以把所有放进去的js文件压缩混淆成一个大的文件但是我们游戏的子游戏非常多 这样子弄显然不合适&…

青少年CTF-qsnctf-Web-登陆试试

题目环境: 题目难度:★题目描述:Syclover用户忘了他的密码,咋办哦,依稀记得密码为6位数字,以774开头,这次我们来爆爆他的密码,让他再也不犯相同的错了 先不着急进行爆破 看看源码里面有没有其它有用的信息 …

Shell三剑客:awk(内部变量)

一、$0 :完整的输入记录 [rootlocalhost ~]# awk -F: {print $0} passwd.txt root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/s…

软件分享--图片置顶工具

一个好的程序应该只做一件事情,并且将这件事情做好。 使用许多小工具的集合要比使用一个什么都做但什么都做不好的工具要好。 linux系统强大,组成它的是dd、sed、grep、awk、tar等各种命令工具的集合。 如果你能够合理使用各种小工具。效率会比使用任何…

【python】作用域与闭包 || global与nonlocal

python作用域 其他语言的作用域:块级、函数、类、模块、包等由小到大的级别但是python没有块级(if语句块、for语句块),所以if中定义的变量,相当于普通语句 >>> if True: # if语句块没有作用域x …

Vue3-23-组件-依赖注入的使用详解

什么是依赖注入 个人的理解 : 依赖注入,是在 一颗 组件树中,由 【前代组件】 给 【后代组件】 提供 属性值的 一种方式 ;这种方式 突破了 【父子组件】之间通过 props 的方式传值的限制,只要是 【前代组件】提供的 依…

[MySQL]用基本的mysql语句写的{商店的数据}和{学生成绩}

文章目录 前言一、题目二、创建2.写入table 三.查看表单结构四.插入数据1.俩种方法2.指定插入 五.查询1.全部和指定查询2.别名查询3.去重4.排序5.条件查询(where) 六.修改七.删除八.在table中插入一列总结: 前言 提示:以下是本篇文章正文内容…

实现单链表的基本操作(力扣、牛客刷题的基础笔试题常客)

本节来学习单链表的实现。在链表的刷题中,单链表占主导地位,很多oj题都在在单链表的背景下进行;而且很多链表的面试题都是以单链表为背景命题。所以,学好单链表的基本操作很重要 目录 一.介绍单链表 1.链表及单链表 2.定义一个…

JVM垃圾收集器三色标记算法

垃圾收集算法 分代收集理论 当前虚拟机的垃圾收集都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活周期的不同将内存分为几块。一般将java堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。 比…