收藏 分享(赏)

ucos-ii源码分析.doc

上传人:cjc2202537 文档编号:204151 上传时间:2018-03-23 格式:DOC 页数:15 大小:94.50KB
下载 相关 举报
ucos-ii源码分析.doc_第1页
第1页 / 共15页
ucos-ii源码分析.doc_第2页
第2页 / 共15页
ucos-ii源码分析.doc_第3页
第3页 / 共15页
ucos-ii源码分析.doc_第4页
第4页 / 共15页
ucos-ii源码分析.doc_第5页
第5页 / 共15页
点击查看更多>>
资源描述

1、首先从 main函数开始,下面是 uC/OS-II main函数的大致流程:main()OSInit();TaskCreate(.);OSStart();首先是调用 OSInit进行初始化,然后使用 TaskCreate创建几个进程/Task,最后调用 OSStart,操作系统就开始运行了。OSInit最先看看 OSInit完成哪些初始化:void OSInit (void)#if OS_VERSION = 204OSInitHookBegin(); #endifOS_InitMisc(); OS_InitRdyList(); OS_InitTCBList(); OS_InitEventLis

2、t(); #if (OS_VERSION = 251) #endif#if (OS_MEM_EN 0) #endif#if (OS_Q_EN 0) #endifOS_InitTaskIdle(); #if OS_TASK_STAT_EN 0OS_InitTaskStat(); #endif#if OS_VERSION = 204OSInitHookEnd(); #endif#if OS_VERSION = 270 #endifOS_InitMisc()完成的是一些其其他他的变量的初始化:OSIntNesting = 0; OSLockNesting = 0; OSTaskCtr = 0; OS

