注:紅體字都是自己對這個概念的理解,有什麼不對的歡迎拍磚哈,呵呵
一、uC/OSii 內核結構:任務管理,時間管理,中斷處理,任務之間的通信與同步!
二、代碼的臨界區分析:
代碼的臨界區也稱為臨界區,指該代碼在被處理時不能被分割,因此不能被中斷打入!所以在進入該代碼(臨界區)時應該關中斷,而執行完後再打開中斷!而uC/OSii 用OS_ENTER_CRITICAL和OS_EXIT_CRITICAL這兩個宏來開/關中斷。而針對不同的處理器,這兩個宏定義是不同的,分為三種,由OS_CRITICAL_METHOD的值來區分。一般ARM的OS_CRITICAL_METHOD=3(第三種宏定義)
三、uC/Osii的TASK(任務)
uC/Osii的任何工作都是由任務來完成的。
任務是一種無限循環的結構,每一個任務對應著一個任務級,uC/Osii有64個任務優先級,每一個優先級不能重復存在,也就是每一個優先級對應一個任務。因此可以把優先級看成一個任務的標志,事實上uC/Osii的確是這樣做的。
TASK最主要的部分就是任務控制快(TCB), uC/Osii控制任務其實本質就是對任務的TCB進行控制
TCB是一種數據結構,那什麼是數據結構?就是一些信息的集合體。TCB裡面包含了哪些信息呢?以下進行分析:
(1)OSTCBStkPtr,它是指向該任務堆棧棧頂的指針,也就是指向堆棧起始地址。
(2)OSTCBStkBottom,是指向該任務堆棧棧底的指針,這個主要是檢測堆棧剩余空間用的。
(3)OSTCBStkSize,堆棧容量。
(4)OSTCBOpt,沒有搞清楚 ,只知道是OSTaskCreateExt(),才有用。
(5)OSTCBNext和OSTCBPrev,用語任務控制塊OS_TCB雙向鏈表的前後任務塊連接,在調用OSTimeTick()時會使用這個前後連接的雙向鏈表,來刷新各個任務的任務延遲變量OSTCBDly(馬上對它說明)。每一個任務TCB建立時,會連接到該連表中,在刪除任務時也會從中刪除。(除了睡眠狀態,任務的控制塊始終連接在這個鏈表)
(6)OSTCBDly,當需要把某任務延遲若干時鐘接拍時,或者因為等待某個事件發生而掛起任務時,都需要這個變量。其實任務時延函數OSTimeDly()的作用就是 將任務從就緒列表移除(移除方法後面會講)並且對這個變量賦值(要延遲的節拍數)。OSTimeTick()會每隔一個節拍就通過OS_TCB雙向列表(第5條講過的)對每一個TCB的OSTCBDly進行查看,如果OSTCBDly為0不做操作繼續檢查下一個TCB。
當OSTCBDly非0,那麼OSTimeTick()對OSTCBDly得值減一,如果做完減一後OSTCBDly值為0則表明該任務延時結束,將該任務添加到就緒隊列。然後繼續下一個TCB。
重要(7)OSTCBPrio、該任務的優先級。個人感覺uC/Osii就是通過這個來區別不同的TCB,也就是OSTCBPrio就是這個任務的標志或者說是名字。
(8)OSTCBX OSTCBY OSTCBBitX OSTCBBitY、 長得很像啊,容易搞混,其實這四個給一個作用那就是分解Prio這個值,從而加速任務進入就緒的過程或者進入等待事件發生狀態的過程。那肯定有人就要疑惑為什麼能加速呢,我們來慢慢分析下:
首先讓任務進入就緒具體的操作就是將該任務的OSTCBPrio寫入就緒表中OSRdyGrp和OSRdyTbl[ ]。僅此而已,所以這也印證了在第7條中我說過OSTCBPrio就是這個任務的標志。而將OSTCBPrio寫入就緒表OSRdyGrp和OSRdyTbl[ ]並不是把這個值直接寫入就完了,而是要通過 OSRdyGrp |=OSMapTbl[prio>>3];
OSRdyTbl[prio>>3] |=OSMapTbl[prio & 0x07];這個計算式。那麼為了讓任務能更快的進入就緒狀態
我們就事先將OSMapTbl[prio>>3] OSMapTbl[prio & 0x07]算出來,而OSTCBX OSTCBY OSTCBBitX OSTCBBitY就是存儲這個些值的變量。
進入進入等待事件發生狀態的過程與之類似,就不講了(累死了。。)
(10)OSTCBEventPtr、指向時間控制快,是TCB和ECB聯系在一起。
四、任務的五種狀態:
(只有休眠狀態,沒有TCB}
休眠態(dormant):指任務駐留在程序空間中,還沒有交給內核管理,也就是任務沒有分配TCB 。把任務交給內核管理是通過調用OSTaskCreate( )或OSTaskCreatExt( )實現的,為其分配TCB
就緒(Ready):當任務一旦建立,這個任務就處於就緒態准備運行。任務可以動態的被另一個程序建立,也可以在系統運行開始之前建立。通過調用OSTaskDel( )使任務返回到休眠態。就緒態的任務都放在就緒列表中。在任務調度時,指針OSTCBHighRdy指向優先級最高的就緒任務,也就是立刻就要運行的任務。
任務處於就緒隊列兩個條件:首現要該任務被分配了TCB。其次是要將該任務的優先級(prio)寫進緒表中OSRdyGrp和OSRdyTbl[ ],具體辦法如下:
OSRdyGrp |=OSMapTbl[prio>>3];
OSRdyTbl[prio>>3] |=OSMapTbl[prio & 0x07];
運行態:優先級最高的任務獲得CUP,該任務就處於運行狀態,指針OSTCBCur指向正在運行的任務。
。 一旦有比這個任務優先級更高的任務出現,uC/OSii 就會通過OSSched()進行任務調度,將現在處於就緒狀態且優先級最高的任務交給CPU處理。
等待或掛起(Pending):正在運行的任務由於調用延時函數OSTimeDly( )、OSTimeDlyHMSM( )(將自身延遲)或等待某一事件的發生時,調用以下幾個函數:OSFlagPend()、OSSemPend(),OSMutexPend()、OSMboxPend(),如果該事件發生了,那麼該任務繼續執行,如果該事件沒有發生,那麼將自身掛起,因而處於等待或掛起態。
等待某事件而被掛起的任務,系統將會從OSRdyGrp和 OSRdyTbl[ ]中把該任務的優先級去掉(也就是相應位清0,因此在事件還沒發生時,這個任務將不會再被調度),轉而將該任務(優先級)添加在在該事件的等待列表中。
事件分為:信號量、互斥信號量,消息郵箱、隊列消息。每一個信號量、互斥信號量,消息郵箱、消息隊列都會分配到一個事件控制塊ECB.
每個ECB都會有 事件的等待列表OSEvenGrp和 OSEvenTbl[ ] ,它與就緒表中OSRdyGrp和OSRdyTbl[ ]極為相似。等待某事件而被掛起的任務,系統會將該任務優先級寫入事件的等待列表OSEvenGrp和 OSEvenTbl[ ]。
當某一事件發生了,那麼該事件的ECB會從事件的等待列表選取優先級最高的任務獲得事件,離開等待狀態,從而進入就緒狀態。
中斷態(Interrupt):正在運行的任務可以被中斷,除非是該任務將中斷關閉。被中斷的任務進入中斷服務程序(ISR)。如果中斷服務程序使一個更高優先級的任務准備就緒,這中斷服務程序結束後,則更高優先級的任務開始運行程序。
我覺得uC/Osii工作,其實根本上就是控制多個任務在這5鐘狀態下轉換,並且任務之間互相通信。所以一下從一個狀態到另一個狀態分析。