μc/os-II原理簡介(筆記)
1、實時作業系統必須是多工系統,任務的切換時間應與系統中的任務數無關,並且中斷延遲的時間應該可預知並儘可能短。
第二章
3.1.1
1、從任務的儲存結構上看,μc/os-II的任務由:任務程式程式碼、任務堆疊和任務控制塊組成。
2、μc/os-II是所有的任務都是執行緒,沒有給任務分配私有空間。
3.1.2
1、任務的5種狀態:睡眠狀態、就緒狀態、執行狀態、等待狀態、中斷服務狀態
3.1.3
1、臨界段,進入臨界巨集段,退出臨界巨集段
2、使用者任務就是一個C語言函式,main()負責任務的建立並把他們交給系統,由作業系統來管理和排程
3.1.4
1、空閒任務 ,叫OSTaskIdle()的系統任務,做加1操作,規定:使用者應用程式必須使用這個空閒任務,且不能通過程式刪除
2、統計任務,叫OSTaskStat()的系統任務,計算CPU單位時間內被使用的時間。根據需要呼叫。
3.1.5
1、任務的優先權及優先級別
3.2
1、每個任務都應該配有自己的堆疊。
3.2.1
1、為提高可移植性,用選擇開關寫出向下和向上增長的任務堆疊
2、把任務初始化資料放到任務堆疊的工作叫做任務堆疊的初始化。
3.3
1、任務控制塊:記錄任務的堆疊指標、任務的當前狀態、任務的優先級別等一些與任務管理有關的屬性的表
122頁
3.3.1
1、任務控制塊結構
3.3.2
1、在任務控制管理上,μC/OS-II有兩條連結串列:一條空任務塊連結串列(其中所有任務控制塊還未分配給任務)和一條任務塊連結串列(其中所有的任務控制塊已分分配給任務)
3.3.3
1、初始化任務控制塊函式OTCBInit()
主要任務:1.為被建立任務從空任務控制塊連結串列獲取一個任務控制塊
2.用任務的屬性對任務控制塊各個成員進行復制
3.把這個任務控制塊鏈入到任務控制塊連結串列
3.4
3.4.1
1、任務就緒表結構:它是一個位圖,系統中的每個任務都在這個點陣圖中佔據一個二進位制位。值為1表示任務處於就緒狀態
2、每個陣列元素描述了8個任務的就緒狀態,這八個任務看成一個任務組
3、優先順序化為二進位制,取低六位,其中高三位指明OSRdyTBl,即第幾個陣列,低三位指明該陣列元素的具體資料位。
3.4.2
對任務就緒表的操作
1、登記:在就緒表中將該任務的對應位置置1
2、登出:某個任務需要脫離就緒狀態時,系統在就緒表中將該任務的對應位置置0
3、最高優先順序就緒任務查詢:排程器能從任務就緒表中查詢最高優先順序任務的能力
3.4.3
1、排程器的主要工作:1.查詢具有最高優先級別的就緒任務2.實現任務的切換
2、兩種排程器:1.任務級的排程器(由OSSched()實現) 2.中斷級的排程器(由函式OSIntExt()實現)
3、任務切換兩個步驟:1.獲得待執行的TCB指標 2.進行斷點資料的切換
4、OSSchedLock()和OSScheedUnclock()給排程器上鎖和解鎖。變數OSLockNesting瞭解排程器上鎖的巢狀次數,上鎖加1,解鎖-1
5、排程器在任務切換前獲得兩個指標OSTCBHignRdy(指向待執行任務控制塊) OSTCBCur(指向當前任務控制塊)
6、任務的切換時斷點資料的切換,斷點資料的切換也就是CPU堆疊指標的切換
7、任務切換巨集OS_TASK_SW()7項工作
①把被中止的斷點指標儲存到任務堆疊中
②把CPU通用暫存器的內容儲存到任務堆疊中
③把被中止的任務的任務堆疊指標當前值儲存到該任務的控制塊的OSTCBStkPtr中
④獲得待執行任務的任務控制塊
⑤使CPU通過任務控制塊獲得待執行任務的任務堆疊指標
⑥把待執行任務堆疊中通用暫存器的任務恢復到CPU的通用暫存器中
⑦使CPU獲得待執行任務的斷點指標
3.5
3.5.1
1、任務建立函式OSTaskCeeate(),OSTaskCreateExt()
3.6
1、任務的掛起:停止這個任務的執行
2、OSTakSuspend()掛起自身或者除空閒任務之外的其他任務
3、用OSTakSuspend()掛起的任務,只能在其他任務中通過呼叫恢復函式OSTaskResume()使其恢復為就緒函式
3.7.1
1、任務優先級別的修改函式OSTaskChangePrio()
3.7.2
1、任務的刪除:把該任務置於睡眠狀態
2、任務刪除函式OTaskDel()刪除自身或者除了空閒任務之外的其他任務
3、刪除一個佔用資源的任務時,提出刪除任務請求的任務只負責提出刪除任務請求而刪除工作則由被刪除任務自己來完成
3.7.3
1、OSTaskQuery()獲取選定任務的資訊
3.8.1
1、應用程式首先應該呼叫OSInit()函式對全域性變數和資料結構進行初始化,以建立執行環境
2、應用程式是通過呼叫函式OSStart()開始進行多工管理的,但在呼叫函式OSStart()之前必須至少建立了一個任務。
4.1
1、應中斷請求而執行的程式叫做中斷服務子程式(ISR),中斷服務子程式的入口地址叫做中斷向量
2、對於可剝奪型的μC/OS-II核心來說,中斷服務子程式執行結束後,系統將會根據情況進行一次任務排程去執行優先級別最高的就緒任務,而不一定是繼續執行被中斷的任務。
4.1.1
μC/OS-II中,通常用一個任務來進行非同步事件的處理,而在中斷服務程式中只是通過向任務發訊息的方法去啟用這個任務
4.1.2
1、OSIntCtxSw()叫做中斷級任務切換函式
2、被中斷任務的斷點保護工作已經在中斷服務程式中完成了。
4.1.3
1、μC/OS-II中不希望被中斷的程式碼段叫做臨界段
2、μC/OS-II中不要在臨界段中呼叫μC/OS-II提供的功能函式,一面系統崩潰
4.2
1、最小的時鐘單位就是兩次中斷之間的相間隔的時間,這個最小時鐘單位叫做時鐘節拍
2、時鐘中斷服務程式中呼叫的OSTiemTick()叫做時鐘節拍服務函式
3、函式OSTimeTick()的任務就是在每個時鐘節拍瞭解每個任務的延時狀態,使其中已經到了延時實現的非掛起任務進入就緒狀態。
4、OSTimeTick()是系統呼叫的函式,為了方便程式設計師能在系統呼叫的函式中插入一些自己的工作,μC/OS-II提供了時鐘節拍服務函式的鉤子函式OSTimeTickHook()
4.3
1、除了空閒任務之外的所有任務必須在任務中合適的位置呼叫系統提供的函式OSTimeDly(),使當前任務的執行延時(暫停)一段時間並進行一次任務排程,以讓出CPU的使用權
2、呼叫了函式OSTimeDly()或OSTimeDlyHMSM()的任務,當規定的延時時間期滿,或有其他任務通過呼叫函式OSTimeDlyResume()取消了延時時,它立即回進入就緒狀態
4.3.2
1、延時的任務可通過在其他任務中呼叫函式OSTimeDlyResume()取消延時而進入就緒狀態。如果任務比正在執行的任務優先級別高,則立即引發一次任務排程
4.3.3
1、OSTime記錄系統發生的時鐘節拍數
2、應用程式中呼叫函式OSTimeGet()可獲取OSTime的值
5.1.1
1、任務之間的制約關係:1.直接制約關係:源於任務之間的合作
2.間接制約關係:源於對資源的共享
2、μC/OS-II使用訊號量、郵箱(訊息郵箱)和訊息佇列這些中間環節來實現任務之間的通訊。這些中間環節統一稱作"事件"
5.1.2
1、μC/OS-II把任務傳送事件、請求事件以及其他對事件的操作都定義成為全域性函式,以供應用程式的所有任務來呼叫
2、用來傳遞訊息緩衝區的指標的資料結構叫做訊息郵箱。定義一個數組,讓陣列的每個元素都存放一個訊息緩衝區指標,那麼任務就可以通過傳遞這個指標陣列指標的方法來傳遞多個訊息。
3、可以傳遞多個訊息的資料結構叫做訊息佇列
5.2.1
1、功能完善的事件對等待任務具有兩方面的管理功能:一是要對等待事件的所有任務進行記錄並排序,二是應該允許等待任務有一個等待時限,即當等待任務認為等不及時可以退出對事件的請求
5.2.2
1、EventWaitLostInit()可以對事件控制塊進行初始化。該函式的作用就是把變數OSEventGrp及任務等待表中的每一位都清0,即令事件的任務等代表中不含有任何等待任務。
2、把一個任務置於等待狀態要用函式OS_EventTaskWait()
3、OS_EventTaskRdy() 使具備可以執行條件的正在等待的任務進入就緒狀態。函式作用是把呼叫這個函式的任務在任務等待表中的位置清0(解除等待狀態)後,再把任務在任務就緒表中對應的位置1,然後引發一次任務排程
4、一個正在等待事件的任務已經超過了等待的時間,卻仍因為沒有獲取事件等原因而未具備而已執行的條件,卻又要使它進入就緒狀態,這時要呼叫OS_EventTo()
5.3.1
當事件控制塊成員OSEventType的值被設定為OS_EVENT_TYPE_SEM時,這個事件控制塊描述的就是一個訊號量
5.3.2
1、使用訊號之前,應用程式必須呼叫函式OSSemCreate()來建立一個訊號量。函式的返回值為已建立的訊號量的指標。
2、當任務需要訪問一個共享資源時,先要請求管理該資源的訊號量,這樣就可以根據訊號量當前是否有效(即訊號量的計數器OSEventCnt的值是否大於0)來決定改任務是否可以繼續執行
3、任務獲得訊號量,並在訪問共享資源結束以後,必須釋放訊號量。釋放訊號量叫做傳送訊號量,呼叫OSSemPost()
4、應用程式不需要某個訊號量,那麼可呼叫函式OSSemDel()來刪除該訊號量,
5、只能在任務中刪除訊號量,而不能在中斷服務函式中刪除。
6、任務可以呼叫函式OSSemQuery()隨時查詢訊號量的當前狀態。
5.4
1、互斥型訊號是一個二值訊號,它可以使任務以獨佔方式使用共享資源
2、優先順序反轉原因:一個優先級別較低的任務在獲得了訊號量使用共享資源期間,被具有較高優先級別的任務所打斷而不能釋放訊號量,從而使正在等待這個訊號量的更高級別的任務得不到訊號量而被迫處於等待狀態,在這個等待期間,就讓優先級別低於它而高於佔據訊號量的任務的任務先運行了。
3、解決辦法之一:使獲得訊號量的任務的優先級別在使用共享資源期間暫時提高到所有任務最高優先級別的高一個級別上,以使該任務不被其他任務所打斷,從而能儘快地使用完共享資源並釋放訊號量,然後在釋放訊號量之後,再回復該任務原來的優先級別
5.4.2
1、OSMutexCreate()建立互斥型訊號量
2、當任務需要訪問一個獨佔式共享資源時,就要呼叫函式OSMutexPend()來請求管理這個資源互斥型訊號量
3、OSMutexPost()傳送一個互斥型訊號量
4、OSMetexQuery()獲取互斥型訊號量的當前狀態
5、OSMetexDel()刪除一個互斥型訊號量
5.5.2
1、建立郵箱需要呼叫函式OSMboxCreate(),引數為訊息的指標,返回值為訊息郵箱的指標
2、OSMboxPost()向訊息郵箱傳送訊息
3、OSMboxPostOpt(),該函式可以廣播的方式向事件等待任務表中的所有任務傳送訊息
4、OSMboxQuery()查詢郵箱的當前狀態,並把相關資訊存放在一個結OS_MBOX_DATA中
5、OSMboxDel()刪除一個郵箱。
5.6.1
1、使用訊息佇列可在任務之間傳遞多條訊息。訊息佇列由三部分組成:事件控制塊、訊息控制塊、訊息佇列和訊息
5.6.2
1、建立訊息佇列首先需要定義一個指標陣列,然後把各個訊息資料緩衝區的首地址存放入這個陣列中,最後呼叫OSQCreate()來建立訊息佇列。
2、請求訊息佇列函式OSQPend()從訊息佇列中獲取訊息
3、OSQPost()或OSQPOSTFront()來向訊息佇列傳送訊息
4、OSQFlush()來清空訊息佇列
5、OSQDel()刪除訊息佇列
6、0SQQuery()查詢一個訊息佇列的狀態
6.1.1
1、μC/OS-II訊號量集由一個標誌組合多個等待任務控制塊組成
2、標誌組主要組成部分是一個叫做訊號列表的二進位制數OSFlagFlags,其實就是一個位圖。該點陣圖每一位都對應一個訊號量,點陣圖的作用就是用來接收並儲存其他任務所發來的訊號量值,所以它也可看做是輸入訊號暫存器。
3、等待任務:已經向訊號量集合發出請求操作的任務
6.1.3
1、給等待任務連結串列新增節點的函式為OS_FlagBlock()
2、從等待任務連結串列中刪除一個節點的函式為OS_flagUnlink()
6.2.1
1、任務可以通過呼叫函式OSFlagCreate()來建立一個訊號量集
6.2.2
1、OSFlagPend()請求一個訊號量集
2、OSFlagPost()向訊號量集傳送訊號
3、OSFlagQueary()查詢一個訊號量集的狀態
4、OSFlagDel()刪除一個訊號量集
7.1
1、μC/OS-II對記憶體進行兩級管理,即把一個連續的記憶體空間分為若干個分割槽,每個分割槽又分為若干個大小相等的記憶體塊
2、作業系統以分割槽為單位來管理動態記憶體,而任務以記憶體塊為單位來獲取和釋放動態記憶體
3、記憶體分割槽是系統對記憶體進行管理的基本單位
7.1.2
1、系統用記憶體控制塊(OS_MEN)來記錄和跟蹤每一個記憶體分割槽的狀態
7.1.3
1、函式首先對建立一個記憶體分割槽的基本條件做一系列判斷,然後定義記憶體分割槽。如果一個條件不滿足,就意味著函式呼叫失敗。
2、條件判斷主要注意兩點:1.分割槽的記憶體塊至少有兩塊,2.每個記憶體塊空間至少能存放一個指標(因為要在記憶體塊中建立一個用於把記憶體分割槽的記憶體塊連結為已個連結串列的指標)
7.2.2
1、應用程式需要一個記憶體塊時,應用程式可以通過函式OSMenGet()向某記憶體分割槽請求獲得一個記憶體塊
2、需要注意:應用程式呼叫OSMenGet(),應該事先知道該分割槽中記憶體塊的大小,並且在使用時不能超過該記憶體塊大小,否則會引起災難性後果
7.2.3
1、當應用程式不再使用一個記憶體塊時,必須及時地將其釋放。
7.2.4
1、OSMenQueary()來查詢一個分割槽目前的狀態資訊
8.1.1
1、可重入函式:能被多個任務所呼叫,並且不會產生任務之間的相互干擾的函式
8.2
1、為了提高可移植性,μC/OS-II的絕大部分程式碼都用C語言編寫。在一般情況下,這部分程式碼不需要修改就可以使用,而需要修改的主要是以下4個檔案
①彙編檔案OS_CPU_A.ASM
②處理器相關的C檔案OS_CPU_.H和OS_CPU_C.C
③系統配置檔案OS_CFG.H
8.2.4
1、原則上對μC/OS-II進行移植時,並不需要修改與處理器無關的程式碼,但因為在預設情況下KEIL編譯器生成的程式碼不可衝入,如果要生成可衝入程式碼,則必須在函式後面顯示地使用關鍵詞reentrant.