μC/OS-II的內核結構
盡的解釋。
OSSched()的所有代碼都屬臨界段代碼。在尋找進入就緒態的優先級最高的任務過程
中,為防止中斷服務子程序把一個或幾個任務的就緒位置位,中斷是被關掉的。為縮短切
換時間,OSSched()全部代碼都可以用匯編語言寫。為增加可讀性,可移植性和將匯編語言
代碼最少化,OSSched()是用C寫的。
3.6 給調度器上鎖和開鎖(LockingandUnLockingtheScheduler)
給調度器上鎖函數OSSchedlock()(程序清單L3.9)用于禁止任務調度,直到任務完
成后調用給調度器開鎖函數OSSchedUnlock()為止,(程序清單L3.10)。調用
OSSchedlock()的任務保持對CPU的控制權,盡管有個優先級更高的任務進入了就緒態。然
而,此時中斷是可以被識別的,中斷服務也能得到(假設中斷是開著的)。OSSchedlock()
和OSSchedUnlock()必須成對使用。變量OSLockNesting跟蹤OSSchedLock()函數被調用的
次數,以允許嵌套的函數包含臨界段代碼,這段代碼其它任務不得干預。μC/OS-Ⅱ允許嵌
套深度達255層。當OSLockNesting等于零時,調度重新得到允許。函數OSSchedLock()和
OSSchedUnlock()的使用要非常謹慎,因為它們影響μC/OS-Ⅱ對任務的正常管理。
當OSLockNesting減到零的時候,OSSchedUnlock()調用OSSched[L3.10(2)]。
OSSchedUnlock()是被某任務調用的,在調度器上鎖的期間,可能有什么事件發生了并使一
個更高優先級的任務進入就緒態。
調用OSSchedLock()以后,用戶的應用程序不得使用任何能將現行任務掛起的系統調用。也就是說,用戶程序不得調用OSMboxPend()、OSQPend()、OSSemPend()、OSTaskSuspend
(OS_PR1O_SELF)、OSTimeDly()或OSTimeDlyHMSM(),直到OSLockNesting回零為止。因為調度器上了鎖,用戶就鎖住了系統,任何其它任務都不能運行。
當低優先級的任務要發消息給多任務的郵箱、消息隊列、信號量時(見第6章任務間通訊和同步),用戶不希望高優先級的任務在郵箱、隊列和信號量沒有得到消息之前就取得了CPU的控制權,此時,用戶可以使用禁止調度器函數。
程序清單 L3.9 給調度器上鎖
voidOSSchedLock(void)
{
if(OSRunning==TRUE){
OS_ENTER_CRITICAL();
OSLockNesting++;
OS_EXIT_CRITICAL();
}
}
程序清單L3.10給調度器開鎖.
voidOSSchedUnlock(void)
{
if(OSRunning==TRUE){
OS_ENTER_CRITICAL();
if(OSLockNesting>0){
OSLockNesting--;
if((OSLockNesting|OSIntNesting)==0){(1)
OS_EXIT_CRITICAL();
OSSched();(2)
}else{
OS_EXIT_CRITICAL();
}
}else{
OS_EXIT_CRITICAL();
}
}
}
3.7 空閑任務(IdleTask)
μC/OS-Ⅱ總是建立一個空閑任務,這個任務在沒有其它任務進入就緒態時投入運行。這個空閑任務[OSTaskIdle()]永遠設為最低優先級,即OS_LOWEST_PRI0。空閑任務OSTaskIdle()什么也不做,只是在不停地給一個32位的名叫OSIdleCtr的計數器加1,統計任務(見3.08節,統計任務)使用這個計數器以確定現行應用軟件實際消耗的CPU時間。程序清單L3.11是空閑任務的代碼。在計數器加1前后,中斷是先關掉再開啟的,因為8位以及大多數16位微處理器的32位加1需要多條指令,要防止高優先級的任務或中斷服務子程序從中打入。空閑任務不可能被應用軟件刪除。
程序清單L3.11μC/OS-Ⅱ的空閑任務.
voidOSTaskIdle(void*pdata)
{
pdata=pdata;
for(;;){
OS_ENTER_CRITICAL();
OSIdleCtr++;
OS_EXIT_CRITICAL();
}
}
3.8 統計任務
μC/OS-Ⅱ有一個提供運行時間統計的任務。這個任務叫做OSTaskStat(),如果用戶將系統定義常數OS_TASK_STAT_EN(見文件OS_CFG.H)設為1,這個任務就會建立。一旦得到了允許,OSTaskStat()每秒鐘運行一次(見文件OS_CORE.C),計算當前的CPU利用率。換句話說,OSTaskStat()告訴用戶應用程序使用了多少CPU時間,用百分比表示,這個值放在一個有符號8位整數OSCPUsage中,精讀度是1個百分點。
如果用戶應用程序打算使用統計任務,用戶必須在初始化時建立一個唯一的任務,在這個任務中調用OSStatInit()(見文件OS_CORE.C)。換句話說,在調用系統啟動函數OSStart()之前,用戶初始代碼必須先建立一個任務,在這個任務中調用系統統計初始化函數OSStatInit(),然后再建立應用程序中的其它任務。程序清單L3.12是統計任務的示意性代碼。
程序清單L3.12初始化統計任務.
voidmain(void)
{
OSInit();/* 初始化uC/OS-II(1)*/
/* 安裝uC/OS-II的任務切換向量 */
/* 創建用戶起始任務(為了方便討論,這里以TaskStart()作為起始任務)(2)*/
OSStart();/* 開始多任務調度 (3)*/
}
voidTaskStart(void*pdata)
{
/* 安裝并啟動uC/OS-II的時鐘節拍 (4)*/
OSStatInit();/* 初始化統計任務 (5)*/
/* 創建用戶應用程序任務 */
for(;;){
/* 這里是TaskStart()的代碼!*/
}
}
因為用戶的應用程序必須先建立一個起始任務[TaskStart()],當主程序main()調用系統啟動函數OSStcnt()的時候,μC/OS-Ⅱ只有3個要管理的任務:TaskStart()、OSTaskIdle()和OSTaskStat()。請注意,任務TaskStart()的名稱是無所謂的,叫什么名字都可以。因為μC/OS-Ⅱ已經將空閑任務的優先級設為最低,即OS_LOWEST_PR10,統計任務的優先級設為次低,OS_LOWEST_PR10-1。啟動任務TaskStart()總是優先級最高的任務。
圖F3.4解釋初始化統計任務時的流程。用戶必須首先調用的是μC/OS-Ⅱ中的系統初始化函數OSInit(),該函數初始化μC/OS-Ⅱ[圖F3.4(2)]。有的處理器(例如Motorola的MC68HC11),不需要“設置”中斷向量,中斷向量已經在ROM中有了。用戶必須調用OSTaskCreat()或者OSTaskCreatExt()以建立TaskStart()[圖F3.4(3)]。進入多任務的條件準備好了以后,調用系統啟動函數OSStart()。這個函數將使 TaskStart()開始執行,因為TaskStart()是優先級最高的任務[圖F3.4(4)]]。
評論