uCOS任务中的OSTCBDly
例:应用程序的 2 个任务使用了延时函数 OSTimeDly () 进行延时,在任务 MyTask 中还调用了函数 OSTimeDlyResume () 取消了任务 YourTask 的延时(为了观察任务YourTask 的延时时间的变化,在钩子函数 OSTimeTickHook () 输出了任务 YourTask在延时时间到时的时钟节拍数)。
OSTimeTickHook钩子函数程序如下
#if OS_CPU_HOOKS_EN > 0
INT8U d=0;
INT8U l=0;
INT8U n=0;
INT8U m=0;
INT16U tt=1; //时钟计数器
char s[5];
void OSTimeTickHook (void)
{
if(OSTCBPrioTbl[2]->OSTCBDly == 1)
{
sprintf(s,"%5d",tt);
PC_DispStr(d,l+4,s,DISP_BGND_BLACK+DISP_FGND_WHITE );
d+=6;
}
/*
if(OSTCBPrioTbl[2]->OSTCBDly == 0)
{
sprintf(s,"%5d",tt);
PC_DispStr(d,l+6,s,DISP_BGND_BLACK+DISP_FGND_WHITE );
d+=6;
}
*/
tt+=1;
}
#endif
经过我调试发现当(OSTCBPrioTbl[2]->OSTCBDly == 1) 时,正常显示节拍数,当(OSTCBPrioTbl[2]->OSTCBDly == 0) 时,则不显示节拍数。
所以显然,在OSTimeTickHook函数中OSTCBPrioTbl[2]->OSTCBDly不为0。
但是仔细一想在OSTimeDlyResume () 中
INT8U OSTimeDlyResume (INT8U prio )
{
if ( prio >= OS_LOWEST_PRIO)
{
return (OS_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
ptcb = (OS_TCB * ) OSTCBPrioTbl[prio ];
if ( ptcb != (OS_TCB * )0)
{
if ( ptcb -> OSTCBDly != 0)
{
ptcb -> OSTCBDly = 0;
if (( ptcb -> OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY)
{
OSRdyGrp |= ptcb -> OSTCBBitY ;
OSRdyTbl[ptcb ->OSTCBY] |= ptcb -> OSTCBBitX ;
OS_EXIT_CRITICAL();
OS_Sched ();
}
else
{
OS_EXIT_CRITICAL();
}
return (OS_NO_ERR);
}
else
{
OS_EXIT_CRITICAL();
return (OS_TIME_NOT_DLY);
}
}
OS_EXIT_CRITICAL();
return (OS_TASK_NOT_EXIST);
}
可以看出在OSTCBPrioTbl[prio]->OSTCBDly 被赋值为0,且进行了一次任务调度,那为什么上面的结果又不对了。那就得看void OSTimeTick (void)
void OSTimeTick ( void )
{
OS_TCB *ptcb;
OSTimeTickHook(); //
ptcb = OSTCBList; //时钟节拍到来时,将控制块双向链表的第一个控制块取出(并不是节拍之前运行的任务)
while (ptcb->OSTCBPrio != OS_IDLE_PRIO)
{ //空闲任务处于控制块双向链表的最后一个,如果取出的控制块为空闲任务的控制块,那么已经取到最后一个了,就结束
//OS_ENTER_CRITICAL();
if (ptcb->OSTCBDly != 0)
{ //
if (--ptcb->OSTCBDly == 0)
{ //
if (!(ptcb->OSTCBStat & OS_STAT_SUSPEND))
{ //检查任务是否处于强制挂起状态,如果是,那再挂起一个时钟节拍,否则就将它就绪
OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
}
else
{
ptcb->OSTCBDly = 1;
}
}
}
ptcb = ptcb->OSTCBNext; //下一个任务控制块
//OS_EXIT_CRITICAL();
}
//OS_ENTER_CRITICAL();
OSTime++; //节拍计数器+1
//OS_EXIT_CRITICAL();
}
可见当OSTCBPrioTbl[prio]->OSTCBDly=1时 在OSTimeTick函数中就已经赋值为0了,且将任务放入就绪表。
分析 当使用OSTimeDlyResume ()将任务中OSTCBPrioTbl[prio]->OSTCBDly强制变为0,在进行任务调度,进入优先级高的任务后,任务中肯要使用延时函数,延时一段节拍,进行任务调度,这时候OSTCBPrioTbl[prio]->OSTCBDly就不为0了,所以再进入OSTimeTick函数时,使用(OSTCBPrioTbl[2]->OSTCBDly == 0) 的判断就不对了。所以就为出现上面调试的结果。