在uCOS-II里,时钟节拍就好比是人的心脏一样重要。它对于CPU能顺利在各任务间切换有着至关重要的作用。
uCOS-II需要用户提供时钟源。使用时钟源有一个特别需要注意的地方:用户必须在多任务系统启动以后再开启时钟节拍器,也就是在调用OSStart()之后。
Ucos II中的时钟节拍服务是通过在定时器中断服务子程序中调用OSTimeTick()实现的。
OSTimeTick()代码如下:
void OSTimeTick (void)
{
OS_TCB *ptcb;
OSTimeTickHook(); //(1)
ptcb = OSTCBList; //(2)
while (ptcb->OSTCBPrio != OS_IDLE_PRIO) { //(3)
OS_ENTER_CRITICAL();
if (ptcb->OSTCBDly != 0) {
if (--ptcb->OSTCBDly == 0) {
if (!(ptcb->OSTCBStat & OS_STAT_SUSPEND)) { //(4)
OSRdyGrp |= ptcb->OSTCBBitY; //(5)
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
} else {
ptcb->OSTCBDly = 1;
}
}
}
Ptcb = ptcb->OSTCBNext;
OS_EXIT_CRITICAL();
}
OS_ENTER_CRITICAL(); //(6)
OSTime++; //(7)
OS_EXIT_CRITICAL();
}
我们知道,CPU总是执行就绪表中优先级最高的任务,任务有没有在就绪表中就得依靠OSTimeTick()了。OSTimeTick()很大的工作是给每个用户任务控制块OS_TCB中的时间延时项OSTCBDly减1,当某任务的任务控制块中的时间延时项OSTCBDly减到了零,这个任务就进入了就绪态。
下面是对以上代码的分析。
OSTimtick()先调用可由用户定义的时钟节拍外连函数OSTimeTickHook(),这个外连函数可以将时钟节拍函数OSTimetick()予以扩展(1)。uCOS-II的作者决定首先调用OSTimTickHook()是打算在时钟节拍中断服务一开始就给用户一个可以做点什么的机会,因为用户可能会有一些时间要求苛刻的工作要做。OSTimtick()中量大的工作是给每个用户任务控制块OS_TCB中的时间延时项OSTCBDly减1(如果该项不为零的话)。OSTimTick()从OSTCBList开始,沿着OS_TCB链表做,一直做到空闲任务(3)。当某任务的任务控制块中的时间延时项OSTCBDly减到了0,这个任务就进入了就绪态(5)。而确切被任务挂起的函数OSTaskSuspend()挂起的任务则不会进入就绪态(4)。OSTimTick()的执行时间直接与应用程序中建立了多少个任务成正比。OSTimeTick()还通过调用OSTime (7)累加从开机以来的时间,用的是一个无符号32位变量。注意,在给OSTime加1之前使用了关中断,因为多数微处理器给32位数加1的操作都得使用多条指令。