ucosiii任務管理相關知識


  只要學習和理解:任務狀態

          任務堆棧

          任務控制塊

          任務就緒表

          任務調度和切換

  關於任務狀態:

  任務堆棧是任務的重要部分,堆棧是在RAM中按照“先進先出(FIFO)”的原則組織的一塊連續的內存空間。為了滿足任務切換和相應中斷時保存CPU寄存器中的內容及任務調用其他函數時的需要,每個任務都應該有自己的堆棧。

  1、任務堆棧的創建:

  UCOSIII中任務堆棧的創建很簡單,如原子系列教程中的例子:

  

  注意:任務堆棧的大小不是512字節,真實大小是下面那個數組所占空間的大小,其中,“CPU_STK”為CPU_INT32U類型(“unsigned int”類型),為4字節的,那么任務堆棧START_TASK_STK的大小就是:512*4=2048字節!

  上面是任務堆棧大小相關的部分,那么如何使用那個創建好的堆棧空間呢“

  2、任務堆棧的初始化:

  任務如何才能切換回上一個任務並且還能繼續從上次被中斷的地方開始運行呢?那就要恢復現場,現場就是CPU的內部各個寄存器。在剛創建一個新任務時,就必須把系統啟動這個任務時所需的CPU各個寄存器的初始值事先存放在任務堆棧中。這樣當任務獲得CPU使用權時,就把任務堆棧的內容復制到CPU的各個寄存器,從而可以讓任務順利的啟動並運行。

  2.1、任務堆棧初始化函數:

    OSTaskStkInit();

    此函數在UCOSIII源碼”os_cpu_c.c“中大概229-263行;

    函數原型:

    CPU_STK *OSTaskStkInit(OS_TASK_PTR    p_task,

                   void         *p_arg,

                   CPU_STK       *p_stk_base,

                   CPU_STK       *p_stk_Limit,

                   CPU_STK_SIZE   stk_size,

                     OS_OPT       opt)

    注意:*用戶一般不會直接操作這個函數,這個函數一般是由”OSTaskCreate()“函數調用;

       *不同CPU對寄存器的操作方式不同,因此在移植UCOSIII時需要用戶根據自己所選的CPU來編寫任務堆棧初始化函數;(這會回想一下,這對應了之前看原子視頻的UCOSII移植部分中對文件做出的各種修改的原因)

  3、之前創建出來的任務堆棧如何使用:

    創建出來的任務堆棧其實是作為任務創建函數”OSTaskCreate()“的參數直接帶入即可;

 

  4、任務堆棧棧深:

 

 

    在“OSTaskCreate()”函數中的第7個參數中,這個參數是任務堆棧棧深的設置;

    棧深就是說,任務在使用堆棧時,給他設定一個“堆棧快要用光”的限位,一般限制在堆棧大小的10%,具體先不要糾結這個參數,我想應該是系統需要根據這個數做出什么反應之類。

  5、任務控制塊:

    任務控制塊是用來記錄與任務相關的信息的數據結構,每個任務都要有自己的控制塊。任務控制塊有用戶自行創建,如下

  代碼為創建一個任務控制塊:

