UCOSII概念及内核.docx

上传人:b****3 文档编号:4746450 上传时间:2022-12-08 格式:DOCX 页数:12 大小:22.17KB
下载 相关 举报
UCOSII概念及内核.docx_第1页
第1页 / 共12页
UCOSII概念及内核.docx_第2页
第2页 / 共12页
UCOSII概念及内核.docx_第3页
第3页 / 共12页
UCOSII概念及内核.docx_第4页
第4页 / 共12页
UCOSII概念及内核.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

UCOSII概念及内核.docx

《UCOSII概念及内核.docx》由会员分享,可在线阅读,更多相关《UCOSII概念及内核.docx(12页珍藏版)》请在冰豆网上搜索。

UCOSII概念及内核.docx

UCOSII概念及内核

UCOS-II概念及内核

实时系统概念

1.有两种类型的实时系统:

软实时系统和硬实时系统。

在软实时系统中系统

的宗旨是使各个任务运行得越快越好,并不要求限定某一任务必须在多长

时间内完成。

在硬实时系统中,各任务不仅要执行无误而且要做到准时。

2.前后台系统:

应用程序是一个无限的循环,循环中调用相应的函数完成相

应的操作,这部分可以看成后台行为(background)。

中断服务程序处理异

步事件,这部分可以看成前台行为(foreground)。

后台也可以叫做任务

级。

前台也叫中断级。

3.可重入型函数:

可重入型函数可以被一个以上的任务调用,而不必担心数

据的破坏。

可重入型函数任何时候都可以被中断,一段时间以后又可以运

行,而相应数据不会丢失。

可重入型函数或者只使用局部变量,即变量保

存在CPU寄存器中或堆栈中。

如果使用全局变量,则要对全局变量予以保

护。

以下技术之一即可使不可重入函数具有可重入性:

把变量定义为局部变量

调用函数之前关中断,调动后再开中断

用信号量禁止该函数在使用过程中被再次调用

4.优先级反转:

应用程序执行过程中,任务的优先级是可变的,则称之为动

态优先级。

实时内核应当避免出现优先级反转问题。

为防止发生优先级反

转,内核能自动变换任务的优先级,这叫做优先级继承(Priority

inheritance)

5.互斥条件:

实现任务间通讯最简便到办法是使用共享数据结构。

特别是当所

有到任务都在一个单一地址空间下,能使用全程变量、指针、缓冲区、链

表、循环缓冲区等,使用共享数据结构通讯就更为容易。

虽然共享数据区

法简化了任务间的信息交换,但是必须保证每个任务在处理共享数据时的

排它性,以避免竞争和数据的破坏。

与共享资源打交道时,使之满足互斥

条件最一般的方法有:

关中断(μC/OS-?

在处理内部变量和数据结构时就是使用的这种手

段)

使用测试并置位指令

禁止做任务切换

利用信号量

6.信号量:

信号量用于:

控制共享资源的使用权(满足互斥条件)

标志某事件的发生

使两个任务的行为同步

对信号量只能实施三种操作:

初始化(INITIALIZE),也可称作建立(CREATE);

等信号(WAIT)也可称作挂起(PEND);

给信号(SIGNAL)或发信号(POST)。

这是我自己写的验证信号量的部分代码:

voidtask_one(void*pdata);

voidtask_two(void*pdata);

OS_EVENT*tasktwo;

#include"includes.h"

GUI_Init();

VCInit();//初始化一些变量

OSInit();

timeSetEvent(OS_TICKS_PER_SEC,0,OSTickISR,0,TIME_PERIODIC);//

产生节拍

tasktwo=OSSemCreate(0);

OSTaskCreate(task_two,0,&TaskStk[7][TASK_STK_SIZE-1],1);OSTaskCreate(task_one,0,&TaskStk[8][TASK_STK_SIZE-1],2);

OSStart();

7.使用实时内核的优缺点:

实时内核也称为实时操作系统或RTOS。

它的使用

使得实时应用程序的设计和扩展变得容易,不需要大的改动就可以增加新

的功能。

通过将应用程序分割成若干独立的任务,RTOS使得应用程序的设

计过程大为减化。

使用可剥夺性内核时,所有时间要求苛刻的事件都得到

了尽可能快捷、有效的处理。

通过有效的服务,如信号量、邮箱、队列、

