关于µC/OS-III 多任务的基本理解

关于µC/OS-III 多任务的基本理解

任务和任务管理是 RTOS 的核心,且大多数项目使用 RTOS 的目的就是为了使用 RTOS 的多任务管理能力。 µC/OS-III作为经典的RTOS,了解并学习其任务管理机制,是非常有必要的。


文章目录

  • 关于µC/OS-III 多任务的基本理解
  • 一、单任务系统和多任务系统
    • 1.单任务系统
    • 2.多任务系统
  • 二、 µC/OS-III 的任务状态
  • 三、 µC/OS-III 的任务优先级
  • 四、 µC/OS-III 的任务调度方式
    • 1.抢占式调度
    • 2.时间片调度
  • 五、 任务操作函数
    • 1.任务堆栈
    • 2.任务创建
    • 3.任务删除
    • 4.任务挂起
    • 5.任务恢复


一、单任务系统和多任务系统

1.单任务系统

单任务系统就是在裸机上编程,一般都是在 main()函数初始化完成后使用一个while大循环,在循环中顺序地调用相应地函数以处理相应的事务,在while(1)循环中插入各种中断服务函数,整个逻辑顺序依次而行,所以我们也一般称为“流水账”编程方式。如下图所示:
在这里插入图片描述

可以看出,整个代码在while大循环中依次执行,其中部分地方插入点中断,这种框架的优势就是代码较易读,基本上函数调用的顺序就是整个软件各个模块的执行顺序;但是这种框架短板也非常明显,那就是对整个软件各个模块时效控制是很低的,没有轻重缓急之分,比如函数1是控制灯闪烁的函数,需要循环一圈才会调用一次,而且因为不知道函数2和函数2以及中断的执行时间,所以你也没法确定你的闪烁周期,如果删除或增加一个函数模块,你这个周期还会变。

2.多任务系统

多任务系统在处理事务的实时性上比单任务系统要好得多,从宏观上来看,多任务系统的多个任务是可以“并行”的,紧急的事务就可以提高优先级被CPU 优先处理。要注意的是,µC/OS-III 作为单核CPU上的操作系统,其实同一时刻CPU只能处理一个任务,所说的多任务并行其实是通过高效的任务调度算法合理分配各个任务占用CPU的时间,使得各个任务都会根据配置高效运行,所以看起来各个任务像是“并行”一样。如下图所示:
在这里插入图片描述
从上图可以看出,相较于单任务系统而言,多任务系统的任务是具有优先级的,高优先级的任务可以像中断的抢占机制一样,抢占低优先级任务的运行,从而获得 CPU 的使用权;各个任务时效也是可以根据配置参数进行配置的,整个系统的实时性和可控性大大提高。

二、 µC/OS-III 的任务状态

µC/OS-III 中任务存在五种状态,分别为休眠态、就绪态、运行态、挂起态和中断态,某一时刻一个任务一定是处于这五种状态中的一种, 整个µC/OS-III 中的五种任务状态之间的转换图如:
在这里插入图片描述
这是经典的µC/OS-III任务状态转换图,标准了五种不同任务状态的转化方式
■. 休眠态:通过函数 OSTaskDel()删除的任务就会回到休眠态,这里所说的删除,并非将任务从代码空间中删除,而仅仅是将任务切换到休眠态,让 µC/OS-III 内核不再管理这个任务,需要通过调用函数 OSTaskCreate()对一个处于休眠态的任务进行重新创建。
■. 就绪态:准备好运行但还未运行时的任务就处于就绪态。此时任务处于µC/OS-III 就绪列表OSRdylist[X] ,X表示任务优先级数值0-31(32位变量,由高位到低位依次排列)。
■. 运行态:对于单核 CPU 的 MCU 而言,就是是当前正在运行的且唯一的任务所处状态,称为运行态。
■. 挂起态:运行态任务因延时或等待某事件被挂起,例如等待信号量、消息队列或事件标志等,这时运行态任务就会让出 CPU 的使用权,切换到挂起态等待事件发生。 当等待的事件发生后,处于挂起态的任务就会切换到就绪态,等待任务调度器调度运行。
■. 中断态:处于运行态任务被打断,CPU跳转去执行中断服务函数,原本属于运行态的任务会切换到中断态,直到中断结束,再切换回来继续运行

总结:
A. 创建的任务默认是就绪态
B. 被删除的任务,转为休眠态
C. 仅就绪态和中断态可转变成运行态
D. 其他状态的任务要运行,必须转成就绪态

三、 µC/OS-III 的任务优先级

在µC/OS-III中,优先级是决定任务调度器如何分配 CPU 使用权的因素之一。因此µC/OS-III中每一个任务都被分配一个0~(OS_CFG_PRIO_MAX-1)的任务优先级,宏 OS_CFG_PRIO_MAX 表示最大优先级数, 并且 µC/OS-III 中一个任务只能有一个优先级,一个优先级下可以有多个任务。

在 cpu_cfg.h文件中有宏CPU_CFG_LEAD_ZEROS_ASM_PRESENT,该宏用于配置 µC/OSIII 使用硬件指令的方法或是软件算法的方法计算前导零数量, µC/OS-III 使用位图的方式记录当前系统中存在的所有任务优先级, 在 µC/OS-III 系统中存在的最高任务优先级时,就会使用到前导零计数。前导置零指指令CPU_CntLeadZeros():简单理解就是计算一个32位数头部有多少个0,OS_PrioGetHighest()函数通过前导置0指令获得最高优先级。

µC/OS-III 的任务优先级高低与其对应的任务优先级数值是成反比的,也就是说,任务优先级数值为 0 的任务是最高优先级的任务,任务优先级数值为(OS_CFG_PRIO_MAX-1)的任务是优先级最低的任务。

四、 µC/OS-III 的任务调度方式

任务调度:就是任务调度器是使用相关算法来决定当前需要执行的哪个任务,在µC/OS-III 中有两种任务调度规则:

1.抢占式调度

首先已经知道在µC/OS-III 每一个任务都会根据其重要性被分配一个任务优先级,抢占式调度的意思任务优先级高的任务就能够抢占任务优先级低的任务,从而获得 CPU的使用权。抢占式调度特点如下:

A:高优先级优先执行
B:高优先级任务不停止,低优先级任务无法执行
C:被抢占的任务会进入就绪态
D:被挂起的高优先级的任务所等待的事件在中断中发生,中断服务函数退出后不会返回任务优先级低的任务运行,会直接返回任务优先级高的任务去运行

2.时间片调度

µC/OS-III 每一个优先级下可能不止一个任务,那么这些任务的优先级都相同,此时又该怎么调度这些任务呢?

当这些具有相同任务优先级的任务就绪时,任务调度器会根据用户设置的任务时间片轮流地运行这些任务,当然这些任务的运行依然会被任务优先级更高的任务抢占。时间片调度特点如下:

A:同等优先级任务,轮流执行,根据时间片流转依次
B:一个时间片大小取决于滴答定时器中断频率
C:每个任务可以定义自己的时间片长度
D:没有使用的时间片,下次执行不会累加,依旧是初始的时间长度

时间片是依一次系统时钟节拍为单位的,uCOS默认设置的任务时间片为100,则当前任务运行100次时钟节拍之后就切换到相同任务优先级的任务中。

五、 任务操作函数

将任务操作函数之前,先说一个重要概念一一任务堆栈

1.任务堆栈

µC/OS-III 中每个任务都有自己独立的堆栈空间,这个栈空间大小是在创建任务时就确定好的,任务中函数中的局部变量、函数调用时的现场保护和现场恢复等都是要使用到该栈空间的。创建任务函数如下:

void  OSTaskCreate (OS_TCB        *p_tcb,       /*指向任务控制块的指针*/ CPU_CHAR      *p_name,      /*指向任务名字*/OS_TASK_PTR    p_task,      /*指向任务函数的指针*/void          *p_arg,       /*传递给任务函数的参数*/OS_PRIO        prio,        /*任务优先级,越小优先级越高*/CPU_STK       *p_stk_base,  /*指向任务栈的起始地址指针*/CPU_STK_SIZE   stk_limit,   /*任务使用的警戒线*/CPU_STK_SIZE   stk_size,    /*任务堆栈大小*/OS_MSG_QTY     q_size,      /*任务内嵌消息队列的大小*/OS_TICK        time_quanta, /*任务时间片*/void          *p_ext,       /*指向用户扩展内存的指针*/OS_OPT         opt,         /*任务选项共5个*/OS_ERR        *p_err)       /*指向接收错误代码变量指针*/

其中参数 p_stk_base 就是任务栈空间的首地址,参数 stk_size 就是任务栈空间的大小,对于 STM32 所使用的 ARM Cortex-M 对应的 CPU_STK 定义如下所示:

typedef unsigned int CPU_INT32U;
typedef CPU_INT32U CPU_STK

因此 stk_size 表示的任务栈大小的单位为字,因此实际栈大小为 :stk_size*4(1 字为 4 字节)字节。

2.任务创建

1.创建任务函数OSTaskCreat():任务创建后会进入就绪态,(如果是多个任务会根据创建的先后顺序以此执行,然后才会根据优先级独立运行,所以要根据运行顺序调整创建顺序或优先级,或者创建任务时使用临界区,然后创建完成释放临界区,任务会根据优先级执行。
2.任务创建流程
A. 定义函数入口参数(任务控制块、堆栈大小、优先级、任务名称…….
B. 调用创建任务函数
C. 实现函数功能
D. 创建后任务就立即进入就绪态,

注意事项:
1.在调用任何关于μCOS3函数之前必须先初始化μCOS3,仅需要初始化一次即可OSInit(&err);
2.任务创建后是不会直接运行的,需要开启任务调度器,任务才会运行,仅需要调用一次即可OSStart(&err);

3.任务删除

1.删除任务函数OSTaskDel (OS_TCB *p_tcb,OS_ERR *p_err):不需要该任务时可以删除任务,但是不会释放该任务堆栈和删除码,

注意事项:不能删除空闲任务

注意:中断中不能创建和删除任务,只能在任务中执行,任务可以删除自己

4.任务挂起

挂起任务:OSTaskSuspend (OS_TCB *p_tcb,OS_ERR *p_err):可以无条件(无论该任务处于什么状态(被删除的除外))的挂起任务,被挂起的任务不会参与任务调度,如果被挂起的任务是当前真正执行的,那么会发生任务调度,将CPU使用权交给另一个任务,无论优先级如何,被挂起之后某人任务不再执行直到任务恢复。当出入的任务控制块指针是0,表示挂起任务自身。

注意事项:
挂起任务本质就是将就绪列表的任务移除(不是删除),不参与运行

5.任务恢复

OSTaskResume (OS_TCB *p_tcb,OS_ERR *p_err):用于恢复被OSTaskSuspend()函数挂起的任务,可多次调用OSTaskSuspend挂起同一个任务,解挂需要调用相同次数的OSTaskResume()才能解挂;恢复任务的目的是将任务插回就绪列表。


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

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

相关文章

SQL SERVER 如何实现UNDO REDO 和PostgreSQL 有近亲关系吗

开头还是介绍一下群,如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,SQL Server,Redis ,Oracle ,Oceanbase 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请加微信号 l…

Excel VSTO开发5 -Excel对象结构

版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 5 Excel对象结构 Excel提供了几个比较重要的对象: Application、Workbooks、Workbook、Worksheets、Worksheet 为了便…

Mp4文件提取详细H.264和MP3文件

文章目录 Mp4文件提取为H.264和MP3文件**提取视频为H.264:****提取音频为MP3:** 点赞收藏加关注,追求技术不迷路!!!欢迎评论区互动。 Mp4文件提取为H.264和MP3文件 要将视频分开为H.264(视频编…

栈 之 如何实现一个栈

前言 栈最鲜明的特点就是后进先出,一碟盘子就是类似这样的结构,最晚放上去的,可以最先拿出来。本文将介绍的是如何自己实现一个栈结构。 栈的操作 栈是一种先进后出(Last-In-First-Out, LIFO)的数据结构&#xff0c…

Ubantu终端常用命令、快捷键和基本操作

目录 前言 一、常用命令 二、常用快捷键 三、快捷键自定义设置 总结 前言 Ubantu终端常用命令和快捷键用于进行系统管理、文件操作、软件安装等常见使用场景。使用它们可以提高工作效率,简化操作流程,并进行更多的自定义配置和控制。同时&#xff0c…

[SSR渲染学习]nuxt的跨域处理

nuxt跨域请求其他api // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({devtools: { enabled: true },css: [//共享css处理,不是重点可以看看,:是当前文件根目录/assets/css/global.css],//跨域处理nitro: {devProxy: {/go1-api:{ta…

jenkins创建用户

一.背景 之前用了很多次,现在转到甲方爸爸的岗位,要培养大学毕业生,才发现好记性不如烂笔头。给年轻人写出来。 二.创建用户的过程 1.用户管理界面入口 Dashboard>Manage Jenkins>Jenkins own user database 2.点击右边的按钮“Cre…

docker容器内访问宿主机127.0.0.1服务

docker容器内访问宿主机127.0.0.1服务 原创 技术生活 技术生活 2020-04-15 09:00 点击上方”技术生活“,选择“设为星标” 做积极的人,而不是积极废人 背景 原因分析 解决方案 背景 已经通过docker启动的elasticsearch 服务,监听端口9…

深入《C++ Core Guidelines解析》:提升C++编程实践的关键指南

目录 1、写在前面2、推荐理由3、内容介绍4、作者介绍5、赠书 or 购买 1、写在前面 C Core Guidelines是一个正在进行的开源项目,通过将广泛认可的现代C上佳实践集中在一个地方来解决这些问题。Core Guidelines依赖于几十年的经验和早期的编码规则。它们与C本身共享一…

数据结构 每日一练:将带头结点的单链表就地逆置(视频讲解两种方法)

目录 方法一 算法视频分析 方法二 算法视频分析 Q:什么是“就地”捏? A:就是指辅助空间复杂度为O(1),通俗一点来说就是不需要再开辟一块空间来实现算法。 特别说明: 笔者第一次录制视频,言语有些不顺&…

MySQL——常见问题

NULL和空值的区别 1、空值不占空间,NULL值占空间。当字段不为NULL时,也可以插入空值。 2、当使用 IS NOT NULL 或者 IS NULL 时,只能查出字段中没有不为NULL的或者为 NULL 的,不能查出空值。 3、判断NULL 用IS NULL 或者 is no…

SQL Server对象类型(3)——4.3.视图(View)

4.3.1. 视图概念 与Oracle中的视图类似,SQL Server中的视图也是一种虚的、通过一个查询定义的逻辑对象,主要用于集中、简化、定制用户需求,控住其底层表安全,以及应用系统提供向后兼容等方面。 --注: 1)上述内容中的“虚的”,表示视图本身并不实际包含和存储数据,SQL…

Win10 ping 虚拟机kali 请求超时解决办法

出现这种问题应该是windows休眠导致的 这里我的解决方法是先禁用再启用连接 然后再ping 虚拟机ip和kali ip,发现就可以连上了

vue前后端端口不一致解决方案

在config index.js文件中 引入如下代码即可 const path require(path) const devEnv require(./dev.env) module.exports {dev: {// PathsassetsSubDirectory: static,assetsPublicPath: /,proxyTable: devEnv.OPEN_PROXY false ? {} : {/api: {target: http://localhos…

2023高教社杯数学建模国赛B题思路解析+代码+论文

下文包含:2023高教社杯数学建模国赛B题思路解析代码参考论文等及如何准备数学建模竞赛(7号比赛开始后逐步更新) C君将会第一时间发布选题建议、所有题目的思路解析、相关代码、参考文献、参考论文等多项资料,帮助大家取得好成绩。…

工作和生活中,如何用项目管理思维解决复杂的事情?

在工作和生活中,许多事情都可以采用项目思维方式来解决。当我们逐渐将工作和生活中的各种事务以项目的方式来处理和推进时,我们可能并没有意识到,实际上我们正在运用项目管理思维。 项目管理思维能帮助我们在面对繁杂事务时,理清…

PY32F003F18按键输入

一、PY32F003F18的GPIO介绍 1、PY32F003F18的18个I/O,均可作为外部中断; 2、每个GPIO都可以由软件配置为输出: 1)、推挽输出(push-pull) 2)、开漏极输出(open drain) 注意:驱动电流为8mA; 3、每个GPIO都可以由软件配置为输入: 1)、…

android 离线语言合成(文字转语音)

1、基于开源MaryTTS https://github.com/AndroidMaryTTS/AndroidMaryTTS 目前查到的资料,不支持中文,只针对西方语种。 2、基于TensorFlowTTS 官方个地址:为 Android 构建 TensorFlow Lite 库 (google.cn) 所依赖包下载地址:Maven Centr…

ERP辅助报价助力提高效率和准确性

一、ERP辅助报价的定义: ERP辅助报价是指通过企业资源计划系统提供的功能和工具,辅助企业进行报价流程的管理和执行。它涵盖了报价数据的收集、计算、分析和生成报价文件的全过程,以提高报价的准确性、效率和一致性。 二、ERP辅助报价的重要…

LeetCode:2. 两数之和

这个解题思路来自代码随想录&#xff1a;代码随想录 (programmercarl.com) class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {std::unordered_map <int,int> map;for(int i 0; i < nums.size(); i) {// 遍历当前元素&am…