1. 程式人生 > >STM32學習筆記一一UCOSII(1)

STM32學習筆記一一UCOSII(1)

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 函式。

定時器的作用:為 UCOSII 提供系統時鐘節拍,實現任務切換和任務延時等功能。這 
個時鐘節拍由 OS_TICKS_PER_SEC(在 os_cfg.h 中定義)設定,一般我們設定UCOSII 的系統時鐘節拍為 1ms~100ms,具體根據你所用處理器和使用需要來設定。本章,利用 STM32的 SYSTICK 定時器來提供 UCOSII 時鐘節拍。

1.2 任務
任務:其實就是一個死迴圈函式,該函式實現一定的功能,一個工程可以有很多這樣的任務(最多 255 個), UCOSII 對這些任務進行排程管理, 讓這些任務可以併發工作(注意不是同時工作,併發只是各任務輪流佔用 CPU,而不是同時佔用,任何時候還是隻有 1個任務能夠佔用 CPU), 這就是 UCOSII 最基本的功能。

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/art