創建任務就是將任務控制塊、任務堆棧、任務代碼等聯繫在一起,並且初始化任務控制塊的相應字段。在UCOSIII中我們通過函數OSTaskCreate ();來創建任務,OSTaskCreate();函數原型如下(在os_task.c中有定義)。創建一個任務之後,剛創建的任務就會進入就緒狀態,注意!不能夠在中斷服務程序中調用OSTaskCreate ();函數創建任務。
創建任務注意一下參數:任務控制塊、任務堆棧、任務優先級、任務函數。
void OSTaskCreate (OS_TCB *p_tcb, CPU_CHAR *p_name, OS_TASK_PTR p_task, void *p_arg, OS_PRIO prio, CPU_STK *p_stk_base, CPU_STK_SIZE stk_limit, CPU_STK_SIZE stk_size, OS_MSG_QTY q_size, OS_TICK time_quanta, void *p_ext, OS_OPT opt, OS_ERR *p_err) { CPU_STK_SIZE i; #if OS_CFG_TASK_REG_TBL_SIZE > 0u OS_REG_ID reg_nbr; #endif #if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) OS_TLS_ID id; #endif CPU_STK *p_sp; CPU_STK *p_stk_limit; CPU_SR_ALLOC(); #ifdef OS_SAFETY_CRITICAL if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return; } #endif #ifdef OS_SAFETY_CRITICAL_IEC61508 if (OSSafetyCriticalStartFlag == DEF_TRUE) { *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME; return; } #endif #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* ---------- CANNOT CREATE A TASK FROM AN ISR ---------- */ *p_err = OS_ERR_TASK_CREATE_ISR; return; } #endif #if OS_CFG_ARG_CHK_EN > 0u /* ---------------- VALIDATE ARGUMENTS ------------------ */ if (p_tcb == (OS_TCB *)0) { /* User must supply a valid OS_TCB */ *p_err = OS_ERR_TCB_INVALID; return; } if (p_task == (OS_TASK_PTR)0) { /* User must supply a valid task */ *p_err = OS_ERR_TASK_INVALID; return; } if (p_stk_base == (CPU_STK *)0) { /* User must supply a valid stack base address */ *p_err = OS_ERR_STK_INVALID; return; } if (stk_size < OSCfg_StkSizeMin) { /* User must supply a valid minimum stack size */ *p_err = OS_ERR_STK_SIZE_INVALID; return; } if (stk_limit >= stk_size) { /* User must supply a valid stack limit */ *p_err = OS_ERR_STK_LIMIT_INVALID; return; } if (prio >= OS_CFG_PRIO_MAX) { /* Priority must be within 0 and OS_CFG_PRIO_MAX-1 */ *p_err = OS_ERR_PRIO_INVALID; return; } #endif #if OS_CFG_ISR_POST_DEFERRED_EN > 0u if (prio == (OS_PRIO)0) { if (p_tcb != &OSIntQTaskTCB) { *p_err = OS_ERR_PRIO_INVALID; /* Not allowed to use priority 0 */ return; } } #endif if (prio == (OS_CFG_PRIO_MAX - 1u)) { if (p_tcb != &OSIdleTaskTCB) { *p_err = OS_ERR_PRIO_INVALID; /* Not allowed to use same priority as idle task */ return; } } OS_TaskInitTCB(p_tcb); /* Initialize the TCB to default values */ *p_err = OS_ERR_NONE; /* --------------- CLEAR THE TASK'S STACK --------------- */ if ((opt & OS_OPT_TASK_STK_CHK) != (OS_OPT)0) { /* See if stack checking has been enabled */ if ((opt & OS_OPT_TASK_STK_CLR) != (OS_OPT)0) { /* See if stack needs to be cleared */ p_sp = p_stk_base; for (i = 0u; i < stk_size; i++) { /* Stack grows from HIGH to LOW memory */ *p_sp = (CPU_STK)0; /* Clear from bottom of stack and up! */ p_sp++; } } } /* ------- INITIALIZE THE STACK FRAME OF THE TASK ------- */ #if (CPU_CFG_STK_GROWTH == CPU_STK_GROWTH_HI_TO_LO) p_stk_limit = p_stk_base + stk_limit; #else p_stk_limit = p_stk_base + (stk_size - 1u) - stk_limit; #endif p_sp = OSTaskStkInit(p_task, p_arg, p_stk_base, p_stk_limit, stk_size, opt); /* -------------- INITIALIZE THE TCB FIELDS ------------- */ p_tcb->TaskEntryAddr = p_task; /* Save task entry point address */ p_tcb->TaskEntryArg = p_arg; /* Save task entry argument */ p_tcb->NamePtr = p_name; /* Save task name */ p_tcb->Prio = prio; /* Save the task's priority */ p_tcb->StkPtr = p_sp; /* Save the new top-of-stack pointer */ p_tcb->StkLimitPtr = p_stk_limit; /* Save the stack limit pointer */ p_tcb->TimeQuanta = time_quanta; /* Save the #ticks for time slice (0 means not sliced) */ #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u if (time_quanta == (OS_TICK)0) { p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta; } else { p_tcb->TimeQuantaCtr = time_quanta; } #endif p_tcb->ExtPtr = p_ext; /* Save pointer to TCB extension */ p_tcb->StkBasePtr = p_stk_base; /* Save pointer to the base address of the stack */ p_tcb->StkSize = stk_size; /* Save the stack size (in number of CPU_STK elements) */ p_tcb->Opt = opt; /* Save task options */ #if OS_CFG_TASK_REG_TBL_SIZE > 0u for (reg_nbr = 0u; reg_nbr < OS_CFG_TASK_REG_TBL_SIZE; reg_nbr++) { p_tcb->RegTbl[reg_nbr] = (OS_REG)0; } #endif #if OS_CFG_TASK_Q_EN > 0u OS_MsgQInit(&p_tcb->MsgQ, /* Initialize the task's message queue */ q_size); #else (void)&q_size; #endif OSTaskCreateHook(p_tcb); /* Call user defined hook */ #if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) for (id = 0u; id < OS_CFG_TLS_TBL_SIZE; id++) { p_tcb->TLS_Tbl[id] = (OS_TLS)0; } OS_TLS_TaskCreate(p_tcb); /* Call TLS hook */ #endif /* --------------- ADD TASK TO READY LIST --------------- */ OS_CRITICAL_ENTER(); OS_PrioInsert(p_tcb->Prio); OS_RdyListInsertTail(p_tcb); #if OS_CFG_DBG_EN > 0u OS_TaskDbgListAdd(p_tcb); #endif OSTaskQty++; /* Increment the #tasks counter */ if (OSRunning != OS_STATE_OS_RUNNING) { /* Return if multitasking has not started */ OS_CRITICAL_EXIT(); return; } OS_CRITICAL_EXIT_NO_SCHED(); OSSched(); }
*p_tcb ------ 任務的控制塊OS_TCB
*p_name ------ 指向任務的名字
p_task ------ 執行任務代碼,也就是任務函數的名字
*p_arg ------ 傳遞給任務的參數
prio ------ 任務優先級,數值越低優先級越高,用戶不能夠使用系統任務使用的那些優先級,
優先級0:中斷服務服務管理任務 OS_IntQTask()
優先級1:時鐘節拍任務 OS_TickTask()優先級2:定時任務 OS_TmrTask()
優先級OS_CFG_PRIO_MAX-2:統計任務 OS_StatTask()
優先級OS_CFG_PRIO_MAX-1:空閒任務 OS_IdleTask()
*p_stk_base ------ 指向任務堆棧的基地址
stk_limit ------ 任務堆棧深度,用來檢測和確保堆棧不溢出
stk_size ------ 任務堆棧大小
q_size COSIII------ 使用任務消息隊列時 任務內部消息隊列能夠接收的最大消息數目,爲0時禁止接收消息
time_quanta ------ 同一優先級下的多個任務是採用時間片輪轉調度。當使能時間片輪轉時的時間片長度,爲0時爲默認長度。在使能時間片輪轉調用時用來設置時間片長度,默認節拍爲時鐘節拍除以10.
*p_ext ------ 指向用戶補充的存儲區。
opt ------ 包含任務的特定選項,有如下選項可以設置。
OS_OPT_TASK_NONE 表示沒有任何選項
OS_OPT_TASK_STK_CHK 指定是否允許檢測該任務的堆棧
OS_OPT_TASK_STK_CLR 指定是否清除該任務的堆棧
OS_OPT_TASK_SAVE_FP 指定是否存浮點寄存器,CPU需要浮點運算硬件並且有專用代碼保護浮點 寄存器
*p_err ------ 用來保存調用該函數後返回的錯誤代碼。