1. 程式人生 > 實用技巧 >ucos_ii-任務的掛起、恢復、刪除和建立

ucos_ii-任務的掛起、恢復、刪除和建立

以下內容主要注重應用,對原始碼不做分析,對原始碼有興趣的可參考官方具體文件,相關連結:https://doc.micrium.com/display/ucos/

開發環境:TrueSTUDIO

微控制器:STM32F103VET6(HAL庫)

一、建立一個任務,OSTaskCreate()或OSTaskCreateExt()

建立任務的函式有兩種,後者相較與前者會佔用更多的資源,在確保使用的硬體資源足夠充分的情況下,使用後者會更加方便開發者觀察系統中資源的使用情況。函式原型分別為:

  1、INT8U OSTaskCreate (void(*task)(void*pd),void*pdata, OS_STK *ptos, INT8U prio);

  • task是指向任務程式碼的指標(即所建立的任務函式名);
  • pdata是一個指標,指向一個引數,該引數在任務開始執行時傳遞給它(在建立任務的時候通常傳遞一個0值);
  • ptos是一個指向分配給任務的堆疊頂部的指標(注意:由於其支援具有從高記憶體到低記憶體或從低記憶體到高記憶體Stack增長的處理器,所以在呼叫OSTaskCreate()時,你必須知道Stack是如何增長的,因為你需要將任務的Stack頂傳遞給這些函式,預設是從高到低增長);

  • prio是需要的任務優先順序(要注意最低優先順序)。

  2、INT8U OSTaskCreateExt (void(*task)(void*pd),

void*pdata,OS_STK *ptos, INT8U prio, INT16U id, OS_STK *pbos, INT32U stk_size,void*pext,INT16U opt)。

  這裡只介紹與OSTaskCreate ()不同的地方,因為用的不多,這裡我直接摘錄了官方的原話,有興趣的可以自行了解。

id

establishes a unique identifier for the task being created. This argument has been added for future expansion and is otherwise unused by µC/OS-II. This identifier will allow me to extend µC/OS-II beyond its limit of 64 tasks. For now, simply set the task’s ID to the same value as the task’s priority.

pbos

is a pointer to the task’s bottom-of-stack and this argument is used to perform stack checking.

stk_size

specifies the size of the stack in number of elements. This means that if a stack entry is four bytes wide, then a stk_size of 1000 means that the stack will have 4,000 bytes. Again, this argument is used for stack checking.

pext

is a pointer to a user-supplied data area that can be used to extend theOS_TCBof the task. For example, you can add a name to a task (see Example 3 in Chapter 1), storage for the contents of floating-point registers (see Example 4 in Chapter 1) during a context switch, a port address to trigger an oscilloscope during a context switch, and more.

opt

specifies options toOSTaskCreateExt(), specifying whether stack checking is allowed, whether the stack will be cleared, whether floating-point operations are performed by the task, etc.uCOS_II.Hcontains a list of available options (OS_TASK_OPT_STK_CHK,OS_TASK_OPT_STK_CLR, andOS_TASK_OPT_SAVE_FP). Each option consists of a bit. The option is selected when the bit is set (simply OR the aboveOS_TASK_OPT_???constants).

二、掛起一個任務,OSTaskSuspend()

  任務如果掛起將不會再執行,直到任務恢復,恢復任務只可以可以使用OSTaskResume()恢復;一個任務可以掛起自己或者其他任務。函式的原型為:

  1、INT8U OSTaskSuspend (INT8U prio)。

  • prio是要掛起任務的優先順序(如果指定OS_PRIO_SELF,則呼叫任務將掛起自己,並將發生重新排程)。

三、恢復一個掛起的任務,OSTaskResume()

  恢復用於掛起的任務,函式原型為:

  1、INT8U OSTaskResume (INT8U prio)。

  • prio是要恢復被掛起的任務的優先順序。

四、刪除一個任務,OSTaskDel()

  刪除任務意味著該任務將返回到休眠狀態,任務程式碼不再被呼叫,而不是該任務的程式碼將被刪除。函式原型為:

  1、INT8U OSTaskDel (INT8U prio)。

  • prio要被刪除任務的優先順序。

五、請求刪除一個任務, OSTaskDelReq()

  有時,任務擁有記憶體緩衝區或訊號量等資源。如果另一個任務試圖刪除此任務,則資源不會被釋放,因此會丟失。這將導致記憶體洩漏,這對於任何嵌入式系統都是不可接受的。在這種情況下,你需要以某種方式告訴擁有這些資源的任務在使用這些資源後刪除自己。請求者和要刪除的任務都需要呼叫OSTaskDelReq()。函式原型為:

  1、INT8U OSTaskDelReq (INT8U prio)

  • prio請求要被刪除任務的優先順序。

  2、請求者虛擬碼如下所示:

void RequestorTask (void *pdata)
{
    INT8U err;
  
  
    pdata = pdata;
    for (;;) {
        /* Application code */
        if ('TaskToBeDeleted()' needs to be deleted) {                     (1)
            while (OSTaskDelReq(TASK_TO_DEL_PRIO) != OS_TASK_NOT_EXIST) {  (2)
                OSTimeDly(1);                                              (3)
            }
        }
        /* Application code */                                             (4)
    }
}

  (1)發出請求的任務需要確定什麼條件會導致刪除該任務的請求。換句話說,您的應用程式決定了什麼條件導致這個決定。

  (2)如果需要刪除任務,通過傳遞要刪除任務的優先順序呼叫OSTaskDelReq()。如果要刪除的任務不存在,OSTaskDelReq()返回OS_TASK_NOT_EXIST。如果要刪除的任務已被刪除或尚未建立,則將獲得此值。如果返回值是OS_NO_ERR,則請求已被接受,但任務尚未被刪除。您可能想要等待,直到要刪除的任務實際上刪除了自己。

  (3)您可以通過延遲請求者一段時間來做到這一點。

  (4)當被請求的任務最終刪除自己時,返回值為OS_TASK_NOT_EXIST,迴圈退出。

  3、需要刪除本身的任務的虛擬碼如下所示:

void TaskToBeDeleted (void *pdata)
{
    INT8U err;
  
  
    pdata = pdata;
    for (;;) {
        /* Application code */
        if (OSTaskDelReq(OS_PRIO_SELF) == OS_TASK_DEL_REQ) {                  (1)
            Release any owned resources;                                      (2)
            De-allocate any dynamic memory;
            OSTaskDel(OS_PRIO_SELF);                                          (3)
        } else {
            /* Application code */
        }
    }
}

  (1)當OSTaskDelReq()返回OS_TASK_DEL_REQ給它的呼叫者時,它表明另一個任務請求刪除這個任務。

  (2)和(3)在這種情況下,要刪除的任務釋放所有的資源,並呼叫OSTaskDel(OS_PRIO_SELF)來刪除自己。如前所述,該任務的程式碼實際上並未刪除。只是不排程任務的執行,任務程式碼將不再執行。但是,您可以通過呼叫OSTaskCreate()或OSTaskCreateExt()重新建立該任務。

六、相關程式碼實現

  1、主函式中建立一個起始任務:

/**
  * @brief 主函式
  * @param None
  * @retval None
  */
int  main (void)
{
    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();
    bsp_clk_init();
    CPU_IntDis();                                                /* Disable all interrupts until we are ready to accept them */

    OSInit();                                                   /* Initialize "uC/OS-II, The Real-Time Kernel"              */

    OSTaskCreate (AppTaskStart, 0, &AppTaskStartStk[APP_TASK_START_STK_SIZE - 1], APP_TASK_START_PRIO);

    OSStart();                                                  /* Start multitasking (i.e. give control to uC/OS-II)       */
}

 2、起始任務中建立兩個任務,同時在該任務中通過獲取按鍵值實現任務掛起、恢復和刪除、建立:

/**
  * @brief 起始任務
  * @param None
  * @retval None
  */
static  void  AppTaskStart (void *p_arg)
{
    INT8U err1, err2;
    INT8U status1 = 1, status2 = 1;

    CPU_INT32U  hclk_freq;
    CPU_INT32U  cnts;

   (void)p_arg;

    BSP_Init();                                                 /* Init BSP fncts.                                          */

    CPU_Init();                                                 /* Init CPU name & int. dis. time measuring fncts.          */

    hclk_freq = BSP_CPU_ClkFreq();                              /* Determine SysTick reference freq.                        */
    cnts  = hclk_freq / (CPU_INT32U)OS_TICKS_PER_SEC;           /* Determine nbr SysTick increments in OS_TICKS_PER_SEC.    */
    OS_CPU_SysTickInit(cnts);                                   /* Init uC/OS periodic time src (SysTick).                  */

    Mem_Init();                                                 /* Init Memory Management Module.                           */

    err1 = OSTaskCreate (AppTaskLed1, 0, &AppTaskLed1Stk[APP_TASK_START_STK_SIZE-1], APP_TASK_LED1_PRIO);
    if(err1 == OS_ERR_NONE)
    {
        status1 = 0;
    }
    err2 = OSTaskCreate (AppTaskLed2, 0, &AppTaskLed2Stk[APP_TASK_START_STK_SIZE-1], APP_TASK_LED2_PRIO);
    if(err2 == OS_ERR_NONE)
    {
        status2 = 0;
    }

    while(1)
    {
        if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET)
        {
            if(status1 == 0)
            {
                /* 掛起AppTaskLed1任務 */
                err1 = OSTaskSuspend(APP_TASK_LED1_PRIO);
                if(err1 == OS_ERR_NONE)
                {
                    status1 = 1;
                }
            }

            if(status2 == 1)
            {
                /* 建立刪除的AppTaskLed2任務 */
                err2 = OSTaskCreate (AppTaskLed2, 0, &AppTaskLed2Stk[APP_TASK_START_STK_SIZE-1], APP_TASK_LED2_PRIO);
                if(err2 == OS_ERR_NONE)
                {
                    status2 = 0;
                }
            }
        }
        else if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET)
        {
            if(status1 == 1)
            {
                /* 把掛起的AppTaskLed1任務恢復 */
                err1 = OSTaskResume(APP_TASK_LED1_PRIO);
                if(err1 == OS_ERR_NONE)
                {
                    status1 = 0;
                }
            }

            if(status2 == 0)
            {
                /* 刪除AppTaskLed2任務 */
                err2 = OSTaskDel(APP_TASK_LED2_PRIO);
                if(err2 == OS_ERR_NONE)
                {
                    status2 = 1;
                }
            }
        }

        OSTimeDlyHMSM(0, 0, 0, 100);
    }
}

  3、起始任務建立的兩個任務,這兩個任務是控制led燈閃爍,通過觀察燈閃爍的狀態判斷對應的任務是否被執行掛起、恢復和刪除、建立:

/**
  * @brief led1任務
  * @param None
  * @retval None
  */
static void AppTaskLed1(void *p_arg)
{
    (void)p_arg;

    while(1)
    {
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1);
        OSTimeDlyHMSM(0, 0, 0, 100);
    }
}

/**
  * @brief led2任務
  * @param None
  * @retval None
  */
static void AppTaskLed2(void *p_arg)
{
    (void)p_arg;

    while(1)
    {
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
        OSTimeDlyHMSM(0, 0, 0, 200);
    }
}

#endif