OS_TCB  StartTaskTcb;//創建一個任務控制塊

    OS_TCB是一個結構體,描述了任務控制塊,任務控制塊中的成員變量用戶不能直接訪問,更不可能改變他們。

    OS_TCB作為一個結構體,其中有些成員采用了條件編譯的方式來確定。

    這部分代碼在UCOSIII源碼“os.h”中大概第939-1045行,這個結構體里面的變量是非常多的;

    這個結構體中的變量的詳細講解在原子的資料“STM32 UCOS開發手冊.pdf”中第5章,“任務控制塊”中;

  5.1、任務控制塊的初始化:

    在前面“OSTaskCreate()”創建任務時,會對任務的任務控制塊進行初始化。函數“OS_TaskInitTCB()”用於初始化任務控制塊,用戶不需要自行初始化任務控制塊;

    函數“OS_TaskInitTCB()”源碼在UCOSIII源碼“os_task.c”中大概第1957-2082行;

  6、UCOSIII任務就緒表:

    6.1優先級

    UCOSIII中任務優先級數由宏“OS_CFG_PRIO_MAX”來配置,UCOSIII中數值越小,優先級越高,最低可用優先級就是“OS_CFG_PRIO_MAX-1”;

    “OS_CFG_PRIO_MAX”這個宏在UCOSIII源碼“os_cfg.h”中大概第48行;(源碼中,這個宏默認是64,用戶可自由修改,理論上可以無限大)

    6.1就緒表

    所謂就緒表,就是有個任務已經准備好了,就等着運行了,如果自己的優先級夠高,那么下一個運行的任務就是它了;

    UCOSIII就緒表中有兩部分組成:

    1、優先級位映射表:OSPrioTb1[]:用來記錄哪個優先級下有任務就緒;

      這個表在“os_prio.c”中有定義,大概41行處:

      

      

    2、就緒任務列表:OSRdyList[]:用來記錄每一個優先級下所有就緒的任務;

    3、下表好好理解理解:

 

    6.3 系統如何找到已經就緒了的最高優先級的任務?

      函數 "OS_PrioGetHighest()"用於找到就緒了的最高優先級的任務;

      源碼在“os_prio.c”大概第85行處;

      這個函數的作用就是找出最高優先級的任務,找最高優先級時是硬件執行的,速度很快,基本原理如下:

 

    函數會一直循環的找“1”,OSPrioTbl[0]里面如果每個位都為0,那就繼續往OSPrioTbl[1]中找,直到碰到“1”,就算是找出來了當前已經就緒了的最高優先級的任務,但是此時還不能找到具體哪個任務,因為一個優先級下面有多個任務;

    6.4就緒任務列表

      剛才上邊說了,找到最高優先級后,還不能確定具體是哪個任務,這時就用到就緒任務列表“OSRdyList[]”(上邊提到過)了;

      在這個列表中,系統會找出最先需要執行的任務,具體要執行哪一個,是按照這個里面的一個鏈表執行的,最先執行的是鏈表頭那個任務,執行完后就插到尾去了,具體細節先不要過分研究;

  7、任務調度和切換

    7.1

    任務調度就是中止當前正在運行的任務轉而去執行其他任務。

    UCOSIII是可剝奪型內核,因此當一個高優先級的任務准備就緒,並且此時發生了任務調度,那么這個高優先級的任務就會獲得CPU的使用權!

    UCOSIII中的任務調度是由任務調度器來完成的,任務調度器有2中:任務級調度器中斷級調度器

    任務級調度器,是個函數:“OSSched()”;,此函數是在普通任務中使用;

    中斷級調度器,是個函數:“OSIntExit()”,當在退出外部中斷服務函數的時候會使用中斷級任務調度,這個函數一般寫在中斷服務函數里面;

    任務調度器使用方法,在原子視頻第8講,UCOSIII任務管理(下)中的第6分左右,有使用方法的說明,就是上邊兩個函數只要調用一次,系統就會發生一次任務切換;

    7.2 任務調度點:

    任務調度點就是發生任務調度的時間點或者說節點,就是在哪個地方發生的任務調度;(用戶可以自己調用一下調度函數來發生任務調度)

    那么,都有哪些任務調度點呢:

 

    7.3 調度器的上鎖和解鎖

    有時候我們不希望發生任務調度,因為有些時候是不能被打斷的,比如正在初始化某個外設的時候,這時就需要對調度器上鎖,上鎖函數:“OSSchedLock()”;當想要恢復調度器的時候,就需要解鎖,解鎖函數:“OSSchedUnlock()”;

    7.4 時間片輪轉調度


  因為有多任務,每個任務執行指定的時間片,然后輪到下一個任務執行,這個過程就是時間片輪轉調度。時間片輪轉調度器:“OS_SchedRoundRobin()”;

  注意:任務可以放棄自己的時間片,比如一個任務本來要執行4個時間片,執行3個時間片后,出於某種原因,不想繼續執行,此時它是可以放棄剩余1個時間片的;

    7.5 任務切換

 

上邊兩個函數在匯編文件“os_cpu_a.asm”中

 

 

注:任務切換是包含在任務調度中的;

  8、UCOSIII系統初始化:

    在使用UCOSIII之前我們必須先初始化UCOSIII,函數“OSIniy()”用來完成UCOSIII的初始化,而且OSInit()必須先於其它UCOSIII函數調用,包括OSStart()。

  9、UCOSIII系統啟動:

    使用函數"OSStart()"來啟動UCOSIII;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM