UCOS-II的基本概念

UCOS—II

一、实时操作系统的概念

1.1 操作系统

? 操作系统是一种系统软件,他在计算机硬件与计算机应用程序之间,通过提供程序接口,屏蔽了计算机硬件工作的一些细节,从提高了应用程序的开发效率。

? 应用在嵌入式系统中的操作系统称为嵌入式操作系统

1.2 前后台系统

? 不复杂的小系统一般设计成前后台系统(也称超循环系统)。应用程序是一个无限的循环,循环中调用相应的函数完成相应的操作,这部分可以看成后台系统。中断服务程序处理异步事件,这部分可以看成前台系统。后台也可以叫任务级,前台也可以叫中断级。时间相关很强的关键操作一定是靠中断服务来保证的,因为中断服务提供的信息一定要等到后台程序走到该处理信息这一步时才能得到处理,因此这种系统在处理信息的及时性上,比实际可以做到的要差。这个指标称作任务的相应时间,最坏情况下的任务级相应时间取决于整个循环的执行时间。因为循环的执行时间不是常数,程序经过某一特定的部分的准确时间也是不能确定的。

? 很多基于微处理器的产品处采用前后台系统设计,如微波炉、玩具、电话机等。

? UCOS-II是按照系统中只有一个CPU来设计的,在这种系统中,一个时刻只会有一个任务占用CPU处在运行状态,而其他任务只能处在其他状态。

任务的状态 说明
休眠态 任务只是以代码的形式驻留在程序空间(ROM或RAM),还没有交给操作系统管理,当并不被多任务内核所调度
就绪态 意味着任务具备了运行的充分条件,可以运行了,但是由于任务的优先级比正在运行的任务的优先级低,因此暂时还不能运行
运行态 指任务掌握了CPU的控制权,正在运行中,任何时刻只能有一个任务处于运行状态。
挂起态 也叫做等待事件态,指任务在等待某一时间的发生(例如等待某外设的I/O操作,等待某共享资源由暂不能使用变成能使用状态,等待定时脉冲的到来或等待超时信 的到来以结束目前的等待,等待)。
中断态 一个正在运行的任务一旦响应中断申请就会在中断运行而去执行中断服务程序,这时候任务的状态叫做中断服务态。

? 在系统任务的管理下,一个任务可以在5个不同对的状态自己发生转换。其转换关系如下图所示。

OSTaskCreate()是UCOS-II提供的用来创建任务的函数;

OSStart()启动UCOS-III的函数。系统被启动后,任务就由操作系统来管理和调度了。

系统任务

UCOS-II预定义了两个系统任务:空闲任务和统计任务。其中,空闲任务是每个应用程序必须使用的,而统计任务是应用程序可以根据实际需要来选择使用的。

空闲任务

在系统运行的过程中,极有可能会在某个时间内无用户任务可运行而处于所谓的空闲状态。为了使CPU在没有用户任务可执行时有事可做,UCOS-II提供了一个叫做空闲任务OSTaskIdle()的系统任务。其代码如下

空闲任务几乎不做什么东西,只是对系统定义的一个空闲任务次数运行次数计数器OSdleCtr进行加1操作。UCOS-II规定,一个用户应用程序必须使用这个空闲任务,而且这个任务不能通过程序来删除。

? 至于代码中的“Pdata = pdata;”是为了防止编译器 错而使用的一个程序设计技巧,因为空闲任务没有用参数pdata,而某些C编译器会对这种情况 错(说定义了参数却没有使用),有了这行代码,编译器就不会 错了。

统计任务

? UCOS-II提供的另一个系统任务就是统计任务()。该任务每秒计算一次CPU在单位时间内被使用的时间,并把计算结果以百分比的形式存放在变量OSCOUsage中,以便其他应用程序来了解CPU的利用率。

? 系统是否使用统计任务,用户可以根据应用程序的实际需求来进行选择。如果用户应用程序决定要使用统计任务,则必须把定义在系统头文件OS_CFG.H中的系统配置常数OS_TASH_STAT_EN设置为1,并且在程序中要调用函数OSStatInit()对统计任务进行初始化。

任务的优先权级优先级别

? UCOS-II中创建追到64个任务(0-63)。数字越小,优先级别越高。

? UCOS-II在系统配置文件OS_CFG.H中定义了一个用来表示最低优先级别的参数OS_LOWEST_PRIO,如果用户为其赋了值,那么就以为着系统可用的优先级有OS_LOWEST_PRIO+1个(0到OS_LOWEST_PRIO)。

? 另外,系统会把最低优先级别OS_LOWEST_PRIO自动赋值给统计任务,如果应用程序使用了统计任务,则系统还会把优先级别OS_LOWEST_PRIO-1自动赋值给统计任务。

任务堆栈

任务堆栈是任务的重要的组成部分

堆栈就是在存储器中按“后进先出(LIFO)”的原则组织的连续存储空间。为了满足任务切换和响应中断时保存CPU寄存器中的内容及任务调用其他函数时的需要,每个任务都应该配有自己的堆栈。所有UCOS-II任务的任务控制块中都含有一个指向该任务堆栈的指针。

四、中断的相关概念

? 任务在运行过程中,应内部或外部异步事件的请求中止当前任务,而去处理异步事件所要求的过程叫做中断。应中断请求而运行的程序叫做中断服务子程序(ISR),中断服务子程序的入口地址叫做中断向量。

4.1.1 UCOS-II的中断过程

? UCOS-II系统响应中断的过程是:系统接收到中断请求后,如果这时CPU出于中断允许状态,系统就会中止正在运行的当前任务,而按照中断向量的指向转而去运行中断服务子程序;当终端服务子程序的运行结束后,系统将会根据返回情况返回到被中止的任务继续运行,或者转向运行另一个具有更高优先级别的就绪任务。

? 对于可剥夺型UCOS-II内核,中断服务子程序运行结束之后,系统将会根据情况进行一次任务调度去运行优先级别最高的就绪任务,而并不一定要接着运行被中断的任务。

? UCOS-II系统允许中断嵌套,即高优先级别的中断源的中断请求可以中断低优先级别的中断服务程序的运行。为了记录中断嵌套的层数,UCOS-II定义了一个全局变量OSIntNesting。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HJOIlmwK-1631626214981)(https://i.loli.net/2021/08/04/bHtewxyfhqs6EWN.png)]

? 编写UCOS-II的中断服务程序时,要用到两个重要的函数:OSIntEnter()OSIntExit()

函数OSIntEnter()的作用就是把全局变量OS_IntNesting加1,从而用它来记录中断嵌套的层数。

函数OSIntEnter()的调用通常发生在中断服务程序保护了被中断任务的断点数据之后运行用户中断服务代码之前,所以称之为进入中断服务函数。

另一个在中断服务程序中要调用的函数叫做退出中断服务函数OSIntExit()。调用该函数中断嵌套层数计数器减1.

函数OSIntExit()的流程图为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ogsioMAL-1631626214983)(https://i.loli.net/2021/08/04/hks7AJVtR2jquZE.png)]

? 从图中可以看出,函数在中断嵌套层数计数器为0、调度器未被锁定且从任务就绪表中查找到的最高级的就绪任务不是被中断的任务的条件下将要进行任务切换,否则就返回被中断的服务子程序。

? 中断服务子程序流程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4sX0iFCa-1631626214984)(https://i.loli.net/2021/08/04/iqBUjX9Vr4ZDGKI.png)]

UCOS-II中,通常用一个任务来表示异步事件的处理,而在中断服务程序中通过向任务发消息的方法去激活这个任务

OSIntCtxSw():中断级任务切换函数

4.1.3应用程序中的临界段

在UCOS-II中,不希望被中断的代码段叫做临界段。从代码上来看,处在关中断和开中断之间的代码段就是临界段。

在UCOS-II中,不要在临界段中调用UCOS-II提供的功能函数,以免系统崩溃。

OS_ENTER_CRITICAL():封装了相关关中断指令的宏

OS_EXIT_CRITICAL():封装了相关开中断指令的宏

4.2 时钟

? 任何操作系统都要提供一个周期性的信 源,以供系统处理诸如延时、超时等与时间有关的事件,这个周期性的信 源叫做时钟。

? UCOS-II用硬件定时器产生一个周期为毫秒(ms)级的周期性中断来实现系统时钟。最小的时钟单位就是两次中断之间相隔的时间,这个最小时钟单位叫做时钟拍(Time Tick)。

? 硬件定时器以时钟节拍为周期定时地产生中断,该中断的中断服务程序叫做OSTickISR(),中断服务程序通过调用函数OSTimeTick()来完成系统系统在每个时钟节拍时需要做的工作。

? UCOS-II每次响应定时中断时调用OSTimeTick()做了两件事情:一是给计数器OSTime加1;二是遍历任务控制块链表中的所有任务控制块,把各个任务控制块中用来存放任务延时时限的OSTCBDly变量减1,并使该项为0,同时又不使被挂起的任务进入就绪状态。

? 简单地说,函数OSTimeTick()的任务就是在每个时钟节拍了解任务的延时状态,了解每个任务的延时状态,使其中一家到了延时时间的非挂起任务进入就绪状态。

4.3 时间管理

4.3.1任务的延时

? 因为嵌入式系统的任务是一个无限循环,并且UCOS-II是一个抢占式内核。UCOS-II规定,出空闲任务之外的所有任务必须在合适的位置调用系统提供的函数OSTimeDly(),使当前任务的运行延时(暂停)一段时间并进行一次任务调度,让出CPU的使用权。

OSTimeDly(INT16U ticks)中的函数参数ticks是以时钟节拍数为单位的延时时间

OSTimeDlyHMSM()shi 是UCOS-II提供的另一个可以用时、分、秒、毫秒为参数的任务的延时函数。该函数与函数OSTimeDly()一样也要引发一次调度。

? 调用了函数OSTime()或OSTimeDlyHMSM()的任务,当规定的延时时间期满,或有其他任务调用函数OSTimeDlyResume()取消了延时,他立即会进入就绪状态。

4.3.2 取消任务的延时

延时的任务可通过在其他任务中调用函数OSTimeDlyResume()取消延时而进入就绪状态。如果任务比正在运行的任务优先级别高,则立即引发一次任务调度。

OSTimeDlyResume(INT8U prio)中的prio为被取消延时任务的优先级别。、

4.3.2 获取和设置系统时间

? 系统定义了一个INT32U类型的全局变量OSTime来记录系统发生的时钟节拍数。OSTime在应用程序调用OSStart()时被初始化为0,以后每发生一个时钟节拍OSTime的值就被加1。

? 在应用程序中调用函数OSTimeGet()可获取OSTime的值。

? 在应用程序中调用函数OSTimeSet(),可设置OSTime的值。函数 OSTimeSet( INT32U ticks)中的参数ticks为OSTime的设定值(节拍数)。

+++

+++

+++

OS_TICKS_PER_SEC :一秒有多少个系统TICK(时钟节拍)

如(#define OS_TICKS_PER_SEC 100)则一秒有100个TICK

reload:系统频率的8分频 (MHz)

1MHz=1000 000Hz

Hz:每秒钟变化几次 例如2Hz则是每秒变化2次

(reload*1000 000)/OS_TICKS_PER_SEC:每个时间节拍需要变化多少次

OSTaskCreate();

第一个参数一个指针,也就是用户代码的首地址

第二个参数是指向数据初始化的指针

第三个参数是指向任务堆栈栈顶的指针

第四个参数是任务的优先级

void OSSemPend ( OS_EVNNT *pevent, INT16U timeout, int8u *err );

pevent 是指向信 量的指针。该指针的值在建立该信 量时可以得到。

err 是指向包含错误码的变量的指针,返回的错误码可能为下述几种:

? * OS_NO_ERR :信 量不为零。
? * OS_TIMEOUT :信 量没有在指定数目的时钟周期内被设置。
? * OS_ERR_PEND_ISR :从中断调用该函数。虽然规定了不允许从中断调用该函数,但μC/OS-Ⅱ仍然包含了检测这种情况的功能。
? * OS_ERR_EVENT_TYPE :pevent 不是指向信 量的指针。

任务控制块:用来记录任务的堆栈、任务的当前状态、任务的优先级、等一些与任务管理有关属性的表叫做任务控制快

五、进程通信

5.1 任务的同步和事件

5.1.1 任务间的同步

为了防止任务之间起冲突,各个任务之间必须建立一些制约关系

制约关系有:直接制约关系、间接制约关系

直接制约关系源于任务之间的合作

间接制约关系源于对资源的共享

任务之间的制约性的合作运行机制叫做任务间的同步

5.1.2 事件

? UCOS-II使用信 量、邮箱(消息邮箱)和消息队列这些中间环节来实现任务之间的通信,这些中间环节被统一称作“事件”。

5.1.2.1 信 量

每当有任务申请信 量时,如果信 量计数器OSEventCnt的值大于0,则把OSEventCnt减1并使任务继续进行;如果OSEventCnt的值为0,则会将任务列入任务等待列表,使任务处于等待状态。如果有正在使用信 量的任务释放了该信 量,则会在任务等待表中找出优先级别最高的等待任务,并在使它就绪后调用调度器引发一次调度;如果任务等待表中已经没有等待任务,则信 量计数器就只是简单的加1。

信 量的操作

创建:OSSemCreate(cnt):cnt为信 量计数器初值

请求:OSSempend(pevent,timeout,err):pevent为信 量的指针,timeout为等待时限,err为错误信息

发送:OSSemPost(pevent)

5.1.2.2 互斥型信 量

? 互斥型信 量是一个二值信 ,他可以使任务以独占方式使用共享资源。

? 两个任务在使用互斥信 量进行通信,可使这两个信 量无冲突的访问一个共享资源,当任务1发现信 量标志位为1时,它一方面把信 量的标志值由“1”改为“0”,另一方面进行共享资源的访问。如果任务2在任务一已经获得信 之后来请求信 量,由于任务2获得的标志值为0,所以任务2只能等待二不能访问共享资源。直到任务1使用完共享资源后,由任务1向信 量发信 使信 量标志的值由“0”再变为“1”时,任务2才能访问共享资源。

? 在使用互斥信 量时,在访问完共享资源后,一定要把信 量标志的值由“1”变为“0”。

任务优先级的反转现象:在可剥夺型内核中,当任务以独占方式使用共享资源时,会出现低优先级任务先于高优先级任务而被运行的现象,这就是所谓的任务优先级反转。

一般来说,在实时操作系统中不允许出现这种现象,因为它破坏了任务执行的预期顺序,可能会导致严重的后果,因此应该杜绝任务优先级反转现象的发生。

任务优先级的反转的原因:之所以出现任务优先级反转现象,是因为一个优先级别较低的任务在获得了信 量使用共享资源期间,被具有较高优先级别的任务所打断而不能示范信 量,从而使正在等待这一信 量的更高级别的任务因得不到信 量而被迫处于等待状态,在这个等待期间,就让优先级别低于它而高于占据 信 量的任务先运行了

**任务优先级的反转的解决办法之一:**是获得信 量任务的优先级别在使用共享资源期间展示提升到所有任务最高优先级别的一个级别上,从而使该任务不被其他任务所打断,从而尽快的使用完共享资源并释放信 量,然后再释放信 量之后,再恢复该任务原来的优先级别。

互斥信 量的操作

OS_EVENT *UartSend; //定义一个互斥型信 量int main(void){	......	UartSend = OSMutexCreate(0, &err);//创建互斥信 量}//任务1void taks1(void *pdata){	while(1)	{		......		OSMutexPend(UartSend, 0, &err);       //请求互斥信 量		......		OSMutexPost(UartSend);             //释放互斥信 量	}}//任务2void taks2(void *pdata){	while(1)	{		......		OSMutexPend(UartSend, 

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2021年8月12日
下一篇 2021年8月12日

相关推荐