延时、超时等,RTOS使得资源得到更好的利用。

如果应用项目对额外的需

求可以承受,应该考虑使用实时内核。

这些额外的需求是:

内核的价格,

额外的ROM/RAM开销,2到4百分点的CPU额外负荷。

内核结构

1.任务:

一个任务通常是一个无限的循环。

看起来像其它C的函数一样,有

函数返回类型,有形式参数变量,但是任务是绝不会返回的。

故返回参数

必须定义成void。

当任务完成以后任务代码并非真的删除了,μC/OS-?

是简单地不再理会这个任务了。

列出一任务:

voidYourTask(void*pdata)

(1)

{

for(;;){

(2)

/*用户代码*/

调用uC/OS-II的某种系统服务:

OSMboxPend();

OSQPend();

OSSemPend();

OSTaskDel(OS_PRIO_SELF);

OSTaskSuspend(OS_PRIO_SELF);

OSTimeDly();

OSTimeDlyHMSM();

/*用户代码*/

}

}

形式参数变量

(1)是由用户代码在第一次执行的时候带入的。

该变量的类型是一个指向void的指针。

这是为了允许用户应用程序传递任何类型的数据给任务。

μC/OS-?

可以管理多达64个任务,但目前版本的μC/OS-?

有两个任务已经被系统占用了。

作者保留了优先级为0、1、2、3、OS_LOWEST_PRIO-3、OS_LOWEST_PRI0-2,OS_LOWEST_PRI0-1以及OS_LOWEST_PRI0这8个任务以被将来使用。

为了使μC/OS-?

能管理用户任务,用户必须在建立一个任务的时候,将任务的起始地址与其它参数一起传给下面两个函数中的一个:

OSTastCreat或OSTaskCreatExt()。

2.任务控制块:

一旦任务建立了,任务控制块OS_TCBs将被赋值。

任务控制

块是一个数据结构,当任务的CPU使用权被剥夺时,μC/OS-?

用它来保存

该任务的状态。

当任务重新得到CPU使用权时,任务控制块能确保任务从

当时被中断的那一点丝毫不差地继续执行。

OS_TCBs全部驻留在RAM中。

µC/OS-II任务控制块清单:

typedefstructos_tcb{

OS_STK*OSTCBStkPtr;//指向当前任务栈顶的指针。

每个任务的栈的

容量可以是//任意的。

#ifOS_TASK_CREATE_EXT_EN

void*OSTCBExtPtr;//指向用户定义的任务控制块扩展

OS_STK*OSTCBStkBottom;//是指向任务栈底的指针

INT32UOSTCBStkSize;//存有栈中可容纳的指针元数目

INT16UOSTCBOpt;//把“选择项”传给OSTaskCreateExt()

INT16UOSTCBId;//存储任务的识别码,留给将来扩展用

#endif

//用于任务控制块OS_TCBs的双重链接,该链表在时钟节

structos_tcb*OSTCBNext;//拍函数OSTimeTick()中使用,用于刷新各个任务的任

structos_tcb*OSTCBPrev;//务延迟变量.

#if(OS_Q_EN&&(OS_MAX_QS>=2))||OS_MBOX_EN||OS_SEM_EN

OS_EVENT*OSTCBEventPtr;//指向事件控制块的指针#endif

#if(OS_Q_EN&&(OS_MAX_QS>=2))||OS_MBOX_EN

void*OSTCBMsg;//是指向传给任务的消息的指针#endif

INT16UOSTCBDly;

INT8UOSTCBStat;

INT8UOSTCBPrio;

INT8UOSTCBX;

INT8UOSTCBY;

INT8UOSTCBBitX;

INT8UOSTCBBitY;

#ifOS_TASK_DEL_EN

BOOLEANOSTCBDelReq;

#endif

}OS_TCB;

目前,一个用于空闲任务,另一个用于任务统计(如果OS_TASK_STAT_EN是设为1的)。

在μC/OS-?

初始化的时候,所有任务控制块OS_TCBs被链接成单向空任务链表。

当任务一旦建立,空任务控制块指针OSTCBFreeList指向的任务控制块便赋给了该任务,然后OSTCBFreeList的值调整为指向下链表中下一个空的任务控制块。

一旦任务被删除,任务控制块就还给空任务链表。

3.就绪表(ReadyList):

每个任务被赋予不同的优先级等级,从0级到最