3、Running = FALSE; OSCtxSwCtr = 0; OSIdleCtr = 0L; 其中包括:中断嵌套标志 OSIntNesting,调度锁定标志 OSLockNesting,OS 标志OSRunning等。OSRunning 在这里设置为 FALSE,在后面 OSStartHighRdy中会被设置为TRUE表示 OS开始工作。OS_InitRdyList()初始化就绪 Task列表:static void OS_InitRdyList (void)INT8U i;INT8U *prdytbl;OSRdyGrp = 0x00; prdytbl = for (i = 0; i OS

4、TCBNext = ptcb2;#if OS_TASK_NAME_SIZE 1ptcb1-OSTCBTaskName0 = ?; ptcb1-OSTCBTaskName1 = OS_ASCII_NUL;#endifptcb1+;ptcb2+;ptcb1-OSTCBNext = (OS_TCB *)0; #if OS_TASK_NAME_SIZE 1ptcb1-OSTCBTaskName0 = ?; ptcb1-OSTCBTaskName1 = OS_ASCII_NUL;#endifOSTCBList = (OS_TCB *)0; OSTCBFreeList = 这里完成的工作很简单,首先把整个

5、数组使用 OSTCBNext指针连接成链表链起来,然后将 OSTCBList初始化为 0,也就是还没有 TCB,因为还没有 Task产生,OSTCBFreeList指向 OSTCBTbl数组的第一个表示所有 TCB都处于 Free状态。OS_InitEventList()初始化 Event列表。static void OS_InitEventList (void)#if OS_EVENT_EN OS_EVENT *pevent1;OS_EVENT *pevent2;OS_MemClr(INT8U *)pevent1 = pevent2 = for (i = 0; i OSEventType =

6、 OS_EVENT_TYPE_UNUSED;pevent1-OSEventPtr = pevent2;#if OS_EVENT_NAME_SIZE 1pevent1-OSEventName0 = ?; pevent1-OSEventName1 = OS_ASCII_NUL;#endifpevent1+;pevent2+;pevent1-OSEventType = OS_EVENT_TYPE_UNUSED;pevent1-OSEventPtr = (OS_EVENT *)0;#if OS_EVENT_NAME_SIZE 1pevent1-OSEventName0 = ?; pevent1-OSE

7、ventName1 = OS_ASCII_NUL;#endifOSEventFreeList = #elseOSEventFreeList = OSEventFreeList-OSEventType = OS_EVENT_TYPE_UNUSED;OSEventFreeList-OSEventPtr = (OS_EVENT *)0;#if OS_EVENT_NAME_SIZE 1OSEventFreeList-OSEventName0 = ?; OSEventFreeList-OSEventName1 = OS_ASCII_NUL;#endif#endif#endif同样将 EventTbl数组

8、中的 OSEventType都初始化为 OS_EVENT_TYPE_UNUSED。OS_InitTaskIdle(),中间我们跳过其他的如 Mem等的初始化,看看 Idle Task的初始化。(void)OSTaskCreateExt(OS_TaskIdle,(void *)0, 其实 Idle Task的初始化很简单就是调用 OSTaskCrete系列的函数创建一个 Task, OSTaskCreate我们后面再做进一步分析。初始化 State Task也是类似调用 OSTaskCreate系列函数创建 Stat Task。这里只是创建了该 Task的各个结构还没有真正运行该 Task,直到

9、 OSStart中才依据优先级调度运行。OK,到这里 OSInit算高一个段落了,我们接着回到 main往下看。OSTaskCreateOSTaskCreate负责创建 Task所需的数据结构,该函数原形如下所示:INT8U OSTaskCreate (void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT8U prio)其中 task是一个函数指针,指向该 Task所开始的函数,当这个 Task第一次被调度运行时将会从 task处开始运行。p_arg是传给 task的参数指针;ptos是堆栈指针,指向栈顶(堆栈从上往下)或栈底(堆栈从下往

10、上);prio是进程的优先级,uC/OS-II 共支持最大 64个优先级,其中最低的两个优先级给Idle和 Stat进程,并且各个 Task的优先级必须不同。接下来,我们看看这个函数的执行流程:#if OS_ARG_CHK_EN 0if (prio OS_LOWEST_PRIO) return (OS_PRIO_INVALID);#endifOS_ENTER_CRITICAL();if (OSIntNesting 0) OS_EXIT_CRITICAL();return (OS_ERR_TASK_CREATE_ISR);if (OSTCBPrioTblprio = (OS_TCB *)0) O

11、STCBPrioTblprio = (OS_TCB *)1; OS_EXIT_CRITICAL();psp = (OS_STK *)OSTaskStkInit(task, p_arg, ptos, 0); err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0);if (err = OS_NO_ERR) if (OSRunning = TRUE) OS_Sched(); else OS_ENTER_CRITICAL();OSTCBPrioTblprio = (OS_TCB *)0;OS_EXIT_CRITICAL();return

12、 (err);OS_EXIT_CRITICAL();return (OS_PRIO_EXIST);OS_LOWEST_PRIO在 ucos-ii.h中被定义为 63,表示 Task的优先级从 0到 63,共 64级。首先判断 prio是否超过最低优先级,如果是,则返回 OS_PRIO_INVALID错误。然后调用 OS_ENTER_CRITICAL(),进入临界段,在临界段中的代码执行不允许被中断。这个宏是用户自定义的,一般是进行关中断操作,例如在 x86中的 CLI等。这个宏和OS_EXIT_CRITICAL()相对应,这个宏表示离开临界段。OSTaskCreate不允许在中断中调用,因此会

13、判断 OSIntNesting是否大于 0,如果大于 0,表示正在中断嵌套,返回 OS_ERR_TASK_CREATE_ISR错误。接着判断该 prio是否已经有 Task存在,由于 uC/OS-II只支持每一个优先级一个Task,因此如果该 prio已经有进程存在,OSTaskCreate 会返回 OS_PRIO_EXIST错误。相反,如果该 prio先前没有 Task存在,则将 OSTCBPrioTblprio置 1,表示该 prio已被占用,然后调用 OSTaskStkInit初始化堆栈,调用 OS_TCBInit初始化 TCB,如果OSRunning为 TRUE表示 OS正在运行,则调

14、用 OS_Sched进行进程调度;否则返回。下面来看看 OSTaskStkInit和 OS_TCBInit这两个函数。OSTaskStkInit是一个用户自定义的函数,因为 uC/OS-II在设计时无法知道当前处理器在进行进程调度时需要保存那些信息,OSTaskStkInit 就是初始化堆栈,让 Task看起来就好像刚刚进入中断并保存好寄存器的值一样,当 OS_Sched调度到该 Task时,只需切换到该堆栈中,将寄存器值 Pop出来,然后执行一个中断返回指令 IRET即可。OSTaskStkInit的原型如下:OS_STK *OSTaskStkInit (void (*task)(void

15、*pd), void *pdata, OS_STK *ptos, INT16U opt)和 OSTaskCreate类似,task 是进程入口地址,pdata 是参数地址,ptos 是堆栈指针,而 opt只是作为一个预留的参数 Option而保留。返回的是调整以后的堆栈指针。在 OSTaskStkInit中,一般是将 pdata入栈,flag 入栈,task 入栈,然后将各寄存器依次入栈。OS_TCBInit初始化 TCB数据结构,下面只提取主要部分来看:INT8U OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, I

16、NT32U stk_size, void *pext, INT16U opt)OS_TCB *ptcb;OS_ENTER_CRITICAL();ptcb = OSTCBFreeList; if (ptcb != (OS_TCB *)0) OSTCBFreeList = ptcb-OSTCBNext; OS_EXIT_CRITICAL();ptcb-OSTCBStkPtr = ptos; ptcb-OSTCBPrio = prio; ptcb-OSTCBStat = OS_STAT_RDY; ptcb-OSTCBPendTO = FALSE; ptcb-OSTCBDly = 0; #if OS_

