第二章  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()