μC/OS-II的時間管理
在 3.10節(jié)時鐘節(jié)拍中曾提到,μC/OS-Ⅱ(其它內(nèi)核也一樣)要求用戶提供定時中斷來實現(xiàn)延時與超時控制等功能。這個定時中斷叫做時鐘節(jié)拍,它應該每秒發(fā)生10至100次。時鐘節(jié)拍的實際頻率是由用戶的應用程序決定的。時鐘節(jié)拍的頻率越高,系統(tǒng)的負荷就越重。
本文引用地址:http://2s4d.com/article/201610/305742.htm3.10 節(jié)討論了時鐘的中斷服務子程序和節(jié)時鐘節(jié)函數(shù) OSTimeTIck——該函數(shù)用于通知μC/OS-Ⅱ發(fā)生了時鐘節(jié)拍中斷。本章主要講述五個與時鐘節(jié)拍有關的系統(tǒng)服務:
z OSTimeDly()
z OSTimeDlyHMSM()
z OSTimeDlyResume()
z OSTimeGet()
z OSTimeSet()
本章所提到的函數(shù)可以在OS_TIME.C文件中找到。
5.0任務延時函數(shù),OSTimeDly()
μC/OS-Ⅱ提供了這樣一個系統(tǒng)服務:申請該服務的任務可以延時一段時間,這段時間的長短是用時鐘節(jié)拍的數(shù)目來確定的。實現(xiàn)這個系統(tǒng)服務的函數(shù)叫做OSTimeDly()。調(diào)用該函數(shù)會使μC/OS-Ⅱ進行一次任務調(diào)度,并且執(zhí)行下一個優(yōu)先級最高的就緒態(tài)任務。任務調(diào)用OSTimeDly()后,一旦規(guī)定的時間期滿或者有其它的任務通過調(diào)用OSTimeDlyResume()取消了延時,它就會馬上進入就緒狀態(tài)。注意,只有當該任務在所有就緒任務中具有最高的優(yōu)先級時,它才會立即運行。
程序清單L5.1所示的是任務延時函數(shù)OSTimeDly()的代碼。用戶的應用程序是通過提供延時的時鐘節(jié)拍數(shù)——一個1到65535之間的數(shù),來調(diào)用該函數(shù)的。如果用戶指定0值[L5.1(1)],則表明用戶不想延時任務,函數(shù)會立即返回到調(diào)用者。非0值會使得任務延時函數(shù)OSTimeDly()將當前任務從就緒表中移除[L5.1(2)]。接著,這個延時節(jié)拍數(shù)會被保存在當前任務的OS_TCB中[L5.1(3)],并且通過OSTimeTick()每隔一個時鐘節(jié)拍就減少一個延時節(jié)拍數(shù)。最后,既然任務已經(jīng)不再處于就緒狀態(tài),任務調(diào)度程序會執(zhí)行下一個優(yōu)先級最高的就緒任務。
程序清單 L5.1 OSTimeDly().
voidOSTimeDly(INT16Uticks)
{
if(ticks>0){(1)
OS_ENTER_CRITICAL();
if((OSRdyTbl[OSTCBCur->OSTCBY]=~OSTCBCur->OSTCBBitX)==0)
{(2)
OSRdyGrp=~OSTCBCur->OSTCBBitY;
}
OSTCBCur->OSTCBDly=ticks;(3)
OS_EXIT_CRITICAL();
OSSched();(4)
}
}
清楚地認識0到一個節(jié)拍之間的延時過程是非常重要的。換句話說,如果用戶只想延時一個時鐘節(jié)拍,而實際上是在0到一個節(jié)拍之間結束延時。即使用戶的處理器的負荷不是很重,這種情況依然是存在的。圖F5.1詳細說明了整個過程。系統(tǒng)每隔10ms發(fā)生一次時鐘節(jié)拍中斷[F5.1(1)]。假如用戶沒有執(zhí)行其它的中斷并且此時的中斷是開著的,時鐘節(jié)拍中斷服務就會發(fā)生[F5.1(2)]。也許用戶有好幾個高優(yōu)先級的任務(HPT)在等待延時期滿,它們會接著執(zhí)行[F5.1(3)]。接下來,圖5.1中所示的低優(yōu)先級任務(LPT)會得到執(zhí)行的機會,該任務在執(zhí)行完后馬上調(diào)用[F5.1(4)]所示的 OSTimeDly(1)。 μC/OS-Ⅱ會使該任務處于休眠狀態(tài)直至下一個節(jié)拍的到來。當下一個節(jié)拍到來后,時鐘節(jié)拍中斷服務子程序會執(zhí)行[F5.1(5)],但是這一次由于沒有高優(yōu)先級的任務被執(zhí)行,μC/OS-Ⅱ會立即執(zhí)行申請延時一個時鐘節(jié)拍的任務[F5.1(6)]。正如用戶所看到的,該任務實際的延時少于一個節(jié)拍!在負荷很重的系統(tǒng)中,任務甚至有可能會在時鐘中斷即將發(fā)生時調(diào)用OSTimeDly(1),在這種情況下,任務幾乎就沒有得到任何延時,因為任務馬上又被重新調(diào)度了。如果用戶的應用程序至少得延時一個節(jié)拍,必須要調(diào)用OSTimeDly(2),指定延時兩個節(jié)拍!
Figure5.1DelayresolutiON.