低优先级OS_LOWEST_PR1O。

每个任务的就绪态标志都放入就绪表中的,就

绪表中有两个变量OSRedyGrp和OSRdyTbl[]。

在OSRdyGrp中,任务按优先

级分组,8个任务为一组。

OSRdyGrp中的每一位表示8组任务中每一组中

是否有进入就绪态的任务。

任务进入就绪态时,就绪表OSRdyTbl[]中的相

应元素的相应位也置位。

以下程序清单中的代码用于将任务放入就绪表。

Prio是任务的优先级OSRdyGrp|=OSMapTbl[prio>>3];

OSRdyTbl[prio>>3]|=OSMapTbl[prio&0x07];

如果一个任务被删除了,则用程序清单中的代码做求反处理

if((OSRdyTbl[prio>>3]&=~OSMapTbl[prio&0x07])==0)

OSRdyGrp&=~OSMapTbl[prio>>3];

找出进入就绪态的优先级最高的任务

y=OSUnMapTbl[OSRdyGrp];

x=OSUnMapTbl[OSRdyTbl[y]];

prio=(y<<3)+x;

4.任务调度(TaskScheduling):

μC/OS-?

总是运行进入就绪态任务中优

先级最高的那一个。

确定哪个任务优先级最高,下面该哪个任务运行了的

工作是由调度器(Scheduler)完成的。

任务级的调度是由函数OSSched()

完成的。

中断级的调度是由另一个函数OSIntExt()完成的,OSSched()的所

有代码都属临界段代码。

5.系统初始化OSIint():

OSInit()建立空闲任务idletask,这个任务总是

处于就绪态的。

OSInit()还得建立统计任务OSTaskStat()并且让其进入就

绪态。

以上两个任务的任务控制块(OS_TCBs)是用双向链表链接在一起的。

μC/OS-?

还初始化了4个空数据结构缓冲区。

6.任务启动OSStart():

多任务的启动是用户通过调用OSStart()实现的。

然而,启动μC/OS-?

之前,用户至少要建立一个应用任务。

当调用OSStart()

时,OSStart()从任务就绪表中找出那个用户建立的优先级最高任务的任务

控制块,然后,OSStart()调用高优先级就绪任务启动函数

任务管理

1.建立任务:

建立任务:

OSTaskCreate()或OSTaskCreateExt()。

OSTaskCreate()与µC/OS是向下兼容的,OSTaskCreateExt()是

OSTaskCreate()的扩展版本,提供了一些附加的功能。

任务可以在多任务

调度开始前建立,也可以在其它任务的执行过程中被建立。

在开始多任务

调度(即调用OSStart())前,用户必须建立至少一个任务。

任务不能由中断

服务程序(ISR)来建立。

OSTaskCreate()需要四个参数:

task是任务代码的指针,pdata是当任务开始执行时传递给任务的参数的指针,ptos是分配给任务的堆栈的栈顶指针,prio是分配给任务的优先级。

OSTaskCreate()清单

INT8UOSTaskCreate(void(*task)(void*pd),void*pdata,OS_STK*ptos,

INT8Uprio)

{

void*psp;

INT8Uerr;

if(prio>OS_LOWEST_PRIO){//检测分配给任务的优先级是否有效

return(OS_PRIO_INVALID);

}

OS_ENTER_CRITICAL();//关中断

if(OSTCBPrioTbl[prio]==(OS_TCB*)0){//确保在规定的优先级上还没有建立任务

OSTCBPrioTbl[prio]=(OS_TCB*)1;//放置一个非空指针保留该优先级

OS_EXIT_CRITICAL();//开中断

psp=(void*)OSTaskStkInit(task,pdata,ptos,0);//建立任务的堆栈

err=OSTCBInit(prio,psp,(void*)0,0,0,(void*)0,0);

//从空闲的OS_TCB池中获得并初始化一个OS_TCB

if(err==OS_NO_ERR){

OS_ENTER_CRITICAL();

OSTaskCtr++;//于保存产生的任务数目

OSTaskCreateHook(OSTCBPrioTbl[prio]);

//户自己定义的函数,用来扩展OSTaskCreate()的功能

OS_EXIT_CRITICAL();

if(OSRunning){//如果OSTaskCreate()函数是在某个任务的执行过程中被调用

OSSched();//调用调度函数

}

}else{

OS_ENTER_CRITICAL();

OSTCBPrioTbl[prio]=(OS_TCB*)0;//放弃该任务的优先级

OS_EXIT_CRITICAL();

}

return(err);

}else{

OS_EXIT_CRITICAL();

return(OS_PRIO_EXIST);

}

}

