1.簡介
UCOSII 是一個能夠基於 ROM 運行的、可裁減的、搶佔式、實時多任務內核,具備高度可移植性,特別適合於微處理器和控制器,是和不少商業操做系統性能至關的實時操做系統(RTOS)。併發
1.1 UCOSII 體系結構圖函數
UCOSII 的移植,咱們只須要修改: os_cpu.h、 os_cpu_a.asm 和 os_cpu.c等三個文件。性能
os_cpu.h: 進行數據類型的定義,以及處理器相關代碼和幾個函數原型;測試
os_cpu_a.asm:是移植過程當中須要彙編完成的一些函數,主要就是任務切換函數;操作系統
os_cpu.c:定義一些用戶 HOOK 函數。.net
定時器的做用:爲 UCOSII 提供系統時鐘節拍,實現任務切換和任務延時等功能。這
個時鐘節拍由 OS_TICKS_PER_SEC(在 os_cfg.h 中定義)設置,通常咱們設置UCOSII 的系統時鐘節拍爲 1ms~100ms,具體根據你所用處理器和使用須要來設置。本章,利用 STM32的 SYSTICK 定時器來提供 UCOSII 時鐘節拍。指針
1.2 任務
任務:其實就是一個死循環函數,該函數實現必定的功能,一個工程能夠有不少這樣的任務(最多 255 個), UCOSII 對這些任務進行調度管理, 讓這些任務能夠併發工做(注意不是同時工做,併發只是各任務輪流佔用 CPU,而不是同時佔用,任什麼時候候仍是隻有 1個任務可以佔用 CPU), 這就是 UCOSII 最基本的功能。blog
Ucos 任務的通常格式爲:接口
void MyTask (void *pdata)
{
任務準備工做…
While(1)//死循環
{ 任務 MyTask 實體代碼;
OSTimeDlyHMSM(x,x,x,x);//調用任務延時函數,釋放 cpu 控制權,
}
}
1
2
3
4
5
6
7
8
1.3 任務優先級
ucos 中,每一個任務都有惟一的一個優先級。優先級是任務的惟一標識。在 UCOSII中,使用 CPU 的時候,優先級高(數值小)的任務比優先級低的任務具備優先使用權,即任務就緒表中老是優先級最高的任務得到 CPU 使用權,只有高優先級的任務讓出 CPU 使用權(好比延時)時,低優先級的任務才能得到 CPU 使用權。 UCOSII 不支持多個任務優先級相同,也就是每一個任務的優先級必須不同。事件
1.4 任務堆棧
存儲器中的連續存儲空間。爲了知足任務切換和響應中斷時保存 CPU 寄存器中的內容以及任務調用其餘函數時的須要,每一個任務都有本身的堆棧。在建立任務的時候,任務堆棧是任務建立的一個重要入口參數。
1.5 任務控制塊 OS_TCB
用來記錄任務堆棧指針,任務當前狀態以及任務優先級等任務屬性。UCOSII 的任何任務都是經過任務控制塊(TCB)的東西來控制的,一旦任務建立了,任務控制塊 OS_TCB 就會被賦值。每一個任務管理塊有 3 個最重要的參數:
1.任務函數指針;
2.任務堆棧指針;
3.任務優先級;
任務控制塊就是任務在系統裏面的身份證。
1.6 任務就緒表
用來記錄系統中全部處於就緒狀態的任務。它是一個位圖,系統中每一個任務都在這個圖中佔據一個進制位,該位置的狀態(1 或者 0)就表示任務是否處於就緒狀態。
1.7 任務調度
一是在任務就緒表中查找優先級最高的就緒任務,二是實現任務的切換。好比說,當一個任務釋放 cpu 控制權後,進行一次任務調度,這個時候任務調度器首先要去任務就緒表查詢優先級最高的就緒任務,查到以後,進行一次任務切換,轉而去執行下一個任務。
1.8 狀態切換
UCOSII 的每一個任務都是一個死循環。每一個任務都處在如下 5 種狀態之一的狀態下,這 5種狀態是:睡眠狀態、 就緒狀態、 運行狀態、 等待狀態(等待某一事件發生)和中斷服務狀態。
睡眠狀態:任務在沒有被配備任務控制塊或被剝奪了任務控制塊時的狀態。
就緒狀態:系統爲任務配備了任務控制塊且在任務就緒表中進行了就緒登記,任務已經準備好了,但因爲該任務的優先級比正在運行的任務的優先級低, 還暫時不能運行,這時任務的狀態叫作就緒狀態。
運行狀態:該任務得到 CPU 使用權,並正在運行中,此時的任務狀態叫作運行狀態。
等待狀態:正在運行的任務,須要等待一段時間或須要等待一個事件發生再運行時,該任務就會把 CPU 的使用權讓給別的任務而使任務進入等待狀態。
中斷服務狀態:一個正在運行的任務一旦響應中斷申請就會停止運行而去執行中斷服務程序,這時任務的狀態叫作中斷服務狀態。
5種狀態之間的轉換以下圖:
2.UCOS相關函數
2.1 創建任務函數
若是想讓 UCOSII 管理用戶的任務,必須先創建任務。 UCOSII 提供了 2 個創建任務的函數: OSTaskCreat 和 OSTaskCreatExt,通常用 OSTaskCreat 函數來建立任務。
該函數原型爲:
OSTaskCreate(void(*task)(void*pd),void*pdata,OS_STK*ptos,INTU prio);
1
task:是指向任務代碼的指針;
pdata:是任務開始執行時,傳遞給任務的參數的指針;
ptos:是分配給任務的堆棧的棧頂指針;
prio :是分配給任務的優先級。
每一個任務都有本身的堆棧,堆棧必須申明爲 OS_STK 類型,而且由連續的內存空間組
成。能夠靜態分配堆棧空間,也能夠動態分配堆棧空間。
2.2 任務刪除函數
任務刪除,其實就是把任務置於睡眠狀態。 UCOSII提供的任務刪除函數原型爲:
INT8U OSTaskDel(INT8U prio);
1
參數 prio :要刪除的任務的優先級,可見該函數是經過任務優先級來實現任務刪除的。
特別注意:任務不能隨便刪除,必須在確保被刪除任務的資源被釋放的前提下才能刪除!
2.3 請求任務刪除函數
前面提到,必須確保被刪除任務的資源被釋放的前提下才能將其刪除,因此經過向被刪除任務發送刪除請求,來實現任務釋放自身佔用資源後再刪除。
UCOSII 提供的請求刪除任務函數原型爲:
INT8U OSTaskDelReq(INT8U prio);
1
經過優先級來肯定被請求刪除任務。
2.4 任務掛起函數
任務掛起和任務刪除有點相似,可是又有區別,任務掛起只是將被掛起任務的就緒標誌刪除,並作任務掛起記錄,並無將任務控制塊任務控制塊鏈表裏面刪除, 也不須要釋
放其資源, 而任務刪除則必須先釋放被刪除任務的資源,並將被刪除任務的任務控制塊也給刪了。被掛起的任務,在恢復(解掛)後能夠繼續運行。
UCOSII 提供的任務掛起函數原型爲:
INT8U OSTaskSuspend(INT8U prio);
1
2
2.5 任務恢復函數
有任務掛起函數,就有任務恢復函數,經過該函數將被掛起的任務恢復,讓調度器能
夠從新調度該函數。
UCOSII 提供的任務恢復函數原型爲:
INT8U OSTaskResume(INT8U prio);
1
3.移植 UCOSII
3.1 移植UCOUS
3.2 編寫任務函數並設置其堆棧大小和優先級等參數
編寫任務函數,以便 UCOSII 調用。
設置函數堆棧大小,這個須要根據函數的需求來設置,若是任務函數的局部變量多,嵌套層數多,那麼相應的堆棧就得大一些,若是堆棧設置小了,極可能出現的結果就是 CPU進入 HardFault,遇到這種狀況,就必須把堆棧設置大一點了。另外,有些地方還須要注意堆棧字節對齊的問題,若是任務運行出現莫名其妙的錯誤(好比用到 sprintf 出錯),請考慮是否是字節對齊的問題。
設置任務優先級, 這個須要根據任務的重要性和實時性設置,高優先級的任務有優先使用 CPU 的權利。
3.3 初始化 UCOSII,並在 UCOSII 中建立任務
調用 OSInit,初始化 UCOSII,經過調用 OSTaskCreate 函數建立咱們的任務。
3.4 啓動 UCOSII
調用 OSStart,啓動 UCOSII。
4.軟件配置
4.1 UCOSII源碼說明
UCOSII-CORE:是UCOSII 的核心源碼,不須要作任何變更。
UCOSII-PORT :移植 UCOSII 要修改的 3 個代碼,這個在移植的時候完成。
UCOSII-CONFIG : UCOSII 的配置部分,主要由用戶根據本身的須要對 UCOSII進行裁剪或其餘設置。
4.2 UCOSII簡易測試
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "includes.h"
/////////////////////////UCOSII任務設置///////////////////////////////////
//START 任務
//設置任務優先級
#define START_TASK_PRIO 10 //開始任務的優先級設置爲最低
//設置任務堆棧大小
#define START_STK_SIZE 64
//任務堆棧
OS_STK START_TASK_STK[START_STK_SIZE];
//任務函數
void start_task(void *pdata);
//LED0任務
//設置任務優先級
#define LED0_TASK_PRIO 7
//設置任務堆棧大小
#define LED0_STK_SIZE 64
//任務堆棧
OS_STK LED0_TASK_STK[LED0_STK_SIZE];
//任務函數
void led0_task(void *pdata);
//LED1任務
//設置任務優先級
#define LED1_TASK_PRIO 6
//設置任務堆棧大小
#define LED1_STK_SIZE 64
//任務堆棧
OS_STK LED1_TASK_STK[LED1_STK_SIZE];
//任務函數
void led1_task(void *pdata);
int main(void)
{
delay_init(); //延時函數初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 設置中斷優先級分組2
LED_Init(); //初始化與LED鏈接的硬件接口
OSInit();
OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//建立起始任務
OSStart();
}
//開始任務
void start_task(void *pdata)
{
OS_CPU_SR cpu_sr=0;
pdata = pdata;
OS_ENTER_CRITICAL(); //進入臨界區(沒法被中斷打斷)
OSTaskCreate(led0_task,(void *)0,(OS_STK*)&LED0_TASK_STK[LED0_STK_SIZE-1],LED0_TASK_PRIO);
OSTaskCreate(led1_task,(void *)0,(OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-1],LED1_TASK_PRIO);
OSTaskSuspend(START_TASK_PRIO); //掛起起始任務.
OS_EXIT_CRITICAL(); //退出臨界區(能夠被中斷打斷)
}
//LED0任務
void led0_task(void *pdata)
{
while(1)
{
LED0=0;
delay_ms(80);
LED0=1;
delay_ms(920);
};
}
//LED1任務 void led1_task(void *pdata) { while(1) { LED1=0; delay_ms(300); LED1=1; delay_ms(300); }; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 參考:原子庫函數手冊 ———————————————— 版權聲明:本文爲CSDN博主「霽風AI」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接及本聲明。 原文連接:https://blog.csdn.net/wwt18811707971/article/details/80978819