嵌入式實時作業系統ucos/ii 原理與應用(二)
第二章 Uc/OS-II中的任務
3.1任務的基本概念
3.1.1
從程式碼上看:Uc/OS-II中的任務就是一個函式
從任務的儲存結構上看:任務分成三個組成:
任務程式程式碼(函式)
任務堆疊 (儲存任務的工作環境)
任務控制塊 (關聯任務程式碼的程式控制塊,記錄各個任務的屬性)
任務組成(Uc/OS-II中的任務都沒有定義私有空間,屬於執行緒)
任務管理:任務控制塊連結串列
任務分類:使用者任務 由應用程式設計者編寫,解決應用程式問題
系統任務由系統提供,為應用程式提供某種服務或為系統本身服務
3.1.2
任務狀態:睡眠狀態就緒狀態 執行狀態 等待狀態 中斷服務狀態
3.1.3
使用者任務程式碼的一般結構—— 超迴圈結構
使用者應用程式的一般結構—— 在main函式中初始化與建立任務,由作業系統進行管理和排程
3.1.4系統任務 (系統自己需要的任務)
空閒任務:系統無使用者任務可執行而處於空閒狀態,執行空閒任務
統計任務:計算CPU被使用的時間,以百分比的形式存放於變數中
3.1.5任務的優先權及優先級別
任務的優先級別最多有64級,每個級別用一個整數數字表示。
數字越小,優先級別越高。
顯示定義每個任務唯一的優先級別,呼叫系統函式OSTaskCreate()建立
3.2任務堆疊
3.2.1任務堆疊的建立 ——OSTaskCreate
例#define MyTaskStkN 64
OS_STK MyTaskStk[MyTaskStkN ];
void main(void)
{
…….
#if OS_STK_GROWTH == 1 //堆疊向下增長
OSTaskCreate(
MyTask, //任務的指標
& MyTaskAgu, //傳遞給任務的引數
& MyTaskStk[MyTaskStkN - 1], //任務堆疊棧頂的地址
20 //任務的優先級別
);
#else //堆疊向上增長
OSTaskCreate(
MyTask, //任務的指標
& MyTaskAgu, //傳遞給任務的引數
& MyTaskStk[0], //任務堆疊棧頂的地址
20 //任務的優先級別
);
#endif
}
3.2.2任務堆疊的初始化——OSTaskStkInit
初始化:將任務初始化資料(任務指標,任務堆疊指標及程式狀態字)存放到任務堆疊
3.3任務控制塊及任務控制塊連結串列
3.3.1 任務控制塊結構
3.3.2任務控制塊連結串列
空任務控制塊連結串列(所有任務控制塊未分配任務)
包含元素共使用者任務最大數目+系統任務數目(2)個
任務塊連結串列(任務控制塊已分配任務)
雙向連結串列 ----à加快對任務控制塊的訪問速度
定義一個數據型別為OS_TCB*的陣列OSPrioTbl[]
3.3.3任務控制塊的初始化——OSTaskInit
函式主要任務:
為被建立任務從空任務控制塊連結串列獲取一個任務控制塊
用任務的屬性對任務控制塊各個成員
3.4任務就緒表及任務排程
多工作業系統的核心工作是任務排程(通過一個演算法確定哪個任務來執行)
3.4.1任務就緒表的結構
任務就緒表 ——OSRdyTbl[]
變數OSRdyGrp的每一個位對應OSRdyTbl[]的一個任務組(即陣列的一個元素)
如果某任務組中有任務就緒,則在變數OSRdyGrp裡把該任務組所對應的位置置1
優先級別——一個6位二進位制數
高3位(D5D4D3)—— 指明變數OSRdyGrp的具體資料位,並用來確定就緒表陣列元素的下標
低3位(D2D1D0)—— 該陣列元素的具體資料位
3.4.2對任務就緒表的操作
1.登記 (將優先級別為prio的任務置為就緒狀態)
OSRdyGrp |= OSMapTbl[prio >> 3];
OSRdyTbl[prio >> 3] |= OSMapTbl[prio& 0x07];
2.登出 (將優先級別為prio的任務脫離就緒狀態)
If((OSRdyTbl[prio >> 3] &= -OSMapTbl[prio & 0x07]) == 0)
{
OSRdyGrp&= - OSMapTbl[prio >> 3]
}
3.最高級別的就緒任務獲取
y = OSUnMapTal[OSRdyGrp]; //獲取優先級別的D5D4D3位
x = OSUnMapTal[OSRdyTbl[y]]; //獲取優先級別的D2D1D0位
prio = (y << 3) + x; //獲取就緒任務的優先級別
3.4.3任務的排程 ——按某種規則進行任務切換
1.任務排程器工作:1.在任務就緒表中查詢具有最高優先級別的就緒任務
2.實現任務的切換
任務級排程器——OSSched()
中斷級排程器——OSIntExt()
2.獲得待執行就緒任務控制塊的指標
void OSSched(void)
{
#ifOS_CRITICAL_METSOD == 3 //確認未被上鎖 且 不是中斷服務程式呼叫
OS_CPU_SR cpu_sr; 排程器
#endif
INT8U y;
OS_ENTER_ CRITICAL();
If((OSLockNesting |OSIntNesting) == 0)
{
y = OSUnMapTbl[OSRdyGrp];
//得到最高階優先任務
OSPrioHighRdy = (INT8U)((y << 3) + UnMapTbl[OSRdyTbl[y]]);
if(OSPrioHighRdy != OSPrioCur)
{
//統計人切換次數的計數器加1
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++;
OS_TASK_SW();
}
}
OS_EXIT_CRITICAL();
}
確認未被上鎖且不是中斷服務程式呼叫排程器——>從任務就緒表中查得的最高優先級別就緒任務的優先級別OSTCBHighRdy——>確認是否是正在執行的任務——>用OSPrioHighRd做下標去訪問陣列OSTCBPrioTbl[],將陣列元素OSTCBPrioTbl[OSPrioHighRdy]的值賦給指標變數OSTCBHighRdy——>依據指向待執行任務控制塊和當前任務控制塊的指標在巨集OS_TASK_SW中實施任務切換
3.任務切換巨集OS_TASK_SW
任務切換:中止正在執行的任務,轉而去執行另外一個任務
在任務被中止時把任務的斷點資料儲存到堆疊中,重新執行時把堆疊中的斷點資料再恢復到CPU的各暫存器中——> 無縫接續執行
CPU的堆疊指標SP指向正確——> 正確回覆斷點資料——>任務在斷點處恢復執行
排程器任務切換操作:
1. 被終止任務的斷點指標儲存到任務堆疊
2. CPU通用暫存器內容儲存到任務堆疊
3. 被終止任務的任務堆疊指標當前值儲存到該任務控制塊的OSTCBStkPtr
4. 獲得待執行的任務控制塊
5. 使CPU通過任務控制塊獲得待執行任務的任務堆疊指標
6. 把待執行任務的任務堆疊中的通用暫存器內容恢復到CPU通用暫存器
7. 使CPU獲得待執行任務的斷點指標
流程圖如下:
巨集封裝一個軟中斷指令——> 引發中斷——>跳轉到中斷服務程式,把斷點指標存入堆疊
3.5任務的建立
建立任務==建立一個任務控制塊
3.5.1用函式OSTaskCreaate()建立任務
判斷建立任務的優先級別——>確認優先級別合法且未被使用——>初始化任務堆疊和任務控制塊——>任務計數器加1——>判斷Uc/OS-II是否在執行——>在執行,則進行任務排程——>建立任務成功,返回OS_NO_ERR;失敗,返回其他
3.5.2用函式OSTaskCreaateExt()建立任務——更靈活,增加額外的開銷
3.5.3建立任務的一般方法
Uc/OS-II初始化——> 建立起始任務——>在起始任務中,初始化統計任務,建立其他任務——> 開始多工排程
不允許在中斷服務程式中建立任務
3.6任務的掛起與恢復
掛起——> 停止這個任務的執行
3.6.1掛起任務
待掛起的任務呼叫函式的任務本身——>刪除任務就緒表中的就緒標誌——>掛起記錄——>引發任務排程
待掛起的任務不呼叫函式的任務本身——>刪除任務就緒表中的就緒標誌——>掛起記錄
3.6.2恢復任務
判斷任務確實是已存在的掛起任務,且不是等待任務——>清除掛起任務——>任務排程——>返回成功
3.7其他任務管理函式
3.7.1任務優先級別的修改——>OSTaskChangPrio()
3.7.2任務的刪除——> OSTaskDel()
刪除 = 將任務置於睡眠,把被刪除任務的任務控制塊從任務控制塊連結串列中刪除,並歸還給空任務控制塊連結串列
提出刪除任務請求的任務只負責提出刪除任務請求,刪除工作由被刪除任務自己完成——>OSTaskDelReq()
提出刪除任務請求的任務呼叫函式時,函式引數是被刪除任務的優先級別
被刪除任務呼叫函式時,函式引數是OS_PRIO_SELF
提出刪除任務請求的任務呼叫OSTaskDelReq():
被刪除任務呼叫OSTaskDelReq():
3.7.3查詢任務的資訊——>OSTaskQuery()
3.8 UC/OS-II的初始化和任務的啟動
3.8.1UC/OS-II的初始化——>OSInit()
初始化所有全域性變數和資料結構(建立包括空任務塊控制連結串列在內的5個空資料緩衝區及建立一個數組),建立空閒任務,賦以最低的優先級別和永遠的就緒狀態。若需用統計任務,賦統計任務優先級別為OS_LOWEST_PRIO – 1
3.8.2 UC/OS-II的啟動——>OSStart()