TinyOS51嵌入式操作系统微小内核课件_第1页
TinyOS51嵌入式操作系统微小内核课件_第2页
TinyOS51嵌入式操作系统微小内核课件_第3页
TinyOS51嵌入式操作系统微小内核课件_第4页
TinyOS51嵌入式操作系统微小内核课件_第5页
已阅读5页,还剩89页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第5章TinyOS51嵌入式操作系统微小内核5.1基础知识5.2最简单的多任务模型5.3协作式多任务操作系统5.4时间片轮询多任务操作系统5.5信号量5.6消息邮箱第5章TinyOS51嵌入式操作系统微小内核5.1第5章TinyOS51嵌入式操作系统本章说明:

操作系统(OS)是计算机专业的一门专业基础课,理论教材比较抽象。本章所学内容是从80C51单片机应用出发,主要介绍一个基于80C51系列单片机,且全部使用C语言编写的开源操作系统微小内核——TinyOS51,其目的是帮助大家建立与操作系统有关的基本概念,如:任务,上下文与可重入性,任务的并发性与调度,以及信号量与消息邮箱的实现机理与程序设计基础,为今后深入学习专业级的操作系统与应用技术做好铺垫。2第5章TinyOS51嵌入式操作系统本章说明:2第5章TinyOS51嵌入式操作系统5.1基础知识5.1.1概述(介绍以下几个基本概念)1、协作式与抢占式OS2、用户任务(UserTask)与系统任务(SystemTask)

3、并发性(Concurrent)与调度(Scheduling)4、任务状态5、任务之间的关系6、临界资源(CriticalResources)与临界区(CriticalSection)7、上下文切换(ContextSwitch)8、可重入性(Reentrant)

3第5章TinyOS51嵌入式操作系统5.1基础知识第5章TinyOS51嵌入式操作系统1、协作式与抢占式OS

在操作系统的发展过程中,先后有2种形式的多任务管理机制,即协作式与抢占式。

协作式:如果任务切换的时机完全取决于正在运行的任务,那么这样的操作系统就是协作式多任务操作系统。即任务执行时的权利比操作系统还大,只有等正在运行的任务完成后,才会将控制权交给操作系统,此时才能执行下一个任务。一旦某个任务运行出错,则导致整个系统挂起(Pending)。抢占式:如果任务优先运行的决定权取决于操作系统,而且即使有一个任务死掉,而系统仍能正常工作,那么这样的操作系统就是抢占式多任务操作系统。4第5章TinyOS51嵌入式操作系统1、协作式与抢占式O第5章TinyOS51嵌入式操作系统2、用户任务(UserTask)与系统任务(SystemTask)

在单片机应用系统设计中,为了提高系统的透明性、可移植性和强壮性,常将一个应用程序分解为许多“可执行的程序单元”。在监控模块的管理下,以“实参”和“形参”形式完成各模块之间的调用和返回。

当使用操作系统时,如果将这些“可执行的程序单元”进行分类,即可得到在操作系统调度下的“用户任务”。此时,任务之间的信息传递是通过“异步”的方式来完成,即由操作系统的各种“通信”机制来实现,比如,信息量与消息邮箱等。

与上述任务不同,操作系统有自己的“系统任务”,比如,空闲任务等。5第5章TinyOS51嵌入式操作系统2、用户任务(Use第5章TinyOS51嵌入式操作系统3、并发性(Concurrent)与调度(Scheduling)调度器是每个内核的心脏,调度器提供决定何时执行何任务的算法。为了满足实时性要求,当有多个任务均处于就绪状态时,嵌入式实时操作系统可以让“一个已经就绪的高优先级任务”抢占另一个“正在运行的低优先级任务”的运行权而进入运行状态。如下图所示,任务A运行中,被任务B抢占而进入执行状态。它们的运行时间有重叠部分,这种运行方式称之为“并发运行”。6第5章TinyOS51嵌入式操作系统3、并发性(Conc第5章TinyOS51嵌入式操作系统在实际的应用中,大多数嵌入式实时操作系统(RTOS)内核支持两种普遍的调度算法:基于优先级的抢占式调度和时间轮询式调度。7第5章TinyOS51嵌入式操作系统在实第5章TinyOS51嵌入式操作系统采用基于优先级“抢占式”的调度算法,就意味着一个“已经就绪的高优先级任务”可以剥夺另一个“正在运行的低优先级任务”的运行权而进入运行状态。

如下图所示:8第5章TinyOS51嵌入式操作系统采用第5章TinyOS51嵌入式操作系统

时间轮询调度为每个任务提供同份额的cpu执行时间。由于纯粹的时间轮询调度不能满足实时性系统要求,取而代之的是基于优先级抢占式调度扩充时间轮询调度,即对同样优先级的任务使用时间片获得相等的cpu分配时间,不同优先级的具有抢占权。9第5章TinyOS51嵌入式操作系统时间第5章TinyOS51嵌入式操作系统4、任务状态无论用户任务还是系统任务,在如何时候,每个任务至少包含:就绪(ready)、运行(running)、阻塞(blocked)在内的状态。随着实时系统的运行,每个任务根据简单的有限状态自动机(FSM)逻辑,从一个状态迁移到另一个状态。虽然内核可以定义多个任务状态组,但典型的OS中至少有3个主要的状态:就绪状态;运行状态;阻塞状态10第5章TinyOS51嵌入式操作系统4、任务状态10第5章TinyOS51嵌入式操作系统就绪状态:当一个任务创立并准备运行时,内核将其放入就绪状态。但不能运行,因为有一个更高优先级的任务在执行,内核调度器根据优先级决定哪个任务先迁移到运行状态,但处于就绪状态的任务不能直接迁移到阻塞状态。运行状态:操作系统可让处于运行状态的低优先级任务暂停运行,转而执行另一个处于就绪状态的高优先级任务,这样正运行的任务就从运行状态迁移到了就绪状态。阻塞状态:当任务已经请求一个还不能用的资源,或已经请求等待某些事件的发生,或自身要延时一段时间,则任务都从运行状态迁移到阻塞状态。如果没有阻塞状态,那么较低优先级的任务将不能运行;如果更高优先级的任务没有设置成阻塞状态,则可能导致cpu处于饥饿状态。11第5章TinyOS51嵌入式操作系统就绪状态:当一个任务第5章TinyOS51嵌入式操作系统图5.4任务执行状态图12第5章TinyOS51嵌入式操作系统图5.4任务执行第5章TinyOS51嵌入式操作系统5、任务之间的关系由于内存中可同时存在多个任务,且任务之间可能存在直接和间接的相互作用关系。直接作用只发生在相关任务之间,其相互之间的联系是有意安排的,它们需要相互协作来共同完成一个任务。间接作用是指任务之间因为某种中介(如共同使用同一设备)而发生了一定的关系,也就是说,它可以发生在相关任务之间,也可以发生在无关任务之间。从另一个角度来看任务间的相关关系,可以将任务之间的关系提炼为同步(Synchronization)与互斥(Exclusion)两种。13第5章TinyOS51嵌入式操作系统5、任务之间的关系1第5章TinyOS51嵌入式操作系统任务同步:任务间的同步是一种直接作用,任务同步是指系统中的多个任务之间存在某种时序关系,需要相互协作才能共同完成一个任务。比如,一个任务运行到某个时间点时,需要另一个任务为它提供消息,在未获得消息之前,该任务处于阻塞状态,获得消息后被唤醒进入就绪状态。

任务互斥:任务间的互斥是一种间接作用,由于内存中的多个任务要求共享某一资源,而有些资源必须互斥,因此各任务之间只能竞争使用这些资源。14第5章TinyOS51嵌入式操作系统任务同步:14第5章TinyOS51嵌入式操作系统6、临界资源(CriticalResources)与临界区(CriticalSection)从上面的分析可以看出,任务间的互斥涉及到共享资源的竞争使用,因此竞争使用这些资源的任务在执行使用这些资源的程序时也会受到一定的限制,从而也就引出了临界资源与临界区的概念。(1)临界资源在操作系统中,将一次只允许一个任务(中断)使用的资源称之为临界资源。(2)临界区在操作系统中将并发任务中访问临界资源的程序称之为临界区,临界区也常叫做互斥区。15第5章TinyOS51嵌入式操作系统6、临界资源(Cri第5章TinyOS51嵌入式操作系统7、上下文切换(ContextSwitch)当硬件机制决定接受哪个中断时,则当前指令流暂停,转而执行一个上下文切换,而后cpu从执行当前指令流转换到执行另外的指令流。这种在中断发生时执行的替换指令集就是中断服务程序。将被中止的任务的“上下文信息”保存到“堆栈”中,当任务在重新运行时,则要将堆栈中的“上下文信息”在恢复到cpu的各个寄存器中,通过这样的上下文切换,可实现cpu的“无缝”接续运行。调度器从一个任务切换到另一个任务所开销的时间则称之为上下文切换时间。16第5章TinyOS51嵌入式操作系统7、上下文切换(Co第5章TinyOS51嵌入式操作系统图5.5上下文切换示意图17第5章TinyOS51嵌入式操作系统图5.5上下文切第5章TinyOS51嵌入式操作系统8、可重入性(Reentrant)

由于任务的并发性,因此经常会出现调用同一个函数的情况,如果一段程序可以被多个任务同时调用,而不必担心数据被破坏,那么这样的程序就是可重入的程序。一般来说具有可重入性的函数应该只使用局部变量,因为函数的局部变量保存在cpu内部的寄存器或堆栈中,这样调用同一个函数时不会发生冲突。如果函数一定要使用全局变量,那么必须对使用的全局变量进行必要的保护。由此可见,C编译器也应该具有产生可重入代码的能力。18第5章TinyOS51嵌入式操作系统8、可重入性(Ree第5章TinyOS51嵌入式操作系统5.1.2

<setjmp.h>头文件与中止函数about()和退出函数exit()相比,初看起来,goto语句处理异常更可行,但是,goto语句只能在函数内部跳转,即不能从一个函数直接跳转到另一个函数。为此,标准C函数库提供了setjmp()和longjmp()函数,setjmp()函数相当于非局部标号,longjmp()函数相当于goto的作用,从而解决了从一个函数直接跳转到另一个函数的问题,即非局部跳转。头文件<setjmp.h>申明了这些函数及同时所需的jmp_buf数据类型。19第5章TinyOS51嵌入式操作系统5.1.2<s第5章TinyOS51嵌入式操作系统1、非局部远程跳转要实现非局部跳转,都可以使用<setjmp.h>,该头文件提供了以下必须的机制:jmp_buf是一个数组类型变量,可将它当做“标号”数据对象类型来看待,用于存放恢复调用环境所需要的上下文信息。

setjmp将程序的上下文信息保存到跳转“缓冲区(jmp_buf类型的数组)”,当稍后调用longjmp时,将保存在缓冲区中的上下文信息作为返回地点标记;无论在何地调用longjmp,将恢复最后一次由setjmp调用保存在“缓冲区”中的上下文信息,实现非局部远程跳转。20第5章TinyOS51嵌入式操作系统1、非局部远程跳转2第5章TinyOS51嵌入式操作系统2、保存调用环境

下表所示的setjmp是C标准库中的一个函数,setjmp使用jmp_buf类型数组environment变量来记录现在的位置,即变量bp的当前值、堆栈指针值(SP)和函数的返回地址addr15~addr0,供以后longjmp恢复该环境时使用。bp是在SDCC中定义的一个虚拟寄存器,用于简化重入操作。21第5章TinyOS51嵌入式操作系统2、保存调用环境第5章TinyOS51嵌入式操作系统bp是在SDCC中定义的一个虚拟寄存器,用于简化重入操作。书P186,对局部变量与bp做了描述说明以及在堆栈中的变化如下图所示,可参考。22第5章TinyOS51嵌入式操作系统bp是第5章TinyOS51嵌入式操作系统3、jmp_buf由于jmp_buf主要用于保存当前调用的上下文信息,为相应的longjmp调用作为返回地点标记,因此保存在缓冲区jmp_buf中的上下文信息,至少包括变量bp的当前值、堆栈指针的当前值(sp)、高8位和低8位返回地址addr15~addr0。其中的bp是在SDCC51中定义的一个虚拟寄存器,用户不必关心变量bp的变化。23第5章TinyOS51嵌入式操作系统3、jmp_buf第5章TinyOS51嵌入式操作系统4、恢复调用环境longjmp也是C标准库中的一个函数,longjmp表示回到跳转缓冲区jmp_buf类型数组environment变量记录的位置,恢复setjmp调用所保存的变量bp的当前值、堆栈指针值

和函数的返回地址addr15~addr0,转移到setjmp调用处继续执行。24第5章TinyOS51嵌入式操作系统4、恢复调用环境第5章TinyOS51嵌入式操作系统

尽管longjmp会导致程序转移,但它和goto有所不同,其区别如下:

goto语句不能跳出C语言的当前函数;

longjmp只能跳回曾经到过的地方。与此同时,setjmp与longjmp必须协同工作,它们有严格的执行顺序,必须先调用setjmp,然后再调用longjmp,以恢复到先前被保存的“程序执行点”。如果setjmp调用之前执行了longjmp,则程序的执行流程变得不可预见,从而导致程序崩溃而退出。25第5章TinyOS51嵌入式操作系统尽管lo第5章TinyOS51嵌入式操作系统5.1.3变量命名规则1、概述

变量命名使用类匈牙利命名法:变量名最多由三部分组成:作用域,类型,描述。作用域:变量的作用范围,确定管理的有效范围是在函数体外还是在函数体内。类型:该变量的类型,使用小写字母。如:整型等描述:完全准确地描述出该变量所代表的事物。如:Max,Error,New等。26第5章TinyOS51嵌入式操作系统5.1.3变量命第5章TinyOS51嵌入式操作系统2、作用域

作用域是变量名字的第一部分,只有三种情况:局部变量、模块内全局变量、应用程序全局变量,其定义见下表。27第5章TinyOS51嵌入式操作系统2、作用域27第5章TinyOS51嵌入式操作系统3、类型缩写

类型是变量名字第二部分,使用缩写形式,见表5.44、变量描述5、变量类型缩写TinyOS51中定义了一些变量类型,见表5.5

28第5章TinyOS51嵌入式操作系统3、类型缩写28第5章TinyOS51嵌入式操作系统5.1.4范例分析非局部跳转控制范例——程序清单5.5(P190),说明了setjmp函数和longjmp函数的具体作用。

29第5章TinyOS51嵌入式操作系统5.1.4范例分第5章TinyOS51嵌入式操作系统5.1.5setjmp与longjmp的实现setjmp和longjmp是标准库函数,其具体实现与编译器有很大关联,且与硬件有密切的关系,所以它们往往都是由汇编语言编写的。本书实例中,为了简化这两个函数,约定以下规则:限定SDCC51为小模式;限定SDCC51的integer和long库被编译成可重入的;限定SDCC51所有函数被编译成可重入的;修改setjmp和longjmp的返回值为char;取消longjmp的第二参数,当调用longjmp时,则让setjmp的返回值始终为1;30第5章TinyOS51嵌入式操作系统5.1.5se第5章TinyOS51嵌入式操作系统1、jmp_buf(TinyOS51中定义的变量类型,见表5.5)jmp_buf定义程序清单(setjmp.h)

30#define_SP_SIZE1//堆栈指针长度31#define_BP_SIZE_SP_SIZE//编译器虚拟寄存器,用于重入32#define_RET_SIZE2//返回地址长度33typedefunsignedcharjmp_buf[_RET_SIZE+_SP_SIZE+_BP_SIZE];31第5章TinyOS51嵌入式操作系统1、jmp_buf第5章TinyOS51嵌入式操作系统2、setjmp的实现

setjmp就是将相应的寄存器和返回地址保存到jmp_buf数组类型的jbBuf变量中,即保存的寄存器为变量bp的当前值、堆栈指针的当前值、高8位和低8位返回地址值。对于80C51单片机来说,由于调用函数是使用ACALL或LCALL指令来实现的,因此这些指令会将函数的返回地址保存在堆栈中。setjmp()定义详见如下程序清单。32第5章TinyOS51嵌入式操作系统2、setjmp的实第5章TinyOS51嵌入式操作系统

setjmp()定义(_setjmp.c)程序清单30externunsignedcharbp;//编译器为简化重入操作而定义的变量39charsetjmp(jmp_bufjbBuf)40{dataunsignedchar*pucBuf=(datavoid*)0;//指向上下文信息存储位置的指针

pubBuf=(dataunsignedchar*)jbBuf;//将jbBuf数组的首地址赋给pucBuf*pucBuf++=bp//保存bp的当前值*pucBuf++=SP//保存SP的当前值*pucBuf++=*((dataunsignedcahr*)SP);//保存返回地址高8位*pucBuf=*((dataunsignedcahr*)((char)(SP-1)));//保存返回地址低8位

return()}33第5章TinyOS51嵌入式操作系统第5章TinyOS51嵌入式操作系统见P192,下图是setjmp()的执行过程说明。34第5章TinyOS51嵌入式操作系统见P192,下图是s第5章TinyOS51嵌入式操作系统3、longjmp的实现在setjmp()定义中,其存储顺序依次是bp、SP、返回地址高8位、低8位。,那么,longjmp()的定义就是按照上述顺序恢复即可,最后函数返回1。

longjmp()定义(_longjmp.c)的程序清单见书P193.

35第5章TinyOS51嵌入式操作系统3、longjmp的第5章TinyOS51嵌入式操作系统见P193,下图是longjmp()执行过程说明。36第5章TinyOS51嵌入式操作系统见P193,下图是l第5章TinyOS51嵌入式操作系统5.2最简单的多任务模型5.2.1两任务切换模型两任务是多任务最简单的典型情况,而任务切换是学习多任务操作系统的重点和难点。如果搞清楚了两个任务间的任务切换,那么也就搞清楚了多任务操作系统核心的基本原理。在源代码层次,“任务”也是函数,所以很自然想到,可以使用setjmp()和longjmp()函数实现任务间的切换。假设两个任务已运行起来,则任务间的切换模型见下图,其切换程序流向及状态机见下程序清单。37第5章TinyOS51嵌入式操作系统5.2最简单的第5章TinyOS51嵌入式操作系统两任务切换模型图示:38第5章TinyOS51嵌入式操作系统两任务切换模型图示:第5章TinyOS51嵌入式操作系统5.939第5章TinyOS51嵌入式操作系统5.939第5章TinyOS51嵌入式操作系统5.2.2待解决的问题1、如何让任务互不干扰地运行?

函数在运行期间可能被中断打断,转而执行中断服务程序。中断服务程序不改变80C51的内部寄存器值,所以,中断不会干扰任务的运行。在源代码层次,任务也是一个函数,任务正确运行的条件与函数一致。2、如何让任务运行?两个任务切换,必须要先执行一个setjmp()函数,系统在启动时没有任务存在,即先前也没有执行过一个setjmp(),即无法切换。为解决此矛盾,可在创建任务task1时,系统用另一个函数(假设为setTaskJmp())模拟任务task1调用setjmp()函数,而事实上只要两者执行效果一致,即可。40第5章TinyOS51嵌入式操作系统5.2.2待解决第5章TinyOS51嵌入式操作系统5.2.3setTaskJmp()的实现任务调用setjmp()所做的工作如下:将返回地址压人“任务堆栈”(即使用ACALL或LCALL指令),此时堆栈指针SP的值增加2;保存bp到任务上下文中;保存堆栈指针SP(指向任务堆栈)到任务上下文中;保存“返回地址”到任务上下文中。搞清楚任务调用setjmp()的工作,用setTaskJmp()来模拟实现setjmp(),其程序清单见P197-5.10。41第5章TinyOS51嵌入式操作系统5.2.3set第5章TinyOS51嵌入式操作系统5.2.4任务切换模型范例分析1、模型范例根据上面的分析,可以写出任务切换模型的范例,详见程序清单P197-5.11。2、堆栈分配每个任务都有独立的堆栈,80C51的堆栈为idataunsignedchar类型数组。因此可通过定义对应的全局变量来分配任务堆栈,程序5.11-29就是为两个任务分配了堆栈空间。同时,在系统调用setTaskJmp()函数时,还需要指定对应任务的堆栈。42第5章TinyOS51嵌入式操作系统5.2.4任务切第5章TinyOS51嵌入式操作系统3、切换任务

通过上述分析,可以画出完整的两任务切换图如下,程序清单5.11的切换程序流向及状态详见程序清单5.12

.43第5章TinyOS51嵌入式操作系统3、切换任务43第5章TinyOS51嵌入式操作系统5.1244第5章TinyOS51嵌入式操作系统5.1244第5章TinyOS51嵌入式操作系统5.3协作式多任务操作系统(TinyOS51V1.0)5.3.1整体规划1、内核API现代操作系统不再使用协作式多任务管理机制,但作为学习还是有意义的,下面通过调用SDCC编译器提供的setjmp()和longjmp()函数,来编写一个能够实现多任务切换的协作式操作系统——TinyOS51V1.0,以此介绍协作式多任务操作系统的设计思想。45第5章TinyOS51嵌入式操作系统5.3协作式多第5章TinyOS51嵌入式操作系统操作系统仅有内核是不够的,还需要各种应用程序才能完成相应的功能,所以TinyOS51必须具备创建任务的功能,tnOsTaskCreate()的作用就是创建任务,该函数可以在调用tnOsInit()函数后任何时候调用,但在调用tnOsStart()函数之前至少调用一次,见下表。46第5章TinyOS51嵌入式操作系统操作第5章TinyOS51嵌入式操作系统任务退出运行状态时,则必须释放占有的资源,以便让其他任务使用。因此,TinyOS51必须具备删除自身任务和其他任务的功能,tnOsTaskDel()函数的作用就是删除任务,见下表。47第5章TinyOS51嵌入式操作系统任务第5章TinyOS51嵌入式操作系统当任务运行一段时间后,可以主动放弃控制权,让下一个任务运行,这是通过调度程序来实现的,TinyOS51必须具备任务切换功能,tnOsSched()函数的作用就是实现任务切换,执行下一个任务,该函数必须在任务中调用,而且每个任务都必须周期性的调用它,见下表。48第5章TinyOS51嵌入式操作系统当任第5章TinyOS51嵌入式操作系统系统从驱动到创建任务的过程中,操作系统需要做很多的准备工作,这些都是由初始化引导程序完成的,在嵌入式系统中,这些工作可以由main()函数来完成。在TinyOS51中提供了2个供用户调用的函数,一个是初始化TinyOS51内部变量的函数tnOsInit(),这个函数必须在其他函数之前调用,并只能调用一次,见下表。另一个是启动多任务环境的函数tnOsStart(),并执行第一个任务。在调用此函数之前必须创建至少一个任务,该函数不能重复调用,且该函数不返回,见下表。49第5章TinyOS51嵌入式操作系统系统第5章TinyOS51嵌入式操作系统2、资源配置与示例

TinyOS51对任务最大数没有限制,但由于任务需要占用内部有限的idata资源,同时为了保护可重入函数的变量,还将占用更多的堆栈,所以可支持的任务数目实现上是有限的。根据实现情况,TinyOS51的最大任务数以3~4最为合适,OS资源配置代码如下:

程序清单(tiny_os_51_cfg.h)

37#defineTN_OS_MAX_TASKS2//最大任务数目一个简单的测试用例的程序清单见5.14(P202)。50第5章TinyOS51嵌入式操作系统2、资源配置与示例5第5章TinyOS51嵌入式操作系统5.3.2任务控制块TCB(TaskControlBlock)1、任务的识别

对于RTOS来说,它为每一个任务分配一个称为“任务控制块的结构体变量”来管理任务的,即使用“任务控制块结构体变量的指针”来识别任务。每个指针占用3个字节,开销较大。

任务控制块是多任务操作系统的核心数据,为了避免用户任务“意外”修改任务控制块,则这个指针不应当提供给用户程序。TinyOS51不使用任务控制块结构体指针方法来识别任务,主要是为了节省MCU内的RAM。51第5章TinyOS51嵌入式操作系统5.3.2任务控第5章TinyOS51嵌入式操作系统最好的方法,为每个任务建立一个“任务控制块结构体类型数组”,将任务的完整信息保存到这个数组中,然后通过数组_GtcbTasks[]的下标来识别任务。由此可见,下标就是识别任务的字符型整数,下标又俗称为句柄(Handle),任务句柄的定义如下:程序清单5.15任务句柄的定义(tiny_os_51.h)31typedefcharTN_OS_TASK_HANDLE;52第5章TinyOS51嵌入式操作系统最好第5章TinyOS51嵌入式操作系统2、任务控制块

当一个任务创立并准备运行时,内核将其放入就绪状态。任务一旦运行完毕,则立即删除,从而释放内存资源。因此要设立一个任务状态字“ucTaskStat”来管理任务所处状态,如图。任务状态字的定义如下:

程序清单5.16任务状态字(tiny_os_51_core.c)31#define_TN_TASK_FLG_DEL0X00//任务被删除32#define_TN_TASK_FLG_RDY0X01//任务就绪53第5章TinyOS51嵌入式操作系统2、任务控制块第5章TinyOS51嵌入式操作系统上下文信息:当一个任务主动放弃CPU的控制权,从而允许下一个任务运行时,则此时必须保存该任务的上下文信息,当操作系统决定再次运行该任务时,可通过释放上下文信息就可以让该任务再次运行。在TinyOS51中,上下文信息保存在jmp_buf数组类型的jbTaskContext变量中,而jmp_buf是在<setjmp.h>C语言标准头文件中定义的。一个示例见程序清单5.17(P204)54第5章TinyOS51嵌入式操作系统上下文信息:54第5章TinyOS51嵌入式操作系统5.3.3内部变量初始化我们知道单片机需要初始化,其实,TinyOS51也需要初始化,当初始化时还没有任务存在,因此必须将所有的任务控制块初始化为一个“空白表”。因为TinyOS51只有知道当前运行的是哪个任务,才能在任务切换时决定下一个将要运行的任务。由于用户创建的第一个任务的句柄为0,所以系统开始运行句柄为0的任务,因此,必须将用于追踪当前正在运行的任务的句柄_GthTaskCur变量初始化为0。见程序清单5.18(P204)55第5章TinyOS51嵌入式操作系统5.3.3内部变第5章TinyOS51嵌入式操作系统5.3.4创建任务(TaskCreate)

如果一个程序需要运行,必须要创建一个与之对应的任务,才能在内存中运行。一个任务可以在操作系统启动前(即调用tnOsStart())创建,也可以在其他任务的执行过程中创建,但任务不能由中断程序来创建,创建任务函数原型为:TN_OS_TASK_HANDLEtnOsTaskCreate(void(*pfuncTask)(void),idataunsignedchar*pucStk)举例:unOsTaskCreate(task0,_GuctaskStks[0]);其中,task0为任务函数的入口地址,_GucTaskStks[0]为任务堆栈的位置。56第5章TinyOS51嵌入式操作系统5.3.4创建任第5章TinyOS51嵌入式操作系统针对任务的三种状态模型,创建任务函数源代码见程序清单5.19(P206),其创建任务的过程包括:(1)申请一个空白TCB:搜索一个空闲的TCB项,并分配给新任务,同时系统赋予它唯一的任务句柄thRt。(2)填充TCB:先保存新任务的上下文,将搜索到的TCB设置为就绪状态,其返回值为就绪任务的任务句柄thRt。(3)空闲任务启动多任务环境之前,操作系统至少需创建一个用户任务(低优先级空闲任务)。当多任务环境启动后,则表明多任务环境已经建立,此时可以创建新的任务了.57第5章TinyOS51嵌入式操作系统针第5章TinyOS51嵌入式操作系统5.3.5启动多任务环境在操作系统中运行第一个用户任务的过程被称之为“启动多任务环境”,由于用户创建的第一个任务的句柄是0,所以系统开始运行句柄为0的任务。TinyOS51是通过调用tnOsStart()函数来实现的,由longjmp()函数执行句柄为0的任务,见程序清单5.20。

程序清单5.20启动OS(tiny_os_core.c)107voidtnOsStart(void)108{109longjmp(_GtcbTasks[0],jbTaskContext);//执行0号任务110}58第5章TinyOS51嵌入式操作系统5.3.5启动多第5章TinyOS51嵌入式操作系统5.3.6任务切换(TaskSwitch)任务切换是指保存当前任务的上下文,并恢复需要执行任务的上下文的过程。当任务发生切换时,将当前执行任务的上下文保存到该任务的TCB中,然后从相应的TCB中恢复下一个将要执行的已就绪任务的上下文,若所有任务都处于未就绪状态,则等待本任务直到就绪为止,相当于一般操作系统的空闲任务。这就是任务切换的设计思想。

TinyOS51的任务切换就是通过调用tnOsSched()函数来实现的。任务切换见程序清单5.21(P207)59第5章TinyOS51嵌入式操作系统5.3.6任务切第5章TinyOS51嵌入式操作系统5.3.7删除任务(TaskDelete)

当删除任务时,只需要将任务句柄告诉“删除任务”函数,即可将对应的任务删除。一个任务既可以删除别的任务,也可以删除自身。删除其他任务,只要将任务设置为不可运行状态即可;如果删除自身,则需要将任务设置为不可运行状态,还要将CPU控制权交给另一个可运行的任务,即进行任务切换。

TinyOS51删除任务的是通过调用tnOsTaskDel()函数来实现的,见删除任务程序清单5.22(P208)60第5章TinyOS51嵌入式操作系统5.3.7删除任第5章TinyOS51嵌入式操作系统5.3.8小结

5.3节介绍的协作式多任务操作系统仅仅是为了入门学习之用,实际上,抢占式实时多任务操作系统已经成为商业化实时多任务操作系统的主流。在嵌入式应用系统中,并非选用最好的操作系统,而恰到好处的、性价比高的操作系统才是最佳选择。下节5.4将介绍“TinyOS51V1.1时间片轮询多任务操作系统”。61第5章TinyOS51嵌入式操作系统5.3.8小结6第5章TinyOS51嵌入式操作系统5.4时间片轮询多任务操作系统(TinyOS51V1.1)5.4.1概述不同的操作系统内核使用了不同“调度算法”来决定什么时候运行那个任务(即调度),而事实上协作式多任务操作系统时没有调度算法的,它由任务自己来决定何时调度。一般来说,操作系统的单独算法主要有3类:时间片轮询(Time-slicePolling)优先级(Priority)带优先级的时间片轮询调度算法62第5章TinyOS51嵌入式操作系统5.4时间片轮第5章TinyOS51嵌入式操作系统时间片轮询调度算法:在分时系统中,一般采用“时间片轮询”调度算法,这是一种绝对公平的思想策略。首先将MCU的执行时间划分为若干个时间片,然后让处于就绪状态的任务,按顺序轮流占有MCU。当时间片用完时,即使任务没有执行完毕,则系统也会无情地剥夺该任务使用MCU的权利。63第5章TinyOS51嵌入式操作系统时间片轮询调度算法:第5章TinyOS51嵌入式操作系统优先级调度算法:

为了满足任务的紧迫性和重要性,将任务划分为不同等级区别对待,优先级高的先执行,优先级低的后执行,且优先级高的任务可以暂停正在执行的优先级低的任务,当优先级高的任务执行完毕后,在继续执行暂停的优先级低的任务。对于同优先级的任务,则使用时间片轮询调度算法。如果要求所有任务的优先级必须不同,这就是“完全基于优先级的调度算法”。64第5章TinyOS51嵌入式操作系统优先级调度算法:64第5章TinyOS51嵌入式操作系统带优先级的时间片轮询调度算法:

当今的商业社会,企业为了实现利益的最大化,常常为优先级高的客户提供更多的服务,为优先级低的客户提供相对较少的服务。。

带优先级的时间片轮询调度算法就像企业对待客户一样,将任务划分为优先级(等级),对优先级高的任务可以分配更大的时间片,对优先级低的任务则分配较少的时间片,同时也让所有任务都得到执行。

此算法的操作系统中,有2种情况下进行任务切换:任务主动请求调度分配给任务的时间片已到65第5章TinyOS51嵌入式操作系统带优先级的时间片轮询第5章TinyOS51嵌入式操作系统任务时间片的切换:对于不是任务主动放弃CPU控制权而进行的任务调度,就是抢占式任务调度。事实上,所有的操作系统都是使用一个周期性的中断来管理时间片的,在这个中断服务程序中判断任务是否用完自己的时间片。除了协作式多任务操作系统外,其他的多任务操作系统都只在2个时刻进行任务切换,即任务主动调用OS提供的函数时,或中断服务程序结束时。66第5章TinyOS51嵌入式操作系统任务时间片的切换:6第5章TinyOS51嵌入式操作系统5.4.2整体规则1、内核API

在协作式多任务操作系统中,如果其中一个任务死掉,则可能造成整个系统崩溃。为了克服TinyOS51V1.0这个缺点,在TinyOS51V1.1上添加了最简单的时间片轮询多任务调度算法,“在每个时钟节拍中断时调度”,即每次分配给任务的时钟节拍数都是一个时钟节拍。TinyOS51V1.1为时间片轮询多任务操作系统,因此用户不在使用任务切换函数,它仅提供给内核使用,并更换为_tnOsSched()。下表为新增的延时函数和用户中断函数。程序范例见5.23(P211)67第5章TinyOS51嵌入式操作系统5.4.2整体规第5章TinyOS51嵌入式操作系统68第5章TinyOS51嵌入式操作系统68第5章TinyOS51嵌入式操作系统5.4.3任务控制块由于TinyOS51V1.1新增了任务延时服务功能,因此,必须在TCB中增加一个记录任务延时时间的成员uiTicks,新的TCB关联图见下5.13,如果uiTicks为0,说明任务已经完成延时,则任务不需要等待。同时,在任务状态字中也需要增加一个用于指示当前任务处于延时状态的标志_TN_TASK_FLG_DLY,

详见程序清单5.24(P212)69第5章TinyOS51嵌入式操作系统5.4.3任务控第5章TinyOS51嵌入式操作系统5.4.4内部变量初始化由于TCB增加了一个uiTicks,因此必须初始化,详见程序清单5.25(P212)。5.4.5创建任务

对于时间片轮询多任务操作系统来说,在时钟节拍中断服务的最后,可能会发生任务切换。而时钟节拍中断可能发生在如何时候,而此时系统切换到另一个任务也想创建一个新任务,此时两个任务的句柄是一样的,且占用一个任务控制块,势必引起系统混乱,因此在创建任务的过程中必须禁止任务切换,那么最简单的方法就是“先禁止中断,然后再允许中断”。创建任务程序清单5.26(P231)。70第5章TinyOS51嵌入式操作系统5.4.4内部变第5章TinyOS51嵌入式操作系统5.4.6启动多任务环境在TinyOS51V1.1中,如果不允许中断,则时钟节拍中断服务程序不会运行,因此在启动操作系统时,必须增加允许中断的代码,见程序清单5.27(P214)。5.4.7任务调度与V1.0版本比较,TinyOS51V1.1版本将tnOsSched()函数更名为_tnOsSched(),增加了“禁止中断和允许制度”代码,并仅供内核调用,详见程序清单5.28(P214)。71第5章TinyOS51嵌入式操作系统5.4.6启动多第5章TinyOS51嵌入式操作系统5.4.8时钟节拍中断

大多数操作系统的“延时管理和在中断服务程序中的任务切换”功能,分别是用两个函数实现的。由于TinyOS51V1.1是纯粹的时间片轮询多任务操作系统,除了在“timer0ISR()时钟节拍中断服务程序”中切换任务外,在其他的中断服务程序中不作任务切换操作,所以将“延时管理(程序清单5.29(241~248))”与“在中断服务程序中的任务切换(程序清单5.29(241~248))”功能,写在tnOsTimeTick()时钟节拍处理函数中,见程序清单5.29(P215)72第5章TinyOS51嵌入式操作系统5.4.8时钟节第5章TinyOS51嵌入式操作系统5.4.9longjmplnlsr()

该函数原型为:longjmpInIsr(jmp_bufjbBuf)_nakedlongjmpInIsr()使用了关键字_naked,这是与longjmp的不同之处,在TinyOS51中则说明此函数是无保护函数,即禁止编译器为函数生成开始和结尾代码。实际上它意味着函数的这部分代码必须使用内嵌汇编来写,在这里主要是为“RETI”指令准备的。由于longjmpInIsr()函数是无保护函数,因此其返回值必须由用户自己来处理,longjmpInIsr()定义详见程序清单5.30(P217)。73第5章TinyOS51嵌入式操作系统5.4.9lon第5章TinyOS51嵌入式操作系统5.4.10任务延时在无操作系统的应用系统中,常使用软件的空循环来实现延时,由于CPU完全处于空转状态,因此大大降低了CPU的效率。为了提高CPU的使用效率,大部分操作系统都提供了延时服务。即当任务处于延时期间,而其他的任务仍可继续进行,TinyOS51V1.1也提供了任务延时服务。详见任务清单5.32(P218)最好的方法是设置一个“周期性的中断”,然后用这个“中断服务程序”来记录当前任务的剩余延时时间。

TinyOS51V1.1的时钟节拍中断timer0JSR()调用tnOsTimeTick()函数来记录当前任务的剩余时间。74第5章TinyOS51嵌入式操作系统5.4.10任务第5章TinyOS51嵌入式操作系统5.4.11删除任务tnOsTaskDel()删除任务函数详见程序清单5.33,与V1.0版本比较,TinyOS51V1.1版本在tnOsTaskDel()函数中增加了2部分:由于TCB增加了一个uiTasks,所以必须初始化禁止中断和允许中断75第5章TinyOS51嵌入式操作系统5.4.11删除第5章TinyOS51嵌入式操作系统5.5信号量(TinyOS51V1.2)5.5.1概述1、信号量(Semaphore)

在任务共享同一个地址空间的系统中,任务可以通过全局变量传递数据信息。而在一些多任务操作系统中,由于不同的任务可能占用不同的地址空间,所以一个任务不能直接访问另一个任务定义的变量,因此也就不能使用全局变量了。

通常是采用铁路信号灯控制机制的方法,即在多个相互合作的任务之间使用简单的信号来同步,也就是通过简单的信号量让多个任务进行某种形式的合作。

76第5章TinyOS51嵌入式操作系统5.5信号量第5章TinyOS51嵌入式操作系统2、计数型信号量

在嵌入式多任务系统中,为了使系统达到高效处理和快速响应的目的,大量采用“事件驱动”的方式来编写任务,而事件可能是外部的,也可能是内部的比如:一个任务给另一个任务发送信号量或消息,于是将用于任务之间同步和通信的“信号量、信息邮箱”等称之为“事件”。

信号量如同通行证,任务要运行就必须先拿到通行证,如果信号量已被其他的任务所占用,那么,该任务只能被挂起,直到信号量被当前使用者释放为止。77第5章TinyOS51嵌入式操作系统2、计数型信号量7第5章TinyOS51嵌入式操作系统5.5.2整体规划

1内核API针对8051单片机,在引入信号量后,规划TinyOS51时必须节省RAM,具体如下:由用户代码来定义“信号量类型变量”,其定义在idata中,这样无需删除信号量函数。将任务本身等待的事件保存到TCB中,用指向等待事件的指针pvEvent来记录。为了便于返回以负数表示的错误状态,信号量计数值可保存在一个有符号数char类型字节变量中,其计数范围为0~127。由于信号量属于一种事件,因此TinyOS51规划了事件的返回值,详见程序清单5.34(P220)78第5章TinyOS51嵌入式操作系统5.5.2整体规第5章TinyOS51嵌入式操作系统信号量的标准操作包括创建信号量(初始化),获取信号量和发送信号量,分别见下表。2资源配置与示例

使用信号量必须注意:先创建,后使用,使用范例奖程序清单5.35(P221)79第5章TinyOS51嵌入式操作系统信号第5章TinyOS51嵌入式操作系统80第5章TinyOS51嵌入式操作系统80第5章TinyOS51嵌入式操作系统5.5.3任务控制块任务在同一时刻只能等待一个事件,因此可以用指向等待事件的指针pvEvent指示任务正在等待那个具体的事件,并通过扫描所有TCB的pvEvent成员,即可获得等待信号量的任务列表。任务控制块成员结构示意图见5.15,相关程序清单5.36(P222)81第5章TinyOS51嵌入式操作系统5.5.3任务控第5章TinyOS51嵌入式操作系统5.5.4内部变量初始化由于TCB增加了一个pvEvent,必须初始化,详见程序清单5.37(P223)

5.5.5信号量的定义

信号量不在包含等待任务列表,只包含信号量的值,详见信号量定义程序清单5.38(P224)5.5.6创建信号量

在使用一个信号量之前,必须先调用“创建信号量”函数来创建这个信号量,而信号量的建立实际上就是对信号量进行初始化。见程序清单5.39(P225)82第5章TinyOS51嵌入式操作系统5.5.4内部变第5章TinyOS51嵌入式操作系统5.5.7获得信号量获得信号量又称等待信号量、请求信号量或接收信号量,是信号量的一种基本操作。

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论