目錄
- μC/OS-Ⅱ任務調度
- 1.任務控制塊
- 2.任務管理
- 3.任務狀態
- μC/OS-Ⅱ時間管理
- μC/OS-Ⅱ內存管理
- 內存控制塊MCB
- μC/OS-Ⅱ任務通信
- 1.事件
- 2.事件控制塊ECB
- 3.信號量
- 4.郵箱
- 5.消息隊列
操作系統內核:在多任務系統中,提供任務調度與切換、中斷服務
操作系統內核為每個任務分配CPU時間,并且負責任務之間的通信。
嵌入式操作系統核心內容:
1、進程調度
2、進程通信
3、內存管理
4、設備管理
嵌入式操作系統的結構:
μC/OS-Ⅱ任務調度
用戶在建立操作系統的時候需要初始化操作系統。
任務調度的時候需要開始操作系統。
中斷的代碼不允許其他中斷,需要進入代碼臨界段函數,臨界段完成后使用退出代碼臨界段函數。
有些任務間一些處理過程比較重要,不希望被別的任務打斷,需要使用任務調度上鎖函數,完成之后需要使用任務調度解鎖函數。
1.任務控制塊
任務控制塊是一個基于鏈表的數據結構,任務控制塊主要用于記錄任務的堆棧棧頂指針、指向下一個任務控制塊的指針、任務等待的延遲時間、任務的當前狀態標志與任務的優先級別等一些與任務管理有關的屬性。
當任務的CPU使用權被剝奪時,μC/OS-Ⅱ用任務控制塊來保存該任務的狀態,從而保證任務重新獲得CPU使用權時從斷點處執行。
系統中的每一個任務都有一個任務控制快,用于存放該任務的狀態。任務控制塊中的各個單元的值一般不需要用戶改動。
2.任務管理
任務分為兩個形式:
1、無限循環
void Task1()
{for(;;){//用戶任務代碼}osdelay();
}
2、任務在運行完畢后自我刪除
void Task2()
{//用戶任務代碼//自我刪除osTaskDel(OS_PRIO_SELF);osdelay();
}
3、基本的應用任務框架:
int main()
{//目標板初始化OsInit(); //創建任務1、2、3......osTaskCreate(Task1,(void*)0,(os_stk *)&Task1_Stack[TASK_STACK_SIZE - 1],Task1_PRIO);osTaskCreate(Task2,(void*)0,(os_stk *)&Task1_Stack[TASK_STACK_SIZE - 1],Task2_PRIO);//開始任務osStart();//進入調度
}
3.任務狀態
μC/OS-Ⅱ任務共有4種狀態:
1、睡眠態:任務處于該狀態時,僅有任務代碼,并沒有操作系統處理
2、就緒態:任務處于該狀態時,隨時可以準備運行
3、運行態:正在運行的任務,一般是運行就緒優先級最高的任務
4、掛起態:當任務處于該狀態時,任務不會運行,只有當任務返回就緒狀態時,才可以運行
每個任務的切換如下:
uC/OS-II OS_TASK.C中有關任務管理的函數
μC/OS-Ⅱ時間管理
μC/OS-Ⅱ內核要求用戶提供定時中斷來實現延時和超時控制等功能。此定時中斷叫做時鐘節拍。時鐘節拍頻率越高,系統的負載越重。
主要用到的函數:
函數 | 用途 |
---|---|
OSTimeDly() | 任務延時函數 |
OSTimeDlyHMSM() | 按時分延時函數 |
OSTimeDlyResume() | 讓處在延時期的任務結束延時 |
OSTimeGet() | 得到系統時間 |
OSTimeSet() | 設置系統時間 |
1、OSTimeDly():
調用該函數會進行一次任務調度,并且執行下一個優先級最高的就緒態任務。
調用函數之后,一旦規定的時間期滿或者有其他任務通過調用OSTimeDlyResume()取消延時,它就會立馬進入就緒狀態。
本函數是將處于運行狀態的轉入掛起狀態,當延時結束的時候,任務重新返回到就緒狀態。
2、OSTimeDlyResume()
使用任務延遲函數OSTimeDly()和任務掛起函數OSTaskSuspend()的任務都是處于掛起狀態,但是兩個處理方法不同:
任務的時間延時與恢復是通過設置任務控制塊TCB中的OSTCBDly表示。
OSTaskSuspend通過設置任務控制塊TCB中的OS_STAT_SUSPEND標志來表示任務正在被掛起。
所以通過任務回復函數OSTaskResume()不能恢復處于被時間延時的任務
μC/OS-Ⅱ內存管理
malloc和free函數可以動態分配內存和釋放內存,但是多次這樣做會把原來很大的一塊連續內存區域逐漸地分割成許多非常小而且彼此不相鄰的內存區域,也就是內存碎片
操作系統把連續的大塊內存按照分區:
μC/OS-Ⅱ對malloc和free進行了改進,使它們可以分配和釋放固定大小的內存塊。用戶應用程序可以從不同的內存分區中得到不同大小的內存塊,特定的內存塊在釋放時必須重新放回它以前所屬于的內存分區。使用這樣的內存管理算法,內存碎片問題得以解決。
內存控制塊MCB
內存控制塊MCB是一個數據結構,μCOSII用它對內存進行管理,來表示每個內存分區的信息,系統中的每個內存分區都有它自己的內存控制塊,MCB包括以下內容:
μC/OS-Ⅱ任務通信
1.事件
μC/OS-Ⅱ提供三種特殊的數據共享和任務通信的方法:信號量、郵箱、消息隊列。統稱為事件。
μC/OS-Ⅱ用事件控制塊ECB表示事件的信息。
任務或中斷服務子程序可以通過ECB向另外的任務發事件。
任務可以等待另一個任務或者中斷服務子程序給它發事件。
只有任務可以等待事件發生,中斷服務子程序不能。
1、對于等待的任務,可指定一個最長等待事件,以免無限期等待。中斷服務程序不能等待事件
2、多個任務同時等待一個事件,優先級最高的任務得到該時間并進入就緒態
2.事件控制塊ECB
ECB是描述事件的數據結構,它由以下幾個部分構成:
- OSEventPtr 當事件是郵箱或者消息隊列時,是指向郵箱或消息隊列的的指針
2.OSEventCnt 當事件是一個信號量時,是信號量的計數器。
3.OSEventTbl[] 和 .OSEventGrp 等待該事件的任務表和組。
4.OSEventType定義了事件的具體類型,可以是信號量(OS_EVENT_SEM)、郵箱(OS_EVENT_TYPE_MBOX)或消息隊列(OS_EVENT_TYPE_Q)中的一種。
3.信號量
信號量由兩部分組成:該信號量的計數器的值、等待該信號量的任務組成的等待任務列表。
信號量的接口分為:
建立一個信號量
等待一個信號量
發送一個信號量
無等待地請求一個信號量
查詢一個信號量的當前狀態
信號量的使用規范:
任何時刻都可以建立信號量
只有任務可以等待信號量
中斷和任務可以發送信號量
中斷和任務可以無等待地請求一個信號量
只有任務可以查詢一個信號量的當前狀態
工作原理
在使用一個信號量之前,首先調用函數建立該信號量,對信號量的初始計數值賦值。
如果信號量用來表示一個或者多個事件的發生,那么該信號量的初始值設為0;
如果信號量用來對共享資源的訪問,那么該信號量的初始值設為1;
如果信號量是用來表示允許任務訪問n個相同的資源,那么初始值應為n,并作為可計數的信號量使用。
任務根據信號量的值來判斷是否可以運行(比如是否對公共資源可以訪問)
幾個任務往往只建立一個信號量sem:
任務一先執行任務二后執行的信號量變化順序:任務一先P操作信號量排斥任務二的執行,完成后再V操作信號量放行任務二
4.郵箱
郵箱的接口分為:
建立一個郵箱
等待一個郵箱中的消息
發送一個消息到郵箱中
無等待地從郵箱中得到一個消息
查詢一個郵箱的狀態
郵箱使一個任務或者中斷服務子程序向另一個任務發送一個指針型的變量。該指針指向一個包含特定“消息”的數據結構。
如果使用郵箱的目的是通知一個事件的發生(發送一條消息),那么就要初始化該郵箱為NULL,因為在開始時,事件還沒有開始。
如果用郵箱來共享某些資源,那么就要初始化該郵箱為一個非NULL的指針,這種情況,郵箱作為一個二值信號使用。
郵箱的使用規范:
1、任何時刻都可以建立郵箱
2、中斷和任務可以無等待地請求郵箱的消息
3、中斷和任務可以發送消息到消息
4、只有任務可以等待一個郵箱的消息
5、只有任務可以查詢一個郵箱的當前狀態
6、郵箱中的消息可以被讀出
5.消息隊列
一個任務通過消息隊列向另一個任務發送“一串”指針型的變量,該些指針指向各個包含“消息”的數據結構
消息隊列可以看成多個郵箱組成的隊列,但這些郵箱使用同一個等待任務列表
消息隊列的接口分為:
建立一個消息隊列
等待一個消息隊列中的消息
發送一個消息到消息隊列中
無等待地從消息隊列中得到一個消息
查詢一個消息隊列的狀態
清空一個消息隊列
消息隊列的使用規范:
任何時刻都可以建立消息隊列中的消息
只有任務可以等待一個消息隊列中的消息
中斷和任務可以發送消息到消息隊列中
中斷和任務可以無等待地請求消息隊列中的消息
只有任務可以查詢一個消息隊列的當前狀態
中斷和任務可以清空消息隊列