5.1按時分秒延時函數(shù) OSTimeDlyHMSM()
OSTimeDly()雖然是一個非常有用的函數(shù),但用戶的應用程序需要知道延時時間對應的時鐘節(jié)拍的數(shù)目。用戶可以使用定義全局常數(shù)OS_TICKS_PER_SEC(參看OS_CFG.H)的方法將時間轉換成時鐘段,但這種方法有時顯得比較愚笨。筆者增加了OSTimeDlyHMSM()函數(shù)后,用戶就可以按小時(H)、分(M)、秒(S)和毫秒(m)來定義時間了,這樣會顯得更自然些。與OSTimeDly()一樣,調(diào)用OSTimeDlyHMSM()函數(shù)也會使μC/OS-Ⅱ進行一次任務調(diào)度,并且執(zhí)行下一個優(yōu)先級最高的就緒態(tài)任務。任務調(diào)用OSTimeDlyHMSM()后,一旦規(guī)定的時間期滿或者有其它的任務通過調(diào)用OSTimeDlyResume()取消了延時(參看5.02,恢復延時的任務OSTimeDlyResume()),它就會馬上處于就緒態(tài)。同樣,只有當該任務在所有就緒態(tài)任務中具有最高的優(yōu)先級時,它才會立即運行。
程序清單L5.2所示的是OSTimeDlyHMSM()的代碼。從中可以看出,應用程序是通過用小時、分、秒和毫秒指定延時來調(diào)用該函數(shù)的。在實際應用中,用戶應避免使任務延時過長的時間, 因為從任務中獲得一些反饋行為(如減少計數(shù)器, 清除LED等等)經(jīng)常是很不錯的事。
但是,如果用戶確實需要延時長時間的話,μC/OS-Ⅱ可以將任務延時長達256個小時(接近11天)。
OSTimeDlyHMSM()一開始先要檢驗用戶是否為參數(shù)定義了有效的值[L5.2(1)]。與OSTimeDly()一樣,即使用戶沒有定義延時,OSTimeDlyHMSM()也是存在的[L5.2(9)]。因為μC/OS-Ⅱ只知道節(jié)拍,所以節(jié)拍總數(shù)是從指定的時間中計算出來的[L5.2(3)]。很明顯,程序清單L5.2中的程序并不是十分有效的。筆者只是用這種方法告訴大家一個公式,這樣用戶就可以知道怎樣計算總的節(jié)拍數(shù)了。真正有意義的只是OS_TICKS_PER_SEC。[L5.2(3)]決定了最接近需要延遲的時間的時鐘節(jié)拍總數(shù)。500/OS_TICKS_PER_SECOND的值基本上與0.5個節(jié)拍對應的毫秒數(shù)相同。例如,若將時鐘頻率(OS_TICKS_PER_SEC)設置成100Hz(10ms),4ms的延時不會產(chǎn)生任何延時!而5ms的延時就等于延時10ms。
μC/OS-Ⅱ支持的延時最長為65,535個節(jié)拍。要想支持更長時間的延時,如L5.2(2)所示,OSTimeDlyHMSM()確定了用戶想延時多少次超過65,535個節(jié)拍的數(shù)目[L5.2(4)]和剩下的節(jié)拍數(shù)[L5.2(5)]。例如,若OS_TICKS_PER_SEC的值為100,用戶想延時15分鐘,則OSTimeDlyHMSM()會延時15x60x100=90,000個時鐘。這個延時會被分割成兩次32,768個節(jié)拍的延時(因為用戶只能延時65,535個節(jié)拍而不是65536個節(jié)拍)和一次24,464個節(jié)拍的延時。在這種情況下,OSTimeDlyHMSM()首先考慮剩下的節(jié)拍,然后是超過65,535的節(jié)拍數(shù)[L5.2(7)和(8)](即兩個32,768個節(jié)拍延時)。
評論