用OSTaskCreateExt()函数来建立任务会更加灵活,但会增加一些额外的开销。

其内部结构与OSTaskCreate()大体相同。

2.任务堆栈:

每个任务都有自己的堆栈空间。

堆栈必须声明为OS_STK类型,

并且由连续的内存空间组成。

用户可以静态分配堆栈空间(在编译的时候分

配)也可以动态地分配堆栈空间(在运行的时候分配)。

µC/OS-?

支持的处理

器的堆栈既可以从上(高地址)往下(低地址)长也可以从下往上长。

用户在

调用OSTaskCreate()或OSTaskCreateExt()的时候必须知道堆栈是怎样长

的,因为用户必须得把堆栈的栈顶传递给以上两个函数,当OS_CPU.H文件

中的OS_STK_GROWTH置为0时,用户需要将堆栈的最低内存地址传递给任

务创建函数,当OS_CPU.H文件中的OS_STK_GROWTH置为1时,用户需要将

堆栈的最高内存地址传递给任务创建函数。

任务所需的堆栈的容量是由应

用程序指定的。

用户在指定堆栈大小的时候必须考虑用户的任务所调用的

所有函数的嵌套情况,任务所调用的所有函数会分配的局部变量的数目,

以及所有可能的中断服务例程嵌套的堆栈需求。

另外,用户的堆栈必须能

储存所有的CPU寄存器。

3.堆栈检验OSTaskStkChk():

为了使用µC/OS-?

的堆栈检验功能,用户必须要做以下几件事情:

在OS_CFG.H文件中设OS_TASK_CREATE_EXT为1。

用OSTaskCreateExt()建立任务,并给予任务比实际需要更多的内存空间。

在OSTaskCreateExt()中,将参数opt设置为OS_TASK_OPT_STK_CHK+

OS_TASK_OPT_STK_

CLR。

注意如果用户的程序启动代码清除了所有的RAM,并且从未删除过已

建立了的任务,那么用户就不必设置选项OS_TASK_OPT_STK_CLR了。

这样

就会减少OSTaskCreateExt()的执行时间。

将用户想检验的任务的优先级作为OSTaskStkChk()的参数并调用之。

OSTaskStkChk()顺着堆栈的栈底开始计算空闲的堆栈空间大小。

具体实现方法是统计储存值为0的连续堆栈入口的数目,直到发现储存值不为0的堆栈入口。

用户应该使自己的应用程序运行足够长的时间,并且经历最坏的堆栈使用情况,这样才能得到正确的数。

4.删除任务OSTaskDel():

删除任务,是说任务将返回并处于休眠状态,并不

是说任务的代码被删除了,只是任务的代码不再被µC/OS-?

调用。

过调用

OSTaskDel()就可以完成删除任务的功能。

删除任务程序清单

INT8UOSTaskDel(INT8Uprio)

