μC/OS-II的時間管理
程序清單 L5.2 OSTimeDlyHMSM().
INT8UOSTimeDlyHMSM(INT8Uhours,INT8Uminutes,INT8Useconds,INT16U
milli)
{
INT32Uticks;
INT16Uloops;
if(hours>0|| minutes>0|| seconds>0|| milli>0){(1)
if(minutes>59){
return(OS_TIME_INVALID_MINUTES);
}
if(seconds>59){
return(OS_TIME_INVALID_SECONDS);
}
If(milli>999){
return(OS_TIME_INVALID_MILLI);
}
ticks=(INT32U)hours*3600L*OS_TICKS_PER_SEC(2)
+(INT32U)minutes*60L*OS_TICKS_PER_SEC
+(INT32U)seconds*OS_TICKS_PER_SEC
+OS_TICKS_PER_SEC*((INT32U)milli
+500L/OS_TICKS_PER_SEC)/1000L;(3)
loops=ticks/65536L;(4)
ticks=ticks%65536L;(5)
OSTimeDly(ticks);(6)
while(loops>0){(7)
OSTimeDly(32768);(8)
OSTimeDly(32768);
loops--;
}
return(OS_NO_ERR);
}else{
return(OS_TIME_ZERO_DLY);(9)
}
}
由于OSTimeDlyHMSM()的具體實現方法,用戶不能結束延時調用OSTimeDlyHMSM()要求延時超過65535個節(jié)拍的任務。換句話說,如果時鐘節(jié)拍的頻率是100Hz,用戶不能讓調用OSTimeDlyHMSM(0,10,55,350)或更長延遲時間的任務結束延時。
5.2讓處在延時期的任務結束延時,OSTimeDlyResume()
μC/OS-Ⅱ允許用戶結束延時正處于延時期的任務。延時的任務可以不等待延時期滿,而是通過其它任務取消延時來使自己處于就緒態(tài)。這可以通過調用OSTimeDlyResume()和指定要恢復的任務的優(yōu)先級來完成。實際上,OSTimeDlyResume()也可以喚醒正在等待事件(參看第六章——任務間的通訊和同步)的任務,雖然這一點并沒有提到過。在這種情況下,等待事件發(fā)生的任務會考慮是否終止等待事件。
OSTimeDlyResume()的代碼如程序清單L5.3所示,它首先要確保指定的任務優(yōu)先級有效[L5.3(1)]。 接著, OSTimeDlyResume()要確認要結束延時的任務是確實存在的[L5.3(2)]。
如果任務存在, OSTimeDlyResume()會檢驗任務是否在等待延時期滿[L5.3(3)]。 只要OS_TCB
域中的OSTCBDly包含非0值就表明任務正在等待延時期滿,因為任務調用了OSTimeDly(),OSTimeDlyHMSM()或其它在第六章中所描述的PEND函數。然后延時就可以通過強制命令OSTCBDly為0來取消[L5.3(4)]。延時的任務有可能已被掛起了,這樣的話,任務只有在沒有被掛起的情況下才能處于就緒狀態(tài)[L5.3(5)]。當上面的條件都滿足后,任務就會被放在就緒表中[L5.3(6)]。這時,OSTimeDlyResume()會調用任務調度程序來看被恢復的任務是否擁有比當前任務更高的優(yōu)先級[L5.3(7)]。這會導致任務的切換。
程序清單 L5.3 恢復正在延時的任務
INT8UOSTimeDlyResume(INT8Uprio)
{
OS_TCB*ptcb;
if(prio>=OS_LOWEST_PRIO){(1)
return(OS_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
ptcb=(OS_TCB*)OSTCBPrioTbl[prio];
if(ptcb!=(OS_TCB*)0){(2)
if(ptcb->OSTCBDly!=0){(3)
ptcb->OSTCBDly=0;(4)
if(!(ptcb->OSTCBStatOS_STAT_SUSPEND)){(5)
OSRdyGrp|=ptcb->OSTCBBitY;(6)
OSRdyTbl[ptcb->OSTCBY]|=ptcb->OSTCBBitX;
OS_EXIT_CRITICAL();
OSSched();(7)
}else{
OS_EXIT_CRITICAL();
}
return(OS_NO_ERR);
}else{
OS_EXIT_CRITICAL();
return(OS_TIME_NOT_DLY);
}
}else{
OS_EXIT_CRITICAL();
return(OS_TASK_NOT_EXIST);
}
}
注意,用戶的任務有可能是通過暫時等待信號量、郵箱或消息隊列來延時自己的(參看第六章)??梢院唵蔚赝ㄟ^控制信號量、郵箱或消息隊列來恢復這樣的任務。這種情況存在的唯一問題是它要求用戶分配事件控制塊(參看6.00),因此用戶的應用程序會多占用一些RAM。
5.3系統時間,OSTimeGet()和 OSTimeSet()
無論時鐘節(jié)拍何時發(fā)生,μC/OS-Ⅱ都會將一個32位的計數器加1。這個計數器在用戶調用OSStart()初始化多任務和4,294,967,295個節(jié)拍執(zhí)行完一遍的時候從0開始計數。在時鐘節(jié)拍的頻率等于100Hz的時候,這個32位的計數器每隔497天就重新開始計數。用戶可以通過調用OSTimeGet()來獲得該計數器的當前值。也可以通過調用OSTimeSet()來改變該計數器的值。OSTimeGet()和OSTimeSet()兩個函數的代碼如程序清單L5.4所示。注意,
在訪問OSTime的時候中斷是關掉的。這是因為在大多數8位處理器上增加和拷貝一個32位的數都需要數條指令,這些指令一般都需要一次執(zhí)行完畢,而不能被中斷等因素打斷。
程序清單 L5.4 得到和改變系統時間
INT32UOSTimeGet(void)
{
INT32Uticks;
OS_ENTER_CRITICAL();
ticks=OSTime;
OS_EXIT_CRITICAL();
return(ticks);
}
voidOSTimeSet(INT32Uticks)
{
OS_ENTER_CRITICAL();
OSTime=ticks;
OS_EXIT_CRITICAL();
}
評論