1. 程式人生 > >uC/OS-III 任務詳解(四)

uC/OS-III 任務詳解(四)

uC/OS系統的任務一般都放在最開始介紹,我放在第四章主要是對模糊的概念作清晰的講解。

從使用者的角度來看,uC/OS-III 中的任務可以分為5 種狀態,分別是休眠態、就緒態、執行態、掛起態和中斷態,如下表所示。

 

 

 任務狀態之間的具體切換情況如下圖所示。

 

 

也就是說,任務有五個狀態,分別是休眠態、就緒態、執行態、等待態、中斷服務態。即任務還沒使用函式OSTaskCreate()建立時就是屬於休眠態,而一但使用函式OSTaskCreate()建立了任務,並且函式OSStart()之前已經被執行的話,那麼任務就屬於就緒態了。然後系統會根據就緒表裡任務的優先順序來只執行最高的任務,而這個被執行的任務也從就緒態變為執行態,這個時刻就是這個優先順序最高的任務的CPU獨享moment(也就是獨自擁有CPU的使用權),直到這個任務被被切換成其他狀態(使用OSTimeDly()、OSSemPend()等函式能將執行態的函式變為等待態),那麼就緒表裡優先順序最高的任務就會得到CPU的使用權執行任務,依次迴圈。

所以我這麼分類,如果一個正在執行的任務M(即正在執行優先順序最高的任務),它就只有兩種情況,A.一直迴圈執行下去   B.改變自己任務狀態。 改變狀態也分為     b1.自己任務呼叫延時類函式或者等待訊號值類函式的主動改變;    b2.被一個優先順序更高的就緒任務H打斷的被動改變(也就是隻要有優先順序更高的就緒任務,那麼在下一個時鐘節拍到來的的時候,任務H就會剝奪任務1的CPU)。

主動改變的話可以是除執行態之外的任意狀態,被動改變就是任務變為掛起態。

還有一種情況就是當兩個任務的優先順序一樣怎麼辦?這裡使用的是時間片輪轉排程,就要在檔案中使能  OSSchedRoundRobinCfg(DEF_ENABLED,1,&err)  函式,如下圖所示。

 

 

 

 

 

 然後在app.C檔案的初始函式中初始化OSSchedRoundRobinCfg(DEF_ENABLED,1,&err) ,這個1代表1*5ms的時間,意思是相同的最高優先順序時每個任務輪流執行5ms。

例子如下:

#define LED0_TASK_PRIO          4                   //任務優先順序;
#define LED0_STK_SIZE           128                 //任務堆疊大小,實際大小是:128*4位元組
CPU_STK LED0_TASK_STK[LED0_STK_SIZE];               //任務堆疊;
OS_TCB Led0TaskTCB;                                 //任務控制塊;
//宣告任務函式(一般將一個任務寫成一個函式):
void Led0_task(void *p_arg);                        //注:“p_arg”這個引數基本用不上,但必須得寫上

#define LED1_TASK_PRIO          4                   //任務優先順序;
#define LED1_STK_SIZE           128                 //任務堆疊大小,實際大小是:128*4位元組
CPU_STK LED1_TASK_STK[LED1_STK_SIZE];               //任務堆疊;
OS_TCB Led1TaskTCB;                                 //任務控制塊;
//宣告任務函式(一般將一個任務寫成一個函式):
void Led1_task(void *p_arg);                        //注:“p_arg”這個引數基本用不上,但必須得寫上


//任務建立函式,注:一般將其它任務的建立放到一個專門建立任務的函式中;
void start_task(void *p_arg)
{
    OS_ERR err;
    CPU_SR_ALLOC();
    p_arg = p_arg;      //故意使用一下這個引數,否則編譯器會警告說此引數沒有使用

    CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0u
   OSStatTaskCPUUsageInit(&err);      //統計任務
#endif
    
#ifdef CPU_CFG_INT_DIS_MEAS_EN        //如果使能了測量中斷關閉時間
    CPU_IntDisMeasMaxCurReset();
#endif
    
#if    OS_CFG_SCHED_ROUND_ROBIN_EN     //當使用時間片輪轉的時候
    
    //使能時間片輪轉排程功能,時間片長度為:1*5=5ms
    OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);
#endif
    
    OS_CRITICAL_ENTER();            //進入臨界區
    //建立LED0任務:
    OSTaskCreate(   (OS_TCB *)      &Led0TaskTCB,
                    (CPU_CHAR *)    "led0 task",
                    (OS_TASK_PTR)   Led0_task,
                    (void *)        0,
                    (OS_PRIO)       LED0_TASK_PRIO,
                    (CPU_STK *)     &LED0_TASK_STK[0],
                    (CPU_STK_SIZE)  LED0_STK_SIZE/10,
                    (CPU_STK_SIZE)  LED0_STK_SIZE,
                    (OS_MSG_QTY)    0,
                    (OS_TICK)       2,              //時間片長度,啟用時間片輪轉排程時有用,這個引數用來設定此任務時間片長度
                    (void *)        0,
                    (OS_OPT)        OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                    (OS_ERR *)      &err
                );
                 
    //建立LED1任務:
    OSTaskCreate(   (OS_TCB *)      &Led1TaskTCB,
                    (CPU_CHAR *)    "led1 task",
                    (OS_TASK_PTR)   Led1_task,
                    (void *)        0,
                    (OS_PRIO)       LED1_TASK_PRIO,
                    (CPU_STK *)     &LED1_TASK_STK[0],
                    (CPU_STK_SIZE)  LED1_STK_SIZE/10,
                    (CPU_STK_SIZE)  LED1_STK_SIZE,
                    (OS_MSG_QTY)    0,
                    (OS_TICK)       2,              //時間片長度,啟用時間片輪轉排程時有用,這個引數用來設定此任務時間片長度
                    (void *)        0,
                    (OS_OPT)        OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                    (OS_ERR *)      &err
                );
    //OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err);        //掛起"start_task"任務
    OS_CRITICAL_EXIT();    //退出臨界區
    OSTaskDel((OS_TCB *)0,&err);//刪除任務自身;(第一個引數填寫0,就是刪除任務自身,要是填寫別的任務的控制塊,那就是刪除別的任務)
}

&n