{

OS_TCB*ptcb;

OS_EVENT*pevent;

if(prio==OS_IDLE_PRIO){//确保用户所要删除的任务并非是空闲任务

return(OS_TASK_DEL_IDLE);

}

if(prio>=OS_LOWEST_PRIO&&prio!

=OS_PRIO_SELF){

//用户可以删除statistic任务

return(OS_PRIO_INVALID);

}

OS_ENTER_CRITICAL();

if(OSIntNesting>0){//确保用户不是在ISR例程中去试图删除一个任务

OS_EXIT_CRITICAL();

return(OS_TASK_DEL_ISR);

}

if(prio==OS_PRIO_SELF){//任务可以通过指定OS_PRIO_SELF参数来删除自己

Prio=OSTCBCur->OSTCBPrio;

}

if((ptcb=OSTCBPrioTbl[prio])!

=(OS_TCB*)0){//保证被删除的任务确实存在

if((OSRdyTbl[ptcb->OSTCBY]&=~ptcb->OSTCBBitX)==0){

OSRdyGrp&=~ptcb->OSTCBBitY;//任务处于就绪表中,它会直接被移除

}

if((pevent=ptcb->OSTCBEventPtr)!

=(OS_EVENT*)0){

if((pevent->OSEventTbl[ptcb->OSTCBY]&=~ptcb->OSTCBBitX)==0){//如果任务处于邮箱、消息队列或信号量的等待表中,它就从自己所处的表中被移除

pevent->OSEventGrp&=~ptcb->OSTCBBitY;

}

}

Ptcb->OSTCBDly=0;

//将任务的时钟延迟数清零,以确保自己重新允许中断的时候,ISR例程不会使该任务就绪

Ptcb->OSTCBStat=OS_STAT_RDY;//阻止其它任务或ISR例程让该任务重新开始执行

OSLockNesting++;//阻止任务调度程序在删除过程中切换到其它的任务中去

OS_EXIT_CRITICAL();//重新允许中断以减少中断的响应时间

OSDummy();//确保在再次禁止中断之前至少执行了一个调用指令和一个返回指令

OS_ENTER_CRITICAL();

OSLockNesting--;//锁定嵌套计数器减一以重新允许任务调度

OSTaskDelHook(ptcb);//调用用户自定义的OSTaskDelHook()函数

OSTaskCtr--;

OSTCBPrioTbl[prio]=(OS_TCB*)0;//将指向被删除的任务的OS_TCB的指针指向NULL

if(ptcb->OSTCBPrev==(OS_TCB*)0){//将任务从OS_TCB双向链表中移除

ptcb->OSTCBNext->OSTCBPrev=(OS_TCB*)0;

OSTCBList=ptcb->OSTCBNext;

}else{

ptcb->OSTCBPrev->OSTCBNext=ptcb->OSTCBNext;

ptcb->OSTCBNext->OSTCBPrev=ptcb->OSTCBPrev;

}

ptcb->OSTCBNext=OSTCBFreeList;

//OS_TCB返回到空闲OS_TCB表中,并允许其它任务的建立

OSTCBFreeList=ptcb;

OS_EXIT_CRITICAL();

OSSched();//中断服务子程序是否曾使更高优先级的任务处于就绪状态

return(OS_NO_ERR);

}else{

OS_EXIT_CRITICAL();

return(OS_TASK_DEL_ERR);

}

}

5.请求删除任务,OSTaskDelReq():

有时候,如果任务A拥有内存缓冲区或

信号量之类的资源,而任务B想删除该任务,这些资源就可能由于没被释

放而丢失。

在这种情况下,用户可以想法子让拥有这些资源的任务在使用

完资源后,先释放资源,再删除自己。

用户可以通过OSTaskDelReq()函数

来完成该功能。

6.改变任务的优先级OSTaskChangePrio():

为了改变调用本函数的任务的优

先级,用户可以指定该任务当前的优先级或OS_PRIO_SELF,

OSTaskChangePrio()会决定该任务的优先级。

用户还必须指定任务的新(即

想要的)优先级。

因为µC/OS-?

不允许多个任务具有相同的优先级,所以

OSTaskChangePrio()需要检验新优先级是否是合法的

7.挂起任务OSTaskSuspend():

挂起任务可通过调用OSTaskSuspend()函数

来完成。

被挂起的任务只能通过调用OSTaskResume()函数来恢复。

OSTaskSuspend()要确保用户的应用程序不是在挂起空闲任务

确认用户指定优先级是有效的,记住最大的有效的优先级数是

OS_LOWEST_PRIO

检验用户是否通过指定OS_PRIO_SELF来挂起调用本函数的任务本身

用户也可以通过指定优先级来挂起调用本函数的任务

检验要挂起的任务是否存在

在任务的OS_TCB中设置OS_STAT_SUSPEND标志,以表明任务正在被挂

若被挂起的任务是调用本函数的任务本身,调用任务调度程序

任务管理2

1.时钟节拍:

µC/OS-?

(其它内核也一样)要求用户提供定时中断来实现延时与超时控制等功能。

五个与时钟节拍有关的系统服务:

OSTimeDly()

OSTimeDlyHMSM()

OSTimeDlyResume()

OSTimeGet()

OSTimeSet()

2.任务延时函数OSTimeDly():

调用该函数会使µC/OS-?

进行一次任务调度,并且执行下一个优先级最高的就绪态任务。

其实现过程如下:

如果用户指定0值,则表明用户不想延时任务,函数会立即返回到调

用者

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 解决方案

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1