UCOSii(三)——時(shí)間管理
一、時(shí)間管理
1.1 時(shí)鐘節(jié)拍
UCOSii通過時(shí)鐘節(jié)拍OSTimeTick()來(lái)定期進(jìn)行任務(wù)調(diào)度,一般來(lái)說(shuō)這個(gè)頻率是10-100HZ,頻率越高,系統(tǒng)的開銷也就越大。
1.2 任務(wù)延時(shí)函數(shù)
OSTimeDly()
任務(wù)可以調(diào)用OSTimeDly()來(lái)對(duì)自身延時(shí)一段時(shí)間。延時(shí)時(shí),任務(wù)被掛起。任務(wù)被延時(shí)的時(shí)間必須是時(shí)鐘節(jié)拍的倍數(shù)。與延時(shí)有關(guān)的變量在上一片文章里提到的Tcb結(jié)構(gòu)體中。
Tcb.OSTCBDly表示任務(wù)自己延時(shí)掛起的時(shí)間。
這樣,當(dāng)任務(wù)調(diào)用OSTimeDly()來(lái)進(jìn)行延時(shí)時(shí),該函數(shù)會(huì)修改修改OSTCBDly的值,把要延時(shí)的次數(shù)寫入該變量,最后進(jìn)行任務(wù)調(diào)度即可。
每次時(shí)鐘節(jié)拍發(fā)生的時(shí)候,OSTCBDly的值都會(huì)被減去一,當(dāng)該值為0的時(shí)候,內(nèi)核就會(huì)把它放入就緒隊(duì)列。
NOTE: 當(dāng)調(diào)用OSTimeDly(1)只延時(shí)一個(gè)時(shí)鐘節(jié)拍的時(shí)候,由于任務(wù)可能運(yùn)行在一個(gè)時(shí)鐘節(jié)拍的中后期,此時(shí)經(jīng)過不到半個(gè)時(shí)鐘節(jié)拍的時(shí)間,OSTCBDly的值就會(huì)被修改。因此,如果用戶的應(yīng)用程序至少得延時(shí)一個(gè)節(jié)拍,必須要調(diào)用 OSTimeDly(2),指定延時(shí)兩個(gè)節(jié)拍。
來(lái)看一下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í)次數(shù)傳遞給了OSTCBDly,并將該任務(wù)從就緒列表里刪除。
OSTimeDlyHMSM()
OSTimeDly()還有一些缺點(diǎn),一是只能延時(shí)65535次時(shí)鐘節(jié)拍,二是不能換算成時(shí)間。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ù)檢測(cè),然后做換算計(jì)算延時(shí)次數(shù),如果超過65535次就做循環(huán)延時(shí)。
1.3 結(jié)束任務(wù)延時(shí)函數(shù)
OSTimeDlyResume()函數(shù)可以被用來(lái)強(qiáng)制某一任務(wù)結(jié)束延時(shí),它的主要作用是支持任務(wù)之間的通訊和同步。
OSTimeDlyResume()要做的就是將OSTCBDly清0,然后進(jìn)行任務(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ù)是否因?yàn)槠渌录粧炱?。如果沒有,那么就將任務(wù)放入就緒列表。
1.4 系統(tǒng)時(shí)間
每次發(fā)生時(shí)鐘節(jié)拍時(shí),UCOS都會(huì)將一個(gè)32位的計(jì)數(shù)器加1。
OSTimeGet()和 OSTimeSet()用來(lái)獲取或者設(shè)置這個(gè)計(jì)數(shù)器的值。