17、TASK_CREATE_EXT_EN 0ptcb-OSTCBExtPtr = pext; ptcb-OSTCBStkSize = stk_size; ptcb-OSTCBStkBottom = pbos; ptcb-OSTCBOpt = opt; ptcb-OSTCBId = id; #elsepext = pext; stk_size = stk_size;pbos = pbos;opt = opt;id = id;#endif#if OS_TASK_DEL_EN 0ptcb-OSTCBDelReq = OS_NO_ERR;#endifptcb-OSTCBY = (INT8U)(prio 3

18、); ptcb-OSTCBBitY = OSMapTblptcb-OSTCBY;ptcb-OSTCBX = (INT8U)(prio ptcb-OSTCBBitX = OSMapTblptcb-OSTCBX;#if OS_EVENT_ENptcb-OSTCBEventPtr = (OS_EVENT *)0; #endifOSTaskCreateHook(ptcb); OS_ENTER_CRITICAL();OSTCBPrioTblprio = ptcb;ptcb-OSTCBNext = OSTCBList; ptcb-OSTCBPrev = (OS_TCB *)0;if (OSTCBList

19、!= (OS_TCB *)0) OSTCBList-OSTCBPrev = ptcb;OSTCBList = ptcb;OSRdyGrp |= ptcb-OSTCBBitY; OSRdyTblptcb-OSTCBY |= ptcb-OSTCBBitX;OSTaskCtr+; OS_EXIT_CRITICAL();return (OS_NO_ERR);OS_EXIT_CRITICAL();return (OS_NO_MORE_TCB);首先调用 OS_ENTER_CRITICAL进入临界段,首先从 OSTCBFreeList中拿出一个 TCB,如果 OSTCBFreeList为空,则返回 OS_

20、NO_MORE_TCB错误。然后调用 OS_EXIT_CRITICAL离开临界段,接着对该 TCB进行初始化:将 OSTCBStkPtr初始化为该 Task当前堆栈指针;OSTCBPrio设置为该 Task的 prio;OSTCBStat设置为 OS_STAT_RDY,表示就绪状态;OSTCBDly设置为 0,当该 Task调用 OSTimeDly时会初始化这个变量为 Delay的时钟数,然后 Task转入 OS_STAT_状态。这个变量在 OSTimeTick中检查,如果大于 0表示还需要进行 Delay,则进行减 1;如果等于零表示无须进行 Delay,可以马上运行,转入OS_STAT_R

21、DY状态。OSTCBBitY和 OSTCBBitX的作用我们在等会专门来讨论。紧接着就要将该 TCB插入 OSTCBList列表中,先调用 OS_ENTER_CRITICAL进入临界段,将该 TCB插入到 OSTCBList成为第一个节点,然后调整 OSRdyGrp和 OSRdyTbl,(这两个变量一会和 OSTCBBitX/OSTCBBitY一起讨论),最后将 OSTaskCtr计数器加一,调用OS_EXIT_CRITICAL退出临界段。OSMapTbl和 OSUnMapTbl刚才我们看到 TCB数据结构中的 OSTCBBitX/OSTCBBitY以及 OSRdyGrp/OSRdyTbl的使

22、用,这里专门来讨论讨论这几个变量的用法。uC/OS-II将 64个优先级的进程分为 8组,每组 8个。刚好可以使用 8个 INT8U的数据进行表示,于是这就是 OSRdyGrp和 OSRdyTbl的由来,OSRdyGrp 表示组别,从 0到 7,从前面我们可以看到 OSRdyGrp和 OSRdyTbl是这么被赋值的:OSRdyGrp |= ptcb-OSTCBBitY;OSRdyTblptcb-OSTCBY |= ptcb-OSTCBBitX;也就是 OSTCBBitY保存的是组别,OSTCBBitX 保存的是组内的偏移。而这两个变量是这么被初始化的:ptcb-OSTCBY = (INT8U)

23、(prio 3);ptcb-OSTCBBitY = OSMapTblptcb-OSTCBY;ptcb-OSTCBX = (INT8U)(prio ptcb-OSTCBBitX = OSMapTblptcb-OSTCBX;由于 prio不会大于 64,prio 为 6位值,因此 OSTCBY为 prio高 3位,不会大于8,OSTCBX 为 prio低 3位。这里就涉及到 OSMapTbl数组和 OSUnMapTbl数组的用法了。我们先看看 OSMapTbl和OSUnMapTbl的定义:INT8U const OSMapTbl8 = 0x01, 0x02, 0x04, 0x08, 0x10, 0

24、x20, 0x40, 0x80;INT8U const OSUnMapTbl256 = 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0

25、, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0

26、, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 ;OSMapTbl分别是一个 INT8U的八个位,而 OSUnMap数组中的值就是从 0x00到 0xFF的八位中,每一个值所对应的最低位的值。我们在调度的时候只需将 OSRdy

27、Grp的值代入OSUnMapTbl数组中,得到 OSUnMapTblOSRdyGrp的值就是哪个优先级最高的 Group有Ready进程存在,再使用该 Group对应 OSRdyTbl数组中的值一样带入 OSUnMapTbl中就可以得出哪个 Task是优先级最高的。于是我们提前来看看 OS_Sched()中获取最高优先级所使用的方法:y = OSUnMapTblOSRdyGrp; OSPrioHighRdy = (INT8U)(y OSTCBY |= ptcb-OSTCBBitX 就等于将该进程所对应的Bit置 1了。OSStartOK,接下来我们来看这个开始函数了。OSStart 其实很短,只有匆匆几句代码:void OSStart (void)INT8U y;INT8U x;if (OSRunning = FALSE) y = OSUnMapTblOSRdyGrp; x = OSUnMapTblOSRdyTbly;OSPrioHighRdy = (INT8U)(y 3) + x);

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

当前位置:首页 > 高等教育 > 教育学

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报