一、時間管理
1.1 時鐘節(jié)拍
UCOSii通過時鐘節(jié)拍OSTimeTick()來定期進行任務(wù)調(diào)度,一般來說這個頻率是10-100HZ,頻率越高,系統(tǒng)的開銷也就越大。
1.2 任務(wù)延時函數(shù)
OSTimeDly()
任務(wù)可以調(diào)用OSTimeDly()來對自身延時一段時間。延時時,任務(wù)被掛起。任務(wù)被延時的時間必須是時鐘節(jié)拍的倍數(shù)。與延時有關(guān)的變量在上一片文章里提到的Tcb結(jié)構(gòu)體中。
Tcb.OSTCBDly表示任務(wù)自己延時掛起的時間。
這樣,當(dāng)任務(wù)調(diào)用OSTimeDly()來進行延時時,該函數(shù)會修改修改OSTCBDly的值,把要延時的次數(shù)寫入該變量,最后進行任務(wù)調(diào)度即可。
每次時鐘節(jié)拍發(fā)生的時候,OSTCBDly的值都會被減去一,當(dāng)該值為0的時候,內(nèi)核就會把它放入就緒隊列。
NOTE: 當(dāng)調(diào)用OSTimeDly(1)只延時一個時鐘節(jié)拍的時候,由于任務(wù)可能運行在一個時鐘節(jié)拍的中后期,此時經(jīng)過不到半個時鐘節(jié)拍的時間,OSTCBDly的值就會被修改。因此,如果用戶的應(yīng)用程序至少得延時一個節(jié)拍,必須要調(diào)用 OSTimeDly(2),指定延時兩個節(jié)拍。
來看一下OSTimeDly()的原型:
void OSTimeDly (INT16U ticks)
{
if (ticks > 0) {
OS_ENTER_CRITICAL();
if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {
OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
}
OSTCBCur->OSTCBDly = ticks;
OS_EXIT_CRITICAL();
OSSched();
}
}
可以看到該函數(shù)將延時次數(shù)傳遞給了OSTCBDly,并將該任務(wù)從就緒列表里刪除。
OSTimeDlyHMSM()
OSTimeDly()還有一些缺點,一是只能延時65535次時鐘節(jié)拍,二是不能換算成時間。OSTimeDlyHMSM()就是為了解決這些問題而存在的,直接看原型吧。
INT8U OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U
milli)
{
INT32U ticks;
INT16U loops;
if (hours > 0 || minutes > 0 || seconds > 0 || milli > 0) {
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
+ (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;
loops = ticks / 65536L;
ticks = ticks % 65536L;
OSTimeDly(ticks);
while (loops > 0) {
OSTimeDly(32768);
OSTimeDly(32768);
loops--;
}
return (OS_NO_ERR);
} else {
return (OS_TIME_ZERO_DLY);
}
}
首先做非法參數(shù)檢測,然后做換算計算延時次數(shù),如果超過65535次就做循環(huán)延時。
1.3 結(jié)束任務(wù)延時函數(shù)
OSTimeDlyResume()函數(shù)可以被用來強制某一任務(wù)結(jié)束延時,它的主要作用是支持任務(wù)之間的通訊和同步。
OSTimeDlyResume()要做的就是將OSTCBDly清0,然后進行任務(wù)調(diào)度。
原型:
INT8U OSTimeDlyResume (INT8U prio)
{
OS_TCB *ptcb;
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)) {
OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
OS_EXIT_CRITICAL();
OSSched();
} 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);
}
}
它在將OSTCBDly清0之后,還判斷了任務(wù)是否因為其他事件而被掛起。如果沒有,那么就將任務(wù)放入就緒列表。
1.4 系統(tǒng)時間
每次發(fā)生時鐘節(jié)拍時,UCOS都會將一個32位的計數(shù)器加1。
OSTimeGet()和 OSTimeSet()用來獲取或者設(shè)置這個計數(shù)器的值。