ucos中文书-第3章内核结构_第1页
ucos中文书-第3章内核结构_第2页
ucos中文书-第3章内核结构_第3页
ucos中文书-第3章内核结构_第4页
ucos中文书-第3章内核结构_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

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

文档简介

第3章内核结 临界段(Critical 任 任务状 任务控制块(TaskControlBlocks, 就绪表(Ready 给调度器上锁和开锁(LockingandUnLockingthe 空闲任务(Idle 统计任 μC/OS中的中断处 时钟节 第3章OS_ENTER_CRITICAL(OSIntEnter(OSSchedLock(OSSchedUnlock(),临界段(Critical时内核开发商应提供的最重要的指标之一,因为这个指标影响用户系统对实件的响应CCCCCCμC/OS-Ⅱ中的这两个宏调用分别是:OS_ENTER_CRITICALOS_EXIT_CRITICAL()。因为这两个宏的定义取决于所用的微处理器,故在文件OS_CPU.H中可以找到相应宏定义。每种微处理器都有自己的OS_CPU.H任其它C的函数一样,有函数返回类型,有形式参数变量,但是任务是绝不会返回的。故返回void[L3.1(1)]。voidvoidYourTask(void{for(;;)/*/*}}程L3.1μC/OSOSTaskDel(),这个任务绝不会返回什么。程序L3.2.任务完成后自我删voidvoidYourTask(void{/*用户代码*/}口的参数(波特率、I/O。用了。作者保留了优先级为0、1、2、3、OS_LOWEST_PRIO-3、OS_LOWEST_PRI0-2为定义的常数在OS_CFG.H文件中用定义常数语句#defineconstant定义的。因此用户可以有多达56个应用任务。必须给每个任务赋以不同的优先级,优先级可以从0到(ID(或任务的ID号也被一些内核服务函数调如改变优先级函数OSTaskChangePrio(),OSTaskDel()。址与其它参数一起传给下面两个函数中的一个:OSTastCreatOSTaskCreatExtOSTaskCreateExt()OSTaskCreate()任务状(L3.2立即得到CPU的控制权。一个任务可以通过调用OSTaskDel()返回到睡眠态,或通过调用该3.1正在运行的任务可以通过调用两个函数之一将自身延迟一段时间,这两个函数是OSTimeDly(OSTimeDlyHMSMCPUOSTimeTick()使延迟了的任务进入就绪态(3.10。正在运行的任务期待某 的发生时也要等待 是调用以下3个函数之一。(WAITING(Pend,件发生了,被挂起的任务进入就绪态发生的报告可能来自另一个任务,也可能来自中。(ISR务子程序控制了CPU的使用权。中断服务子程序可能会报告一个或多个的发生,而使taskOSTaskIdle()函数。任务控制块(TaskControlBlocks,一旦任务建立了,任务控制块OS_TCBs将被赋值(程序3.3。任务控制块是一个数据结构,当任务的CPU使用权被时,μC/OS-Ⅱ用它来保存该任务的状态。当任务重CPUOS_TCBsRAM的逻辑分组。任务建立的时候,OS_TCBs(见第四章任务管理。程序L µC/OS-II任务控制块typedefstructos_tcb{typedefstructos_tcb{ #if structos_tcb*OSTCBNext;structos_tcb#if(OS_Q_EN&&(OS_MAX_QS>=2))||OS_MBOX_EN||OS_SEM_EN #if(OS_Q_EN&&(OS_MAX_QS>=2))||OS_MBOX_EN #if }中唯一的一个能用汇编语言来处置的变量(Context-switchingcode).OSTCBExtPtr指向用户定义的任务控制块扩展。用户可以扩展任务控制块而不必修改μC/OS-Ⅱ的源代码。.OSTCBExtPtr只在函数OstaskCreateExt()中使用,故使用时要将OS_TASK_CREAT_EN1,以允许建立任务函数的扩展。例如用户可以建立一个数据结构,3OSTaskCreateExt()OS_TASK_CREATE_EXT_EN1,以便允许该功能。4,000字节同样是1,000个地址如果每个地址宽度是16位的则总栈容量只有2,000字节。在函数OSStakChk()中要调用OSTCBStkSize。同理,若使用该函数的话,要将OS_TASK_CREAT_EXT_EN1。.OSTCBOpt把“选择项”传给OSTaskCreateExt(),只有在用户将OS_TASK_CREATE_EXT_EN设为1时,这个变量才有效。μC/OS-Ⅱ目前只支持3个选择项(见uCOS_II.H 初始化时,已将RAM清过零,则OS_TASK_OPT_STK_CLR不需要再定义,这可以节约程序执行时间。传递了OS_TASK_OPT_STK_CLR将增加TaskCreateExt()函数的执行时间,因为要将栈空间。栈容量越大,花的时间越长。最后一个选择项OS_TASK_OPT_SAVE_FP通知.OSTCBId用于任务的识别码。这个变量现在没有使用,留给将来扩展用.OSTCBNext和.OSTCBPrev用于任务控制块OS_TCBs的双重,该链表在时钟节拍函数.OSTCBMsg是指向传给任务的消息的指针。用法将在后面的章节中提到(见第6章任务间通.OSTCBStat是任务的状态字。当.OSTCBStat为0,任务进入就绪态。可以给.OSTCBStat赋uCOS_II.H.OSTCBX,.OSTCBY,.OSTCBBitX.OSTCBBitY用于加速任务进入就绪态的过程或进入等者是在改变任务优先级时算出的。这些值的算法见程序L3.4。=priority>>=OSMapTbl[priority>>=priority&=OSMapTbl[priority&程L3.4任务控制块OS_TCB(4应用程序中可以有的最多任务数(OS_MAX_TASKS)OS_CFG.H最多任务数也是μC/OS-Ⅱ分配给用户程序的最多任务控制块OS_TCBs的数目。将OS_MAX_TASKSRAMOS_N_SYS_TASKSμC/OS-Ⅱ.H,供其目前,一个用于空闲任务,另一个用于任务统计(如果OS_TASK_STAT_EN是设为1的。在μC/OS-Ⅱ初始化的时候,如图3.2所示,所有任务控制块OS_TCBs被成单向空任务链表。当任务一旦建立,空任务控制块指针OSTCBList指向的任务控制块便赋给了该任务,然后OSTCBList的值调整为指向下链表中下一个空的任务控制块。一旦任务被删3.2就绪表(Ready每个任务被赋予不同的优先级等级,从0级到最低优先级OS_LOWEST_PR1O,包括0和OS_LOWEST_PR1O在内(见文件OS_CFG.H。当μC/OS-Ⅱ初始化的时候,最低优先级OS_LOWEST_PR1O总是被赋给空闲任务idletask。注意,最多任务数目OS_MAX_TASKS和最每个任务的就绪态标志都放入就绪表中的,就绪表中有两个变量OSRedyGrp和OSRdyTbl[]。在OSRdyGrp中,任务按优先级分组,8个任务为一组。OSRdyGrp中的每一位表示8组任务中每一组中是否有进入就绪态的任务进入就绪态时就绪表OSRdyTbl[]OSRdyTbl[]OS_LOWEST_PR1O(见文件OS_CFG.H)。当用户的应用程序中任务数目比较少时,减少OS_LOWEST_PR1O的值可以降低μC/OSRAM(数据空间)的需求量。中相应字节的相应位置1。OSRdyGrp和OSRdyTbl[]之间的关系见图3.3,是按以下规则给出OSRdyTbl[0]中的任何一1时,OSRdyGrp的第0位置1,OSRdyTbl[1]中的任何一位是1时,OSRdyGrp的第1位置1,当OSRdyTbl[2]中的任何一1时,OSRdyGrp的第2位置1,当OSRdyTbl[3]中的任何一1时,OSRdyGrp的第3位置1,当OSRdyTbl[4]中的任何一1时,OSRdyGrp的第4位置1,当OSRdyTbl[5]中的任何一位是1时,OSRdyGrp的第5位置1,当OSRdyTbl[6]中的任何一1时,OSRdyGrp的第6位置1,程 |=OSMapTbl[prio>>OSRdyTbl[prio>>3]|=OSMapTbl[prio&程L3.5表T3.1OSMapTbl BitMask001224345667接下去的三位用于确定是在OSRdyTbl[]数组的第几个元素。OSMapTbl[]是在ROM中的(见文件OS_CORE.C) 字,用于限制OSRdyTbl[]数组的元素下标在0到7之间,见表3.1程序L3.6从就绪表中删除一个任ifif((OSRdyTbl[prio>>3]&=~OSMapTbl[prio&0x07])==OSRdyGrp&=~OSMapTbl[prio>>字节的8位代表这一组的8个任务哪些进入就绪态了,低位的优先级高于。利用这个字那个任务所在的位置这个返回值在0到7之间。确定进入就绪态的优先级最高的任务是用以下代码完成的,如程序L3.7所示。程序L3.7找出进入就绪态的优先级最高的任 = =prio=(y<<3)+ OSRdyGrpOSUnMapTbl[OSRdyGrp]得到的值是3,它相应于OSRdyGrp中的第3bit3,这里假设最右边的一位是第0bit0。类似地,OSRdyTbl[3]的值是二进制OSUnMapTbl[OSRdyTbc[3]22位。于是任务的优先级Prio就等于2(3*8+2。利用这个优先级的值。查任务控制块优先OSTCBPrioTbl[OS_TCB任务调度(TaskOSSched()完成的。OSIntExt()完成的,这个函数将在以后描述。OSSched()的代码如程序L3.8所示。程序L3.8任务调度器(theTaskvoidOSSched{INT8Uif((OSLockNesting|OSIntNesting)==0) =OSPrioHighRdy=(INT8U)((y<<3)+if(OSPrioHighRdy!=OSPrioCur)OSTCBHighRdy=}}}中[L3.8(1)]条件语句的条件不满足,任务调度函数OSSched()将退出,不做任务调度。这OSSched()OSIntNesting>0,OSSchedLockOSLockNesting>0。OSSched(),并且任务调度是允许的,即没有上锁,则任务μC/OSOSTCBHighRdyOSTCBCur816μC/OS-Ⅱ中是两个整数的比较。并且,除非用户实际需要做任务切换,在查任务控制块优先级表OSTCBPrioTbl[]OSTCBHighRdy。综合这两项改进,即用整数比较代替指针的比较和当需要任务切换时再查表,使得μC/OS-Ⅱ比μC/OS816通过将以OSPrioHighRdy为下标的OSTCBPrioTbl[]数组中的那个元素赋给OSTCBHighRdy来OS_TASK_SW()来完成实际上的任务切换[L3.8(6)]。μC/OS总是看起来跟刚刚发生过中断一样,所有微处理器的寄存器都保存在栈中。换句话说,μC/OSCPUOS_ASK_SW(RAP(TrphadlereptionhandlerSCtxSw(OSCtxw()OS_TCBighRyOSCBCr指向8μC/OSOSCtSw()OSSched()OSSched()()是用C写的。给调度器上锁和开锁(LockingandUnLockingthe(L3.10的任务保持对CPU的控制权,尽管有个优先级更高的任务进入了就绪态。然而,此时中断是OSLockNesting减到零的时候,OSSchedUnlock()调用OSSched[L3.10(2)]也就是说,用户程序不得调用OSMboxPend()OSQPend()OSSemPend()OSTaskSuspend(OS_PR1O_SELF)、OSTimeDly()OSTimeDlyHMSM(OSLockNesting当低优先级的任务要发消息给多任务的邮箱、消息队列、信号量时(6了CPU的控制权,此时,用户可以使用调度器函数。程序L3.9给调度器上voidOSSchedLock {{if(OSRunning==TRUE){}}voidvoidOSSchedUnlock{if(OSRunning==TRUE){if(OSLockNesting>0){if((OSLockNesting|OSIntNesting)==0){}else}}else}}}程L3.10给调度器开锁空闲任务(Idle这个空闲任务[OSTaskIdle()]设为最低优先级,即OS_LOWEST_PRI0。空闲任务计任(见3.08计任务使用这个计数器以确定现行应用软件实际消耗的CPU时间。程序L3.11是空闲任务的代码。在计数器加1前后,中断是先关掉再开启的,因为8位程序L3.11μC/OS-Ⅱ的空闲任务voidvoidOSTaskIdle(void{pdata=pdata;for(;;){}}统计任μC/OSOSTaskStat(),如果用户将系统定义常数OS_TASK_STAT_EN(见文件OS_CFG.H)设为1,这个任务就会建立。一旦得到OS_CORE.C8OSCPUsage1个任务中调用OSStatInit((见文件OS_CORE.C话说在调用系统启动函数OSStart()之前,用户初始代码必须先建立一个任务,在这个任务中调用系统统计初始化函数程序L3.12初始化统计任务voidmain{ /*初始化uC/OS- /*创建用户起始任务(为了方便讨论,这里以TaskStart()作为起始任务) /*开始多任务调 }voidTaskStart(void{ /*/*创建用户应用程序任for(;;)}}系统启动函数t()的时候,μC/OS-Ⅱ只有3个要管理的任务:TaskStart的优先级设为次低,OS_LOWEST_PR10-1。启动任务TaskStart()总是优先级最高的任务。F3.4μC/OS始化函数OSInit(),该函数初始化μC/OS-Ⅱ[图F3.4(2)]。有的处理器(例如Motorola的MC68HC11),不需要“设置”中断向量,中断向量已经在ROM中有了。用户必须调用TaskStartF3.4(4)]]。TaskStart(F3.4(5)]。在这里启动时钟节拍是必要的,因OSStatInitOSTimeDly()2Ⅱ然后选下一个优先级最高的进入就绪态的任务运行,这恰好是统计任务OSTaskStat()。读者会在后面读到OSTaskStat()的代码,但粗看一下,OSTaskStat()所要做的第一件事就一定会是这样,因为标志OSStatRdyOSInit()函数初始化为“假”,所以实际上OTaskIdl中,直到TaskStart()的延迟两个时钟节拍完成[图3.4(10)]。两个时钟节拍之后,TaskStart(F3.4(11)]。在执行OSStartInitOSIdleCtr其它进入就绪态的任务,OSTaskIdle()又获得了CPU的控制权[图F3.4(14秒钟以后,TaskStart()继续运行,还是在OSStatInit()中,空闲计数器将1秒钟内计数的值存入空闲OSIdleCtrMaxF3.4(15)]。OSStarInit()将统计任务就绪标志OSStatRdy设为“真”[图F3.4(16)],以此来允许两个OSTaskStat()CPU程序L3.13统计任务的初始化voidvoidOSStatInit{ =0L;OSIdleCtrMax=OSIdleCtr; =TRUE;}统计任务OSStat()的代码程序L3.14所示。面一段中,已经讨论了为什么要等待的任务消耗了多少CPU时间。当用户的应用程序代码加入以后,运行空闲任务的CPU时间就最大计数值是OSStatInit()在初始化时保存在计数器最大值OSIdleCtrMax中的。CPU利用率(表达式[3.1])OSCPUsage[L3.14(2)]中的:[3.1]表达式[3.1]表达式Needtotypesetthe一旦上述计算完成,OSTaskStat()调用任务统计外界接入函数OSTaskStatHook()3程序L3.14统计任voidvoidOSTaskStat(void{INT32Urun;INT8Susage;pdatapdata=while(OSStatRdy==FALSE){OSTimeDly(2*OS_TICKS_PER_SEC);}for(;;)OSIdleCtrRun= =OSIdleCtr; =0L;if(OSIdleCtrMax>0L)usage=(INT8S)(100L-100L*run/OSIdleCtrMax);if(usage>100){OSCPUUsage=}elseif(usage<0){OSCPUUsage=0;}elseOSCPUUsage=}}elseOSCPUUsage=}}}μC/OS中的中断处务子程序的示意码如程序L3.15程L3.15μC/OS-II中的中断服务子程序Motorola68020(68020再将寄存器加1,然后再写回到变量OSIatNesting中去,就不如调用OSIatEnter()。证处理OSIntNesting时的排它性直接给OSIntNesting1比调用OSIntEnter()快得多,可能时,直接加1更好。要当心的是,在有些情况下,从OSIntEnter()返回时,会把中断开用户应用程序就会!(SIntNestin>0μCOS-F3.5[F35(1)]PUμC/SCPUCPU[F3.(2)],CPU()跳转到中断服务子程序[F35(3)]。如上所述,中断服务子程序保存CPU寄存器(也叫做CPUcontext)[F.5(4)],μC/OSOSIntnter()OSntNestig直接加1[F35(5)]3.5(6)]去做。中断服务子程序通知某任务去做事的是调用以下函数之一:OMboxPos(),OSQPost()SQPostFont(SSemPos要调用OSInExit()F3.5(7)OSIntExit(CPU[35(8[3.(9OInExi间,因为这时要做任务切换[3.5(1)]。新任务的寄存器内容要恢复并执行中断返回指令[3.5(1)]。3.5进入中断函数OSIntEnter()的代码如程序L3.16所示,从中断服务中退出函程序L3.16通知μC/OS-Ⅱ,中断服务子程序开始了voidvoidOSIntEnter{}voidvoidOSIntExit{if((--OSIntNesting|OSLockNesting)==0){ =OSUnMapTbl[OSRdyGrp];程L3.17通知μC/OSOSPrioHighRdyOSPrioHighRdy=(INT8U)((OSIntExitY<<3)if(OSPrioHighRdy!=OSPrioCur){OSTCBHighRdy=OSTCBPrioTbl[OSPrioHighRdy];}}}Y是保存在全程变量OSIntExitY中的[L3.17(3)]是为了避免在任务栈中安排局部变量。这个变量在哪儿和中断任务切换函数OSIntCtxSw(见9.04.03节,中断任务切换函OS_TASK_SW(OSSched()函数中那样。首先是,如程序中L3.5(1)和图F3.6(1)所示,一半的工作,即CPU寄存器入栈的工作移植μC/OS-Ⅱ。最后,调用OSIntCtxSw()时的返回地址又被推入了堆栈[L3.17(4)和有的微处理器,像Motorola68HC11中断发生时CPU寄存器是自动入栈的,且要想允许务期间开中断,也不需要调用OSIntEnter()或OSIntNesting加1。程序L3。18中的示/*程L3.18Motorola68HC11时钟节μC/OS10次到100次之间,或者说10到100Hz。时钟节拍率越高,系统的额外负荷就越重。时钟50/60Hz将允许时钟节拍器中断放在系统初始化函数voidvoid{..../*/*初始化uC/OS-/*通过调用OSTaskCreate()创建至少一个任..;.. /*开始多任务调 }程L3.19启动时钟就节拍器的不正确做法这里潜在地是,时钟节拍中断有可能在μC/OS-Ⅱ启动第一个任务之前发生,此时程序L3.20时钟节拍中断服务子程序的示意代voidvoid{}时钟节拍函数OSTimeTick()的代码如程序3.21所示。OSTimtick()以调用可由用户定义的时钟节拍外连函数OSTimTickHook()开始,这个外连函数可以将时钟节拍函数工作要做。OSTimtick()中量大的工作是给每个用户任务控制块OS_TCB中的时间延时项OSTCBDly减1(如果该项不为零的话。OSTimTick()从OSTCBList开始,沿着OS_TCB链表voidvoidOSTimeTick{OS_TCBptcb=while(ptcb->OSTCBPrio!=OS_IDLE_PRIO){if(ptcb->OSTCBDly!=0)if(--ptcb->OSTCBDly==0)if(!(ptcb->OSTCBStat&OS_STAT_SUSPEND)) |=ptcb-OSRdyTbl[ptcb->OSTCBY]|=ptcb-}elseptcb->OSTCBDly=}}}ptcb=ptcb->OSTCBNext;} }程L3.21时钟节拍函数OSTimtick()OSTimeTick(OSTime()[L3.21(7)]累加从开机以来的时间,用的是一个无任务级调用OSTimeTick(),如程序L3.22所示。要想这么做,得建立一个高于应用程程序L3.22时钟节拍任务TickTask()作时钟节拍服务voidTickTask(void {{pdata=pdata;for(;;){ /**/}}用户当然需要先建立一个邮箱(NULL)用于发信号给上述任何告知时钟节拍中断已经发生了(程序L3.23程序L3.23时钟节拍中断服务函数OSTickISR()做节拍服务voidvoid{发送一个‘空’消息((void*)1)到时钟节拍的邮箱}μC/OS在调用μC/OS-Ⅱ的任何其它服务之前,μC/OSOS_CORE.C绪态。OSTaskStatOS_LOW

温馨提示

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

评论

0/150

提交评论