ucosII任务切换是怎样实现的
uCOS-II的任务切换机理及中断调度优化
uCOS-II的任务切换机理及中断调度优化uC/OS-II的任务切换机理及中断调度优化摘要:μC/OS-II是一种适用于嵌入式系统的抢占式实时多任务操作系统,开放源代码,便于学习和使用。
介绍μC/OS-II在任务级和中断级的任务切换原理,以及这一操作系统基于嵌入式系统的对于中断的处理;相对于内存资源较少的单片机,着重讨论一种优化的实用堆栈格式和切换形式,以提高资源的利用率;结合MSP430单片机,做具体的分析。
关键词:实时多任务操作系统μC/OS MSP430 中断堆栈引言在嵌入式操作系统领域,由Jean J. Labrosse开发的μC/OS,由于开放源代码和强大而稳定的功能,曾经一度在嵌入式系统领域引起强烈反响。
而其本人也早已成为了嵌入式系统会议(美国)的顾问委员会的成员。
不管是对于初学者,还是有经验的工程师,μC/OS开放源代码的方式使其不但知其然,还知其所以然。
通过对于系统内部结构的深入了解,能更加方便地进行开发和调试;并且在这种条件下,完全可以按照设计要求进行合理的裁减、扩充、配置和移植。
通常,购买RTOS 往往需要一大笔资金,使得一般的学习者望而却步;而μC/OS对于学校研究完全免费,只有在应用于盈利项目时才需要支付少量的版权费,特别适合一般使用者的学习、研究和开发。
自1992第1版问世以来,已有成千上万的开发者把它成功地应用于各种系统,安全性和稳定性已经得到认证,现已经通过美国FAA认证。
1 μC/OS-II的几大组成部分μC/OS-II可以大致分成核心、任务处理、时间处理、任务同步与通信,CPU的移植等5个部分。
核心部分(OSCore.c) 是操作系统的处理核心,包括操作系统初始化、操作系统运行、中断进出的前导、时钟节拍、任务调度、事件处理等多部分。
能够维持系统基本工作的部分都在这里。
任务处理部分(OSTask.c) 任务处理部分中的内容都是与任务的操作密切相关的。
包括任务的建立、删除、挂起、恢复等等。
uCOS-II中的任务切换机制
uCOS-II中的任务切换机制【@.1 函数周期与死循环】一般函数的生命周期很简单,从开始调用函数起,直到函数返回,即结束。
这样一来就完成了这个函数的使命,它也就不再需要了。
对于一般的函数就是这样,但是回过头想想,对于一个系统、OS、或者工业控制中的一个控制器重的系统个,函数返回是很轻易很随便的就能返回吗?返回就意味着函数结束,死亡,若是想系统这样一个很大的函数,它的返回就意味着系统结束。
因此,对于系统的函数返回有些时候我们不希望它返回,返回时是需要好好设计的,像嵌入式中的控制程序我们也并不需要它返回,直接关机就好了。
因此,一个系统往往就是一个很大的循环,不停的扫描,而我们编程的时候对于这个死循环是需要好好设计的。
考虑以下一个控制要求,@.按键控制电机启、停、正转反转,并每秒发送CAN报文报告当前情况。
我们可以有多种方法实现这一要求:方法一:每次在循环体重扫描当前按键的电平,从而进入对应的控制电机函数,如果所有电平都没有信号则直接进入下一个循环。
发送CAN报文就直接用一个定时中断。
这样的好处就是编程简单直白,每次循环进入不同的电机控制函数,坏处很明显,一定要等待到下一个循环才能进入其他的电机控制函数,每次循环的时间不好控制,不管你用函数指针还是if/else来判断,每次循环一定要等待电机动作结束才能进入下一个循环。
方法二:改用外部中断来处理按键。
仅当按键按下时触发外部中断,从而控制响应的电机进行操作。
这样的好处就是循环体简单,可以仅仅就是一个计数器加一,所有控制都等中断来实现。
但这样带来的问题也很明显,就是中断嵌套问题。
比如当电机正转时按下停止按钮,这时由于是在中断中,停止按钮是否真的能够得到响应?这就涉及到中断嵌套问题,并不见得所有CPU都能支持中断嵌套,我的这一篇文章对中断嵌套问题进行了一个讨论。
方法三:采用RTOS的思想,加入任务调度系统。
每次任务调度系统就是一个小小的循环,对于各个任务进行轮询,当这次轮询发现某任务是已经就绪的优先级最高的任务,则交给CPU处理,所有中断与任务,任务与任务之间有通讯机制可以交换信息。
UC-OS II多任务机制
UC/OS II 多任务机制前面已经说过,uC/OS-II是一种基于优先级的可抢先的多任务内核。
那么,它的多任务机制到底如何实现的呢?了解这些原理,可以帮助我们写出更加健壮的代码来。
首先我们来看看为什么多任务机制可以实现?其实在单一CPU的情况下,是不存在真正的多任务机制的,存在的只有不同的任务轮流使用CPU,所以本质上还是单任务的。
但由于CPU执行速度非常快,加上任务切换十分频繁并且切换的很快,所以我们感觉好像有很多任务同时在运行一样。
这就是所谓的多任务机制。
由上面的描述,不难发现,要实现多任务机制,那么目标CPU必须具备一种在运行期更改PC的途径,否则无法做到切换。
不幸的使,直接设置PC指针,目前还没有哪个CPU支持这样的指令。
但是一般CPU都允许通过类似JMP,CALL这样的指令来间接的修改PC。
我们的多任务机制的实现也正是基于这个出发点。
事实上,我们使用CALL指令或者软中断指令来修改PC,主要是软中断。
回想一下你在微机原理课程上学过的知识,当发生中断的时候,CPU保存当前的PC和状态寄存器的值到堆栈里,然后将PC设置为中断服务程序的入口地址,再下来一个机器周期,就可以去执行中断服务程序了。
执行完毕之后,一般都是执行一条RETI指令,这条指令会把当前堆栈里的值弹出恢复到状态寄存器和PC里。
这样,系统就会回到中断以前的地方继续执行了。
那么设想一下?如果再中断的时候,人为的更改了堆栈里的值,那会发生什么?或者通过更改当前堆栈指针的值,又会发生什么呢?如果更改是随意的,那么结果是无法预料的错误。
因为我们无法确定机器下一条会执行些什么指令,但是如果更。
关于uCOS-Ⅱ中任务切换的仪器仪表的实现实例
关于uCOS-Ⅱ中任务切换的仪器仪表的实现实例假设某仪器要实现A/D采样、输入控制、显示等功能。
uC/OS-Ⅱ*作系统将对这三个任务进行管理,协调各自工作。
任务描述:统计任务:每做完例行统计后执行一次显示输出;初始任务:每隔10节拍进行一次A/D采样;用户任务:每秒判断一次是否有输入控制信号。
实验中为了测量与观察方便,采用对89C51的P1口每次取反的*作来模拟仪器执行的任务,由于关心的是*作系统的*能,而非任务本身,因此简化是可行的。
设置时钟节拍:50Hz三个任务(包含系统空闲任务):任务名优先级*作空闲任务63空*作统计任务62每秒做一次统计并对P1。
2取反初始任务4每秒对P1。
0取反一次用户任务5每10个节拍对P1。
1取反一次设计中须注意以下两点:(1)任务的现场保护:除PUSH到堆栈的CPU寄存器外,还应包括任务运行过程中保存到堆栈的信息,所以每次保存的信息量是变化的。
(2)任务堆栈的大小应根据实际情况充分估计,避免过大或者不足。
在这个例子中定义了TASKSTKSIZE(任务堆栈)为64个字节,故在内部RAM中预留出64个字节作为*作系统的系统堆栈,用全局变量定义如下:INT8Uidatasp[64]at0x30;该语句表示系统堆栈从30H开始。
(1)开始多任务调度每个任务堆栈初始化情况:堆栈指针SP=48-1+8+5+2+2+sizeof(void*),即系统堆栈放入以上信息后SP指针所指的位置。
下面开始多任务调度:系统堆栈指针SP初始值30H,将初始任务的任务堆栈内容(在xdata段)Load到系统堆栈内,完成后SP应指向系统堆栈栈顶,然后运用pop指令切换到初始任务。
(2)在任务运行中进行任务切换切换前系统堆栈为:将系统堆栈中从当前SP开始一直到30H的堆栈信息保存到当前任务堆栈中,然后把新任务的任务堆栈的内容Load到系统堆栈中来。
然后用POP指令将任务切换到新任务中去。
(3)在中断返回时切换任务须保存的信息在中断时应保存,切换任务时,只要将SP减去由于调用OSIntExit()和OSIntCtxSw()两个函数而使SP指针增加的4个字节,其他与任务级切换一样。
μC/OS-Ⅱ中通过中断返回指令实现任务切换
0 — S K *O TC Sk t;/ 任务 堆 栈 指 针 S T S B tpr /
…
●…Βιβλιοθήκη …………
) - T B;/ 任 务 控 制 块 OS C / O - T B * T B u ;指 向任 务 控 制 块 的 指针 S C OS C C r
33 任 务堆栈的栈增长方式 : .
微 型 电脑 应 用
20 0 6年 第 2 2卷 第 4期
l / 一 Ⅱ中通 过 中断 返 回指 令 实现 任 务 切 换 _ oS I C
胡 蔷
摘 要 :C/ S I是 一 个 源码 公 开 的 实 时嵌 入 式 操 作 系 统 ,  ̄ O - 它的 特 点 在 于公 开 的 源 代 码 , 强 的 移 植 性 , 很 占先 式 多任 务 , 每
2 3 时 钟 定 时 鼍 的硬 件 设 定 .
b .堆 栈 初 始 化 ; 任何 一 个 新 建 任 务 都 要 做 这 个 初 始 化 他 与 处 理 器 相 关 对 于 中 断返 回后 正 确 切 换 到 新 任 务 至关 重 要 。
v i Ta k t l i ( od (*a k v i p , od * od OS s S k nt v i s )( od d) v i
#d f e 0S STK— GR0W TH ei — n 1
( ) 理 器 支 持 能 够 容 纳 一 定 量 数 据 (-能 是 几 千 字 节 ) 4处 - . I
的硬件堆栈 。
() 5 处理器有堆 栈指针和其他 C U寄存器 读 出和存 储到 P
堆 栈 或 内存 中 的指 令 。
过 中 断指 令 实 现 任 务 切 换 , 决 移 植 的核 心 问题 。 解
μCOS-Ⅱ操作系统的任务切换
μC\OS-Ⅱ操作系统的任务切换作者:司新生来源:《数字技术与应用》2010年第06期摘要:μC\OS-Ⅱ操作系统是一个多任务占先式实时操作系统,每一个任务由三部分组成,任务控制块,任务的私有堆栈、任务代码。
每一个任务有一个决定其重要性的任务优先级,系统通过任务就绪表来进行任务的切换,就绪的任务在任务就绪表中设置其标志位,退出就绪的任务在就绪表中撤消其标志位。
任务的切换过程就是通过任务就绪表找到优先级最高的任务,保存原来运行任务的上下文到该任务的私有堆栈中,从最高优先级的任务私有堆栈中复制断点数据到工作寄存器中,pc指针指向该任务的代码段,实现了任务的切换。
关键词:操作系统任务控制块优先级任务切换1 μC\OS-Ⅱ的任务μC\OS-Ⅱ操作系统是一个多任务系统,它最多可以管理64个任务,但两个优先级最低的任务已被系统占用,一个是统计任务,一个是空闲任务。
空闲任务的作用为当操作系统没有其它任务执行时,就转入空闲任务而不使系统没事可做。
任务的结构每一个任务都有如下结构。
它由任务控制块TCB,任务代码,任务堆栈组成,多个任务控制块形成一个任务控制块链表。
每一个任务在创建时都被分配有一个任务优先级,优先级序号从0到63,优先级数值越大则表示优先级越低,最高的优先级是优先级序号为0的任务,最低的优先级是优先级为63的任务。
操作系统可以设定管理的任务数,在OS_CFG.H文件中,可以定义OS_LOWEST_PRIO值,该值最大为63。
每一个任务都有唯一的任务优先级,μC\OS-Ⅱ操作系统任务切换的关键就是该任务的优先级,操作系统总是运行处于就绪状态的最高优先级的任务。
创建任务主要完成四项任务,一是指出任务代码存放的地址,二是指明任务参数指针,也即任务参数地址,三是指明任务堆栈栈顶指针,在进行任务切换时保存或恢复与任务相关的寄存器的值,四是确定任务的优先级,优先级的高低决定了任务的紧迫性和重要性。
任务创建的代码如下。
uC-OS-II的运行机制
uC/OS-II的运行机制在嵌入式系统的应用中,实时性是一个重要的指标,而优先级翻转是影响系统实时性的重要问题。
本文着重分析优先级翻转问题的产生和影响,以及在uC/OS-II 中的解决方案。
uC/OS-II 采用基于固定优先级的占先式调度方式,是一个实时、多任务的操作系统。
系统中的每个任务具有一个任务控制快OS_TCB,任务控制块记录任务执行的环境,包括任务的优先级,任务的堆栈指针,任务的相关事件控制块指针等。
内核将系统中处于就绪态的任务在就绪表(ready list)进行标注,通过就绪表中的两个变量OSRdyGrp 和OSRdyTbl[]可快速查找系统中就绪的任务。
在uC/OS-II 中每个任务有唯一的优先级,因此任务的优先级也是任务的唯一编号(ID),可以作为任务的唯一标识。
内核可用控制块优先级表OSTCBPrioTbl[] 由任务的优先级查到任务控制块的地址。
uC/OS-II 主要就是利用任务控制快OS_TCB、就绪表(ready list)和控制块优先级表OSTCBPrioTbl[]来进行任务调度的。
任务调度程序OSSched()首先由就绪表(ready list)中找到当前系统中处于就绪态的优先级最高的任务,然后根据其优先级由控制块优先级表OSTCBPrioTbl[] 取得相应任务控制块的地址,由OS_TASK_SW()程序进行运行环境的切换。
将当前运行环境切换成该任务的运行环境,则该任务由就绪态转为运行态。
当这个任务运行完毕或因其它原因挂起时,任务调度程序OSSched()再次到就绪表(ready list)中寻找当前系统中处于就绪态中优先级最高的任务,转而执行该任务,如此完成任务调度。
若在任务运行时发生中断,则转向执行中断程序,执行完毕后不是简单的返回中断调用处,而是由OSIntExit()程序进行任务调度,执行当前系统中优先级最高的就绪态任务。
当系统中所有任务都执行完毕时,。
实验二-UCOS-II任务管理
班级学号姓名同组人实验日期室温大气压成绩实验二 UCOS-II任务管理一、实验目的1、掌握UCOS-II中任务管理的函数的应用。
2、掌握UCOS-II在STM32平台下对硬件的控制。
3、掌握开发UCOS-II应用的程序结构。
二、实验步骤1、UCOSII工作原理UCOSII提供系统时钟节拍,实现任务切换和任务延时等功能。
这个时钟节拍由OS_TICKS_PER_SEC(在os_cfg.h中定义)设置,一般我们设置UCOSII的系统时钟节拍为1ms~100ms。
本次实验利用STM32的SYSTICK定时器来提供UCOSII时钟节拍。
UCOSII的任何任务都是通过一个叫任务控制块(TCB)的东西来控制的,每个任务管理块有3个最重要的参数:(1)任务函数指针;(2)任务堆栈指针;(3)任务优先级。
在UCOSII中,使用CPU的时候,优先级高(数值小)的任务比优先级低的任务具有优先使用权,即任务就绪表中总是优先级最高的任务获得CPU使用权,只有高优先级的任务让出CPU使用权(比如延时)时,低优先级的任务才能获得CPU使用权。
UCOSII不支持多个任务优先级相同,也就是每个任务的优先级必须不一样。
任务的调度其实就是CPU 运行环境的切换,即:PC指针、SP指针和寄存器组等内容的存取过程UCOSII的每个任务都是一个死循环。
每个任务都处在以下5种状态之一的状态下,这5种状态是:睡眠状态、就绪状态、运行状态、等待状态(等待某一事件发生)和中断服务状态。
睡眠状态,任务在没有被配备任务控制块或被剥夺了任务控制块时的状态。
就绪状态,系统为任务配备了任务控制块且在任务就绪表中进行了就绪登记,任务已经准备好了,但由于该任务的优先级比正在运行的任务的优先级低,还暂时不能运行,这时任务的状态叫做就绪状态。
运行状态,该任务获得CPU使用权,并正在运行中,此时的任务状态叫做运行状态等待状态,正在运行的任务,需要等待一段时间或需要等待一个事件发生再运行时,该任务就会把CPU的使用权让给别的任务而使任务进入等待状态。
嵌入式实时操作系统uCOS-II原理(课件PPT) μCOS-II中的任务管理
1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 3
1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 4
1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0
5 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0
或
prio=29 0 0 0 1 1 1 0 1
y = OSUnM图5a-6p在T就bl绪[O表S中R查d找yG最高rp优];先级别任务的过程 prio = (INT8U)((y << 3)
任当务控应制用块结程构序的主调要用成员函数OSTaskCreate( )
任务及控任制务块控(O制S_块TC链B)表 t…y创统进任务控这表…pOssIII数具链的表…ettNNNrrd…S建函行务控制个的TTTuue任_会有接任。fcc188Stts任 任 制 认6UU务T一数初从制块任头μ栈务理控tooUr当由按相为务即Kuss控__c个始空块各务部O务务块和ttt制*C指有的制cc进于用应一,相oSObbOOOs/块任化任,个控T_S**SSS控的的管行这户数个故当tT优针关O块OOC链TTTcbCSS务。务然成制BCCCS表系 些提量链这于BTT{BBBI制 身 任理先、 的-SCCDSP时这控后员块ntIBBtr统任供的表个是kliayi块 份 务的NPPot级任 属I;,个制用进链t;r;te初务的任。链一re用x///;vt///就 证 是这函块任行入(任任任/;;别务 性//始控任务表些指///指务务务来指个数链务赋到)向相 , 不等的 的向化制务控叫空等的的向来任记函首表的值任后待当优前时块数制做白当 没 能务为一当 表一的前先一空数先获属,务堆录个,还为块空的时状级个任任于 有 被栈些前 就会为取性最控任限态别任务初没系并任身任栈务务标(务是 任 系控与状 叫调 被 一 对后 制顶控始有统 把务份志节控控制务的用创个任再块制拍一务统制任态做块化对创它块证指制块数块的链系建任务把链针个控承的函应建们链。)务任、的块表指堆指管任务针针
uCOS-II任务调度过程
uCOS-II任务调度过程ucos-II是基于任务优先级抢占式任务调度法的,就是内核在管理调度时,调用任务切换函数(一般为SSched()),在该函数中将此时已处于就绪状态(条件一)并且为最高优先级(条件二)的任务的保存于其栈中的相应信息压入cpu寄存器中(软中断完成),然后cpu 开始运行该任务的代码。
内核是何时进行任务调度的呢?虽然uC/OS-II是可被剥夺资源的内核(高优先级可强行占有低优先级正在使用的资源),但此事发生的前提是内核实时"检测"到了更高就绪的优先级了,那么内核是怎样来实时检测的呢?带着这个问题让我们再来看看任务的结构——里边有函数OSTimeDly(OS_TICKS_PER_SEC),一看就知道这是个延时函数,除了延时外它还会有其他用途呢?经查看其源码了解到里边有一条代码:OSSched(),对,函数OSTimeDly()的作用就是将此时正在运行的函数挂起(保存任务控制块OS_TCB中的相应信息)(任务控制块OS_TCB是系统分配给每个任务的信息存储单元),然后调用函数OSSched()进行任务切换,进而执行就绪的最高优先级任务。
此刻,我们了解到uCOS-II的任务切换是在执行的任务中调用延时函数OSTimeDly()进行的。
现在,还有一个问题还没解决,就是当延时到了,内核如何将资源返还给被延时挂起的任务?我们先来了解一下任务控制块(OS_TCB),任务控制块是一个数据结构,当任务的cpu使用权被剥夺时,uC/OS-II用它来保存该任务的状态。
当任务重新得到cpu使用权时,任务控制块确保任务从当时被中断的那一点丝毫不差地继续执行。
OS_TCB全部驻留在RAM中。
在OS_TCB中有一项时间延时项OSTCBDly,调用函数OSTimeDly()过程中有一步骤就是给OSTCBDly赋延时值。
uC/OS—II中有函数OSTimTick(),叫时钟节拍函数,它的一项工作就是给每个用户任务控制块OS_TCB中的时间延迟项OSTCBDly减1(如果该项不为零),当某项任务的任务控制块中的时间延时项OSTCBDly减为0时,这个任务就进入了就绪态,等待任务切换。
uCOS2任务调度过程
(转)uCOS-II任务调度过程ucos-II是基于任务优先级抢占式任务调度法的,就是内核在管理调度时,调用任务切换函数(一般为SSched()),在该函数中将此时已处于就绪状态(条件一)并且为最高优先级(条件二)的任务的保存于其栈中的相应信息压入cpu 寄存器中(软中断完成),然后cpu开始运行该任务的代码。
内核是何时进行任务调度的呢?虽然uC/OS-II是可被剥夺资源的内核(高优先级可强行占有低优先级正在使用的资源),但此事发生的前提是内核实时"检测"到了更高就绪的优先级了,那么内核是怎样来实时检测的呢?带着这个问题让我们再来看看任务的结构——里边有函数OSTimeDly(OS_TICKS_PER_SEC),一看就知道这是个延时函数,除了延时外它还会有其他用途呢?经查看其源码了解到里边有一条代码:OSSched(),对,函数OSTimeDly()的作用就是将此时正在运行的函数挂起(保存任务控制块OS_TCB中的相应信息)(任务控制块OS_TCB是系统分配给每个任务的信息存储单元),然后调用函数OSSched()进行任务切换,进而执行就绪的最高优先级任务。
此刻,我们了解到uCOS-II的任务切换是在执行的任务中调用延时函数OSTimeDly()进行的。
现在,还有一个问题还没解决,就是当延时到了,内核如何将资源返还给被延时挂起的任务?我们先来了解一下任务控制块(OS_TCB),任务控制块是一个数据结构,当任务的cpu使用权被剥夺时,uC/OS-II用它来保存该任务的状态。
当任务重新得到cpu使用权时,任务控制块确保任务从当时被中断的那一点丝毫不差地继续执行。
OS_TCB全部驻留在RAM中。
在OS_TCB中有一项时间延时项OSTCBDly,调用函数OSTimeDly()过程中有一步骤就是给OSTCBDly赋延时值。
uC/OS—II中有函数OSTimTick(),叫时钟节拍函数,它的一项工作就是给每个用户任务控制块OS_TCB中的时间延迟项OSTCBDly减1(如果该项不为零),当某项任务的任务控制块中的时间延时项OSTCBDly减为0时,这个任务就进入了就绪态,等待任务切换。
实验二UCOS-II任务管理(DOC)
班级学号姓名同组人实验日期室温大气压成绩实验二 UCOS-II 任务管理一、实验目的1、掌握 UCOS-II 中任务管理的函数的应用。
2、掌握 UCOS-II 在 STM32平台下对硬件的控制。
3、掌握开发 UCOS-II 应用的程序构造。
二、实验步骤1、 UCOSII工作原理UCOSII供给系统时钟节拍,实现任务切换和任务延时等功能。
这个时钟节拍由OS_TICKS_PER_SEC(在 os_cfg.h 中定义)设置,一般我们设置 UCOSII的系统时钟节拍为1ms~100ms。
本次实验利用 STM32的SYSTICK准时器来供给 UCOSII时钟节拍。
UCOSII的任何任务都是经过一个叫任务控制块( TCB)的东西来控制的,每个任务管理块有 3 个最重要的参数:( 1)任务函数指针; (2) 任务货仓指针; (3) 任务优先级。
在UCOSII中,使用 CPU的时候,优先级高(数值小)的任务比优先级低的任务拥有优先使用权,即任务就绪表中老是优先级最高的任务获取 CPU使用权,只有高优先级的任务让出 CPU使用权(比方延时)时,低优先级的任务才能获取 CPU使用权。
UCOSII不支持多个任务优先级相同,也就是每个任务的优先级一定不相同。
任务的调动其实就是 CPU 运转环境的切换,即: PC指针、 SP指针和存放器组等内容的存取过程UCOSII的每个任务都是一个死循环。
每个任务都处在以下5种状态之一的状态下,这 5种状态是:睡眠状态、就绪状态、运转状态、等候状态 ( 等候某一事件发生 ) 和中断服务状态。
睡眠状态,任务在没有被装备任务控制块或被剥夺了任务控制块时的状态。
就绪状态,系统为任务装备了任务控制块且在任务就绪表中进行了就绪登记,任务已经准备好了,但因为该任务的优先级比正在运转的任务的优先级低,还临时不可以运转,这时任务的状态叫做就绪状态。
运转状态,该任务获取 CPU使用权,并正在运转中,此时的任务状态叫做运转状态等候状态,正在运转的任务,需要等候一段时间或需要等候一个事件发生再运转时,该任务就会把 CPU的使用权让给其余任务而使任务进入等候状态。
uCOS-II的任务切换总结
uC/OS-II的任务切换总结uC/OS-II的任务切换归根到底都是由以下三个函数引起的:∙OSStart();∙OSIntExit();∙OS_Sched();一、OSStart():OSStart()函数是uC/OS-II任务调度的引导函数,它调用更底层的函数OSStartHighRdy()来完成最初的任务切换;OSStartHighRdy()唯一地在OSStart()函数中被调用。
OSStart()函数代码如下:/**********************************************************/void OSStart (void){INT8U y;INT8U x;if (OSRunning == FALSE) {y = OSUnMapTbl[OSRdyGrp];x = OSUnMapTbl[OSRdyTbl[y]];OSPrioHighRdy = (INT8U)((y << 3) + x);OSPrioCur = OSPrioHighRdy;OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];OSTCBCur = OSTCBHighRdy;OSStartHighRdy();}}/**********************************************************/而OSStartHighRdy()函数需要用户移植实现,主要的工作是:OSRunning = TRUE;调用OSTaskSwHook()函数;设置处理器的堆栈指针寄存器为 OSTCBHighRdy->OSTCBStkPtr;恢复所有处理器的寄存器内容(不包括堆栈指针寄存器和PC寄存器);恢复PC寄存器并开始执行PC指向的指令。
二、OSIntExit():OSIntExit()函数由中断服务代码调用,用户的中断服务代码要求如下:把全部CPU寄存器(包括堆栈指针寄存器和PC寄存器)推入当前任务堆栈;调用OSIntEnter()函数或OSIntNesting++;执行用户的中断处理代码;调用OSIntExit()。
μ COS-Ⅱ操作系统的任务切换
μ COS-Ⅱ操作系统的任务切换
司新生
【期刊名称】《数字技术与应用》
【年(卷),期】2010(000)006
【摘要】μCOS-Ⅱ操作系统是一个多任务占先式实时操作系统,每一个任务由三部分组成,任务控制块,任务的私有堆栈、任务代码.每一个任务有一个决定其重要性的任务优先级,系统通过任务就绪表来进行任务的切换,就绪的任务在任务就绪表中设置其标志位,退出就绪的任务在就绪表中撤消其标志位.任务的切换过程就是通过任务就绪表找到优先级最高的任务,保存原来运行任务的上下文到该任务的私有堆栈中,从最高优先级的任务私有堆栈中复制断点数据到工作寄存器中,pc指针指向该任务的代码段,实现了任务的切换.
【总页数】2页(P12-13)
【作者】司新生
【作者单位】鹤壁职业技术学院,河南鹤壁,458030
【正文语种】中文
【中图分类】G642
【相关文献】
1.基于实时多任务操作系统μCOS-Ⅱ的C8051F系列单片机应用系统开发 [J], 黄亮亮;朱欣华
2.不使用实时操作系统实现任务定时切换 [J], 袁建州;王智晶;于丽娜
3.μC/OS-Ⅱ操作系统的任务切换 [J], 司新生
4.嵌入式操作系统任务切换方法对比分析 [J], 孙利锋
5.基于μcos-Ⅲ操作系统的平衡智能车设计与实 [J], 高娟;马鹏飞;马俊成;王争;谢双;刘尚麟;王思齐;陆登明
因版权原因,仅展示原文概要,查看原文内容请购买。
uCOSII原理及应用
任务控制块
用于存储任务的运行状态和控制信息,包括任 务的优先级、状态、堆栈指针等。
任务切换函数
用于实现任务之间的切换,包括保存当前任务的上下文和恢复下一个任务的上 下文。
ucosii的任务管理
创建任务
通过调用ucosii提供的函数, 创建新的任务并分配相应的 资源。
在物联网应用中,ucosii能够为各种智能硬件提供统一的操 作系统平台,实现设备的互联互通和智能化管理。同时, ucosii还提供了丰富的中间件和驱动程序,方便开发者快速 开发出各种智能硬件和应用软件。
ucosii在嵌入式系统中的应用
嵌入式系统是指嵌入到硬件中的计算机系统,具有特定的功能和性能要求。ucosii作为一种实时操作 系统,在嵌入式系统中也有着广泛的应用。
调试工具
使用JTAG、SWD等调试工具,通过串口、网络等方式与目标板进行通信,实现程序的 下载、运行、断点设置等操作。
调试步骤
首先确认硬件连接正确,然后通过调试工具将程序下载到目标板中,设置断点并运行程 序,观察程序运行过程中变量的变化和程序的执行流程。
常见问题
硬件连接问题、调试工具配置问题、程序编译错误等。
ucosii的性能分析
性能指标
响应时间、吞吐量、资源利用率等。
分析方法
通过代码审查、性能测试、瓶颈分析等方法,找出影响性能的 关键因素,如算法复杂度、内存访问模式、IO性能等。
优化建议
针对分析结果,提出优化建议,如改进算法、优化数据结 构、减少IO操作等。
ucosii的优化建议
算法优化
通过改进算法,减少计算量和复杂度,提高程序执行效率。
易用性
UCOS-II操作系统详解
VμC/OS 和μC/OS-II是专门为计算机的嵌入式应用设计的,绝大部分代码是用C语言编写的。
CPU 硬件相关部分是用汇编语言编写的、总量约200行的汇编语言部分被压缩到最低限度,为的是便于移植到任何一种其它的CPU 上。
工作原理编辑uC/OS-II是一种基于优先级的可抢先的硬实时内核。
要实现多任务机制,那么目标CPU必须具备一种在运行期更改PC的途径,否则无法做到切换。
不幸的是,直接设置PC指针,还没有哪个CPU支持这样的指令。
但是一般CPU都允许通过类似JMP,CALL这样的指令来间接的修改PC。
我们的多任务机制的实现也正是基于这个出发点。
事实上,我们使用CALL指令或者软中断指令来修改PC,主要是软中断。
但在一些CPU上,并不存在软中断这样的概念,所以,我们在那些CPU上,使用几条PUSH指令加上一条CALL指令来模拟一次软中断的发生。
在uC/OS-II里,每个任务都有一个任务控制块(Task Control Block),这是一个比较复杂的数据结构。
在任务控制块的偏移为0的地方,存储着一个指针,它记录了所属任务的专用堆栈地址。
事实上,在uC/OS-II内,每个任务都有自己的专用堆栈,彼此之间不能侵犯。
这点要求程序员在他们的程序中保证。
一般的做法是把他们申明成静态数组。
而且要申明成OS_STK类型。
当任务有了自己的堆栈,那么就可以将每一个任务堆栈在那里记录到前面谈到的任务控制快偏移为0的地方。
以后每当发生任务切换,系统必然会先进入一个中断,这一般是通过软中断或者时钟中断实现。
然后系统会先把当前任务的堆栈地址保存起来,仅接着恢复要切换的任务的堆栈地址。
由于哪个任务的堆栈里一定也存的是地址(还记得我们前面说过的,每当发生任务切换,系统必然会先进入一个中断,而一旦中断CPU就会把地址压入堆栈),这样,就达到了修改PC为下一个任务的地址的目的。
任务管理编辑uC/OS-II 中最多可以支持64 个任务,分别对应优先级0~63,其中0 为最高优先级。
Qsys与uCosii任务切换
Qsys与uC/OS-II学习笔记5:任务切换上个笔记提到调用任务延时函数后,系统将会进行任务切换,否则当前运行任务就会一直霸占着CPU的使用权。
那么这个任务延时函数中到底有什么奥秘?调用它为什么能够让任务切换自如?这个笔记咱就要揭开uC/OS-II的一大设计精髓——任务切换。
特权同学并非软件工程或是计算机科班出身,还真没学过什么操作系统,对于CPU 内部架构和工作机制的理解和认识完全靠自身的实践、摸索加一些教科书的研读。
对于一些概念的阐述或许不够专业,如果有些偏差也非常欢迎大家提出来加以纠正,但是我想这些“草根”式的图文或许多少能够帮助大家快速的理解和认识一些工作机理,但愿“八九不离十”应该是形容这种状态比较合适的词汇吧。
其实如果能起到这样的效果,那么对这些文章而言也就足够。
毕竟一板一眼、中规中矩的教科书我们看得太多了,真的是有些审美疲劳了。
因为要说任务调度的机理,那么我们不得不先把几乎所有嵌入式处理器相关的书籍中都会提及的中断概念再提一下。
虽然讲中断的书满大街都是,但是我想像图1这样一个简单示意图就能够把中断说清楚的还真不多(怎么有点“王婆卖瓜自卖自夸”的嫌疑,脸红中~~)。
一个“裸奔”的CPU软件,无非就是一个main函数里面while(1)中包办所有功能,偶尔来个中断响应一些实时性要求较高的处理,仅此而已。
那么,很显然,中断响应时有一个脱离当前main函数的举动发生,想要让中断响应前后CPU回到原有的main函数执行状态,则必须有一些额外的工作要干,第3和6步的出栈、入栈便是。
这个示意图中,大家需要明白,当某个函数或某些指令占用CPU时,意味着CPU中的寄存器存储着和当前处理状态相关的各种中间数据信息;同样的道理,当中断函数占有CPU数据时,CPU中的寄存器存储着和中断函数相关的各种中间数据。
堆栈是专门开辟的一片存储空间,用于和CPU寄存器相映射。
一个在main函数中运行着的程序(包括在它的子函数中运行),如果被一个中断信号打断后去执行中断处理,最后返回,这样一个过程,发生了以下一些事情:1.应用程序(即Main函数)中执行某条指令,此时应用程序控制CPU的使用权,表现为占有CPU寄存器。
ucos-ii工作原理
ucos-ii工作原理uC/OS-II(Micro C/Operating System-II)是一种用于嵌入式系统的实时操作系统。
它的工作原理可以简单归纳为以下几个步骤:1. 任务管理:uC/OS-II使用优先级调度算法管理多个任务。
每个任务都有一个优先级,高优先级的任务会优先执行。
uC/OS-II通过一个任务控制块(TCB)来管理每个任务的信息,包括任务的状态、堆栈信息、优先级等。
2. 中断处理:uC/OS-II可以处理多种类型的中断。
当发生中断时,uC/OS-II会根据中断类型进行相应的处理,并且可以自动切换到中断服务程序(ISR)进行执行。
中断服务程序中的代码通常是短小且高效的,用于处理特定的中断事件。
3. 任务切换:uC/OS-II使用抢占式的任务调度方式,因此任务切换可以发生在任何时刻。
当一个任务的时间片用尽或者有更高优先级的任务需要执行时,uC/OS-II会保存当前任务的上下文信息,并切换到下一个任务的执行。
任务切换时,uC/OS-II会保存当前任务的栈指针等信息,并从下一个任务的栈指针中恢复相应的上下文,以使下一个任务继续执行。
4. 事件同步:uC/OS-II提供了多种事件同步机制,如信号量、事件标志、消息邮箱等,用于任务之间的同步和通信。
这些机制可以帮助任务之间按照一定的顺序进行执行,实现数据共享和互斥访问等功能。
5. 内存管理:uC/OS-II提供了内存管理功能,可以动态分配和释放内存块。
这种内存管理机制可以帮助节省内存空间,提高系统的效率。
总而言之,uC/OS-II通过任务管理、中断处理、任务切换、事件同步和内存管理等机制,实现了对嵌入式系统的实时调度和资源管理,以提供稳定、可靠的操作系统支持。
手把手,嘴对嘴,讲解UCOSII嵌入式操作系统的任务调度策略(五)
⼿把⼿,嘴对嘴,讲解UCOSII嵌⼊式操作系统的任务调度策略(五)整个UCOSII嵌⼊式操作系统的任务调度策略便是如此,现在进⾏⼀个总结:①某个任务在执⾏中,每隔⼀定周期发⽣滴答时钟中断,在中断中遍历整个任务链表,更新每个任务的延时时间,修改就绪状态。
②任务执⾏完毕后,进⼊延时函数,在延时函数中会把当前任务挂起(清空当前任务的就绪状态,使其进⼊未就绪状态),然后根据查表发找到在就绪任务中,优先级最⾼的那⼀个任务。
③找到新任务以后,⼈⼯强制发⽣⼀个中断,保存上个任务的堆栈信息,弹出下个任务的堆栈信息,同时更改PC指针,进⾏任务切换。
经过以上三个步骤,便可以完成任务的调度。
现在回到第⼀篇提出的那个问题:UCOSII到底是如何保证它的实时性的呢?如果任务的调度都是发⽣在当前任务进⼊延时之后,似乎操作系统根本⽆法⾃⾝的保障实时性。
⽐如⼀个优先级最低的任务由于某些处理⾮常耗费时间,它⼀直⽆法进⼊延时,导致⽆法进⼊任务切换,那么优先级⾼的任务反⽽是⼀只都⽆法被执⾏了……同样在第⼀篇说过,UCOSII系统除了在当前任务进⼊延时函数会发⽣调度之外,还有别的时机会进⾏任务切换: 1.当前任务进⼊了延时。
2.当前任务被挂起。
3.当前任务执⾏时,发⽣了某些中断。
第1点我们已经全部讲完,第2点⾮常好理解,我们现在看⼀个函数:OSTaskSuspend()这个函数的作⽤是把某个任务挂起(也就是不进⾏调度),现在来分析⼀个实例:有⼀个任务调⽤了这个函数:void App1_task(void *pdata){while(1){if (OS_ERR_NONE != OSTaskSuspend(OS_PRIO_SELF)){Dbg_SendStr("App1_task Suspend Error£¡\r\n");}delay_ms(10);};}当前任务执⾏了红⾊代码之后,便会把⾃⾝挂起来,如果没有再别的地⽅对它进⾏激活,这个任务便永远也不会执⾏下去了。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
UC/OS-II学习笔记之——任务切换是怎样实现的问题是,
o Uc/OS-II如何切换任务?通过任务调度器OS_Sched(),那么谁在调用这个函数?
o CPU在这里肯定有作用,因为任务切换必然涉及到CPU寄存器的入栈和出栈,
那么这一块工作是如何完成的?
书上讲:为了做到任务切换,运行OS_TASK_SW(),人为模仿一次中断。
中断服务子程序或陷阱处理(trap hardler),也称作事故处理(exception handler),必须给汇编语言函数OSCtxSw()提供中断向量[1.92]。
那么,“人为模仿一次中断”是什么意思?
是指:OS_TASK_SW()触发了一个中断,由中断完成了任务切换?
阅读源代码,查找答案……
#define OS_TASK_SW()OSCtxSw()//这是一个宏调用,定义在os_cpu.h,Os_cpu_a.asm中定义了OSCtxSw
NVIC_INT_CTRL EQU0xE000ED04
NVIC_PENDSVSET EQU0x10000000
;******************************************************************************
;PERFORM A CONTEXT SWITCH(From task level)
;void OSCtxSw(void)
;
;Note(s):1)OSCtxSw()is called when OS wants to perform a task context switch.This function
;triggers the PendSV exception which is where the real work is done.
;******************************************************************************
OSCtxSw
LDR R0,=NVIC_INT_CTRL;Trigger the PendSV exception(causes context switch) LDR R1,=NVIC_PENDSVSET
STR R1,[R0]
BX LR
注释说明该段汇编代码触发了一个PendSV的异常。
在《cortex-M3权威指南》中搜索关键词“PendSV”,可悬挂请求pend able request,在《2.9中断和异常》表7.1“系统异常清单”所列举的异常类型中,定义PendSV为“为系统设备而设的可悬挂请求”[2.109]
(中断优先级PendSV>SysTick>外部中断)
那么,这个PendSV异常的作用到底是什么?
PendSV典型使用场合是上下文切换(任务间切换)。
上下文被触发的条件是:[2.125] o系统滴答定时器(SYSTICK)中断(轮转调度中需要)
o执行一个系统调用(TASK level code)
个中事件的流水账记录如下:
(1)任务A呼叫SVC来请求任务切换(例如,等待某些工作完成)
(2)OS接收到请求,做好上下文切换的准备,并且悬起一个PendSV异常。
(3)当CPU退出SVC后,它立即进入PendSV,从而执行上下文切换。
(4)当PendSV执行完毕后,将返回到任务B,同时进入线程模式。
(5)发生了一个中断,并且中断服务程序开始执行
(6)在ISR执行过程中,发生SysTick异常,并且抢占了该ISR。
(7)OS执行必要的操作,然后悬起PendSV异常以作好上下文切换的准备。
(当SysTick退出后,回到先前被抢占的ISR中,ISR继续执行
(9)ISR执行完毕并退出后,PendSV服务例程开始执行,并且在里面执行上下文切换
(10)当PendSV执行完毕后,回到任务A,同时系统再次进入线程模式
中断正在执行,禁止上下文切换。
否则中断被延时,而延时时间不可预知——这是实时系统不能容忍的。
早期解决办法,无中断执行时,才执行上下文切换(切换期间无法响应中断)。
弊端在于任务切换可能被拖延的很久。
[2.126]
PendSv可以解决这个问题,OS会悬起一个PendSv,PendSv异常处理函数处理上下文切换请求——
(1).如果还有未处理完的ISR(图7.17后半段SysTick触发了上下文切换),PendSv被悬起,延迟上下文切换请求,直到处理完ISR后才执行上下文切换;
(2).如果没有任何ISR(图7.17前半段),则立刻调用PendSV异常处理函数完成上下文切换。
需要把PendSv编程为最低优先级的异常。
也就是说,PendSv可以像普通中断一样被悬起,OS可以利用它缓期执行一个异常(PendSV)——在其它重要任务完成之后才执行动作(上下文切换)。
悬挂PendSv的方法是:往NVIC的PendSv悬起寄存器中写1。
悬起后,如果优先级不够高,则将缓期执行。
ICSR(Interrupt Control and State Register0xE000ED04)[bit28]
具体的程序调试:
执行系统函数(悬起PendSV异常的手段之一)OSTimeDlyHMSM(),调用OSTimeDly(),调用task scheduler OS_Sched(),终于执行这个宏调用,调用执行OSCtxSw(),(go to definition of OSCtxSw却不能跳转到汇编代码!),汇编代码把1写入中断控制及状态寄存器寄存器ICSR[bit28]从而悬起一个PendSV异常,这是上图7.17中的步骤2,
Void OS_Sched(void)//任务调度器
{
关中断;
if(没有中断&&没有关调度器)
OS_TASK_SW();//在这里悬起PendSV异常,开中断前先在PendSV Handler设置断点开中断;
}
执行完开中断语句后,程序立刻跳到PendSV异常处理函数PendSV Handler(在此处),这个跳转是如何完成的?具体的入栈、出栈涉及到CPU的哪些寄存器,操作是如何完成的?
执行完PendSV Handler后跳转到空闲任务,实现了任务切换:。