要使用 uC/OS 的任务必须先声明任务控制块和创建任务,调用 OSTaskCreate () 函数可以创建一个任务。OSTaskCreate () 函数的信息如下表所示。
OSTaskCreate () 函数的定义位于“os_task.c”:
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(); }
如果使能了 OS_CFG_DBG_EN(位于“os_cfg.h”),创建任务时还会调用 OS_TaskDbgListAdd() 函数将该任务插入到一个任务调试双向列表,是为方便调试所设。
OS_TaskDbgListAdd () 函数的定义位于“os_task.c”:
#if OS_CFG_DBG_EN > 0u void OS_TaskDbgListAdd (OS_TCB *p_tcb) { p_tcb->DbgPrevPtr = (OS_TCB *)0; if (OSTaskDbgListPtr == (OS_TCB *)0) { p_tcb->DbgNextPtr = (OS_TCB *)0; } else { p_tcb->DbgNextPtr = OSTaskDbgListPtr; OSTaskDbgListPtr->DbgPrevPtr = p_tcb; } OSTaskDbgListPtr = p_tcb; }
OSTaskSuspend ()
OSTaskSuspend () 函数用于挂起一个任务,令任务暂停运行。任务可以多次调用OSTaskSuspend() 对任务进行挂起操作,即一个任务被挂起是可以嵌套的,但是想要将任务脱离挂起状态需要调用相应次数的 OSTaskResume() 函数。除空闲任务和延迟提交任务之外,任务可以挂起任何任务。OSTaskSuspend () 函数的信息如下表所示。
OSTaskSuspend () 函数的定义也位于“os_task.c :
#if OS_CFG_TASK_SUSPEND_EN > 0u void OSTaskSuspend (OS_TCB *p_tcb, OS_ERR *p_err) { #ifdef OS_SAFETY_CRITICAL if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return; } #endif #if (OS_CFG_ISR_POST_DEFERRED_EN == 0u) && (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to call from an ISR */ *p_err = OS_ERR_TASK_SUSPEND_ISR; return; } #endif if (p_tcb == &OSIdleTaskTCB) { /* Make sure not suspending the idle task */ *p_err = OS_ERR_TASK_SUSPEND_IDLE; return; } #if OS_CFG_ISR_POST_DEFERRED_EN > 0u if (p_tcb == &OSIntQTaskTCB) { /* Not allowed to suspend the ISR handler task */ *p_err = OS_ERR_TASK_SUSPEND_INT_HANDLER; return; } if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if called from an ISR */ OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_TASK_SUSPEND, /* Post to ISR queue */ (void *)p_tcb, (void *)0, (OS_MSG_SIZE)0, (OS_FLAGS )0, (OS_OPT )0, (CPU_TS )0, (OS_ERR *)p_err); return; } #endif OS_TaskSuspend(p_tcb, p_err); } #endif
其实,不管是否使能了中断延迟发布,最终都是调用 OS_TaskSuspend () 函数挂起任务。只是使能了中断延迟发布的挂起过程会比较曲折,中间会有许多插曲,这是中断管理范畴的内容,留到后面再作介绍。
OS_TaskSuspend () 函数的定义位于“os_task.c”:
#if OS_CFG_TASK_SUSPEND_EN > 0u void OS_TaskSuspend (OS_TCB *p_tcb, OS_ERR *p_err) { CPU_SR_ALLOC(); CPU_CRITICAL_ENTER(); if (p_tcb == (OS_TCB *)0) { /* See if specified to suspend self */ p_tcb = OSTCBCurPtr; } if (p_tcb == OSTCBCurPtr) { if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Can't suspend when the scheduler is locked */ CPU_CRITICAL_EXIT(); *p_err = OS_ERR_SCHED_LOCKED; return; } } *p_err = OS_ERR_NONE; switch (p_tcb->TaskState) { case OS_TASK_STATE_RDY: OS_CRITICAL_ENTER_CPU_EXIT(); p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; p_tcb->SuspendCtr = (OS_NESTING_CTR)1; OS_RdyListRemove(p_tcb); OS_CRITICAL_EXIT_NO_SCHED(); break; case OS_TASK_STATE_DLY: p_tcb->TaskState = OS_TASK_STATE_DLY_SUSPENDED; p_tcb->SuspendCtr = (OS_NESTING_CTR)1; CPU_CRITICAL_EXIT(); break; case OS_TASK_STATE_PEND: p_tcb->TaskState = OS_TASK_STATE_PEND_SUSPENDED; p_tcb->SuspendCtr = (OS_NESTING_CTR)1; CPU_CRITICAL_EXIT(); break; case OS_TASK_STATE_PEND_TIMEOUT: p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED; p_tcb->SuspendCtr = (OS_NESTING_CTR)1; CPU_CRITICAL_EXIT(); break; case OS_TASK_STATE_SUSPENDED: case OS_TASK_STATE_DLY_SUSPENDED: case OS_TASK_STATE_PEND_SUSPENDED: case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: p_tcb->SuspendCtr++; CPU_CRITICAL_EXIT(); break; default: CPU_CRITICAL_EXIT(); *p_err = OS_ERR_STATE_INVALID; return; } OSSched(); } #endif
OSTaskResume ()
与 OSTaskSuspend () 函数相对应,被挂起的任务如果要恢复被挂起前的任务状态,就必须调用 OSTaskResume () 函数解嵌该任务。如果解嵌后任务挂起前套数为 0,就可以恢复被挂起前的任务状态。
OSTaskResume () 函数的定义也位于“os_task.c
#if OS_CFG_TASK_SUSPEND_EN > 0u void OSTaskResume (OS_TCB *p_tcb, OS_ERR *p_err) { CPU_SR_ALLOC(); #ifdef OS_SAFETY_CRITICAL if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return; } #endif #if (OS_CFG_ISR_POST_DEFERRED_EN == 0u) && (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u) if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to call from an ISR */ *p_err = OS_ERR_TASK_RESUME_ISR; return; } #endif CPU_CRITICAL_ENTER(); #if OS_CFG_ARG_CHK_EN > 0u if ((p_tcb == (OS_TCB *)0) || /* We cannot resume 'self' */ (p_tcb == OSTCBCurPtr)) { CPU_CRITICAL_EXIT(); *p_err = OS_ERR_TASK_RESUME_SELF; return; } #endif CPU_CRITICAL_EXIT(); #if OS_CFG_ISR_POST_DEFERRED_EN > 0u if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if called from an ISR */ OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_TASK_RESUME, /* Post to ISR queue */ (void *)p_tcb, (void *)0, (OS_MSG_SIZE)0, (OS_FLAGS )0, (OS_OPT )0, (CPU_TS )0, (OS_ERR *)p_err); return; } #endif OS_TaskResume(p_tcb, p_err); } #endif
其实,不管是否使能了中断延迟发布,最终都是调用 OS_TaskResume () 函数恢复任务。只是使能了中断延迟发布的挂起过程会比较曲折,中间会有许多插曲,这是中断管理范畴的内容,留到后面再作介绍。
OS_TaskResume () 函数的定义位于“os_task.c”:
#if OS_CFG_TASK_SUSPEND_EN > 0u void OS_TaskResume (OS_TCB *p_tcb, OS_ERR *p_err) { CPU_SR_ALLOC(); CPU_CRITICAL_ENTER(); *p_err = OS_ERR_NONE; switch (p_tcb->TaskState) { case OS_TASK_STATE_RDY: case OS_TASK_STATE_DLY: case OS_TASK_STATE_PEND: case OS_TASK_STATE_PEND_TIMEOUT: CPU_CRITICAL_EXIT(); *p_err = OS_ERR_TASK_NOT_SUSPENDED; break; case OS_TASK_STATE_SUSPENDED: OS_CRITICAL_ENTER_CPU_EXIT(); p_tcb->SuspendCtr--; if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) { p_tcb->TaskState = OS_TASK_STATE_RDY; OS_TaskRdy(p_tcb); } OS_CRITICAL_EXIT_NO_SCHED(); break; case OS_TASK_STATE_DLY_SUSPENDED: p_tcb->SuspendCtr--; if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) { p_tcb->TaskState = OS_TASK_STATE_DLY; } CPU_CRITICAL_EXIT(); break; case OS_TASK_STATE_PEND_SUSPENDED: p_tcb->SuspendCtr--; if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) { p_tcb->TaskState = OS_TASK_STATE_PEND; } CPU_CRITICAL_EXIT(); break; case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: p_tcb->SuspendCtr--; if (p_tcb->SuspendCtr == (OS_NESTING_CTR)0) { p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT; } CPU_CRITICAL_EXIT(); break; default: CPU_CRITICAL_EXIT(); *p_err = OS_ERR_STATE_INVALID; return; } OSSched(); } #endif
OSTaskChangePrio ()
在创建任务的时候,可以通过设置参数 prio 来设置任务的优先级。在创建完任务后,还可以通过 OSTaskChangePrio () 函数调整任务的优先级。要使用 OSTaskChangePrio () 函数,还得事先使能 OS_CFG_TASK_CHANGE_PRIO_EN(位于“os_cfg.h”),如下所示。
#define OS_CFG_TASK_CHANGE_PRIO_EN 1u //使能/禁用函数 OSTaskChangePrio()
OSTaskChangePrio () 函数的信息如下所示
OSTaskChangePrio () 函数的定义也位于“os_task.c :
#if OS_CFG_TASK_CHANGE_PRIO_EN > 0u void OSTaskChangePrio (OS_TCB *p_tcb, OS_PRIO prio_new, OS_ERR *p_err) { CPU_BOOLEAN self; CPU_SR_ALLOC(); #ifdef OS_SAFETY_CRITICAL if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); 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_CHANGE_PRIO_ISR; return; } #endif #if OS_CFG_ISR_POST_DEFERRED_EN > 0u if (prio_new == 0) { /* Cannot set to IntQueue Task priority */ *p_err = OS_ERR_PRIO_INVALID; return; } #endif if (prio_new >= (OS_CFG_PRIO_MAX - 1u)) { /* Cannot set to Idle Task priority */ *p_err = OS_ERR_PRIO_INVALID; return; } if (p_tcb == (OS_TCB *)0) { /* See if want to change priority of 'self' */ CPU_CRITICAL_ENTER(); p_tcb = OSTCBCurPtr; CPU_CRITICAL_EXIT(); self = DEF_TRUE; } else { self = DEF_FALSE; } OS_CRITICAL_ENTER(); switch (p_tcb->TaskState) { case OS_TASK_STATE_RDY: OS_RdyListRemove(p_tcb); /* Remove from current priority */ p_tcb->Prio = prio_new; /* Set new task priority */ OS_PrioInsert(p_tcb->Prio); if (self == DEF_TRUE) { OS_RdyListInsertHead(p_tcb); } else { OS_RdyListInsertTail(p_tcb); } break; case OS_TASK_STATE_DLY: /* Nothing to do except change the priority in the OS_TCB */ case OS_TASK_STATE_SUSPENDED: case OS_TASK_STATE_DLY_SUSPENDED: p_tcb->Prio = prio_new; /* Set new task priority */ break; case OS_TASK_STATE_PEND: case OS_TASK_STATE_PEND_TIMEOUT: case OS_TASK_STATE_PEND_SUSPENDED: case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: switch (p_tcb->PendOn) { /* What to do depends on what we are pending on */ case OS_TASK_PEND_ON_TASK_Q: /* Nothing to do except change the priority in the OS_TCB */ case OS_TASK_PEND_ON_TASK_SEM: case OS_TASK_PEND_ON_FLAG: p_tcb->Prio = prio_new; /* Set new task priority */ break; case OS_TASK_PEND_ON_MUTEX: case OS_TASK_PEND_ON_MULTI: case OS_TASK_PEND_ON_Q: case OS_TASK_PEND_ON_SEM: OS_PendListChangePrio(p_tcb, prio_new); break; default: break; } break; default: OS_CRITICAL_EXIT(); *p_err = OS_ERR_STATE_INVALID; return; } OS_CRITICAL_EXIT_NO_SCHED(); OSSched(); /* Run highest priority task ready */ *p_err = OS_ERR_NONE; } #endif
OSTaskDel ()
当任务不再使用时,可以调用 OSTaskDel() 函数删除任务。要使用 OSTaskDel() 函数,还得事先使能 OS_CFG_TASK_SEM_PEND_ABORT_EN(位于“os_cfg.h”)
#define OS_CFG_TASK_DEL_EN 1u //使能/禁用函数 OSTaskDel()
OSTaskDel() 函数的信息如下所示。
OSTaskDel () 函数的定义也位于“os_task.c
#if OS_CFG_TASK_DEL_EN > 0u void OSTaskDel (OS_TCB *p_tcb, OS_ERR *p_err) { CPU_SR_ALLOC(); #ifdef OS_SAFETY_CRITICAL if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return; } #endif #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if trying to delete from ISR */ *p_err = OS_ERR_TASK_DEL_ISR; return; } #endif if (p_tcb == &OSIdleTaskTCB) { /* Not allowed to delete the idle task */ *p_err = OS_ERR_TASK_DEL_IDLE; return; } #if OS_CFG_ISR_POST_DEFERRED_EN > 0u if (p_tcb == &OSIntQTaskTCB) { /* Cannot delete the ISR handler task */ *p_err = OS_ERR_TASK_DEL_INVALID; return; } #endif if (p_tcb == (OS_TCB *)0) { /* Delete 'Self'? */ CPU_CRITICAL_ENTER(); p_tcb = OSTCBCurPtr; /* Yes. */ CPU_CRITICAL_EXIT(); } OS_CRITICAL_ENTER(); switch (p_tcb->TaskState) { case OS_TASK_STATE_RDY: OS_RdyListRemove(p_tcb); break; case OS_TASK_STATE_SUSPENDED: break; case OS_TASK_STATE_DLY: /* Task is only delayed, not on any wait list */ case OS_TASK_STATE_DLY_SUSPENDED: OS_TickListRemove(p_tcb); break; case OS_TASK_STATE_PEND: case OS_TASK_STATE_PEND_SUSPENDED: case OS_TASK_STATE_PEND_TIMEOUT: case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: OS_TickListRemove(p_tcb); switch (p_tcb->PendOn) { /* See what we are pending on */ case OS_TASK_PEND_ON_NOTHING: case OS_TASK_PEND_ON_TASK_Q: /* There is no wait list for these two */ case OS_TASK_PEND_ON_TASK_SEM: break; case OS_TASK_PEND_ON_FLAG: /* Remove from wait list */ case OS_TASK_PEND_ON_MULTI: case OS_TASK_PEND_ON_MUTEX: case OS_TASK_PEND_ON_Q: case OS_TASK_PEND_ON_SEM: OS_PendListRemove(p_tcb); break; default: break; } break; default: OS_CRITICAL_EXIT(); *p_err = OS_ERR_STATE_INVALID; return; } #if OS_CFG_TASK_Q_EN > 0u (void)OS_MsgQFreeAll(&p_tcb->MsgQ); /* Free task's message queue messages */ #endif OSTaskDelHook(p_tcb); /* Call user defined hook */ #if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u) OS_TLS_TaskDel(p_tcb); /* Call TLS hook */ #endif #if OS_CFG_DBG_EN > 0u OS_TaskDbgListRemove(p_tcb); #endif OSTaskQty--; /* One less task being managed */ OS_TaskInitTCB(p_tcb); /* Initialize the TCB to default values */ p_tcb->TaskState = (OS_STATE)OS_TASK_STATE_DEL; /* Indicate that the task was deleted */ OS_CRITICAL_EXIT_NO_SCHED(); *p_err = OS_ERR_NONE; /* See Note #1. */ OSSched(); /* Find new highest priority task */ } #endif
OSSchedRoundRobinCfg ()
当有任务使用相同的优先级的时候,一般需要使用时间片轮转调度。当具有相同优先级的多个任务就绪时,系统会根据分配给它们的时间片轮流调度各个任务运行。要使用时间片轮转调度功能,除了要先使能 OS_CFG_SCHED_ROUND_ROBIN_EN(位于“os_cfg.h”)外,还需调用 OSSchedRoundRobinCfg() 函数使能时间片轮转调度和配置相关指标。OS_CFG_SCHED_ROUND_ROBIN_EN 位于“os_cfg.h”
#define OS_CFG_SCHED_ROUND_ROBIN_EN 1u //使能/禁用时间片轮转调度
OSSchedRoundRobinCfg() 函数的信息如下表所示
OSSchedRoundRobinCfg() 函数的定义位于“os_core.c
#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u void OSSchedRoundRobinCfg (CPU_BOOLEAN en, OS_TICK dflt_time_quanta, OS_ERR *p_err) { CPU_SR_ALLOC(); #ifdef OS_SAFETY_CRITICAL if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return; } #endif CPU_CRITICAL_ENTER(); if (en != DEF_ENABLED) { OSSchedRoundRobinEn = DEF_DISABLED; } else { OSSchedRoundRobinEn = DEF_ENABLED; } if (dflt_time_quanta > (OS_TICK)0) { OSSchedRoundRobinDfltTimeQuanta = dflt_time_quanta; } else { OSSchedRoundRobinDfltTimeQuanta = (OS_TICK)(OSCfg_TickRate_Hz / (OS_RATE_HZ)10); } CPU_CRITICAL_EXIT(); *p_err = OS_ERR_NONE; } #endif
OSSchedRoundRobinYield ()
一个任务也可以主动放弃时间片,当一个任务已经完成要执行的事情后,也可以主动放弃时间片,提前退出运行,让就绪列表(处于就绪状态的同一优先级任务)的下一个任务提前运行。但是,如果就绪列表中只有一个任务,该任务无法放弃时间片。一个任务放弃时间片使用 OSSchedRoundRobinYield () 函数,OSSchedRoundRobinYield () 函数的信息如下表所示
OSSchedRoundRobinYield () 函数的定义位于“os_core.c :
#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u void OSSchedRoundRobinYield (OS_ERR *p_err) { OS_RDY_LIST *p_rdy_list; OS_TCB *p_tcb; CPU_SR_ALLOC(); #ifdef OS_SAFETY_CRITICAL if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return; } #endif #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Can't call this function from an ISR */ *p_err = OS_ERR_YIELD_ISR; return; } #endif if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Can't yield if the scheduler is locked */ *p_err = OS_ERR_SCHED_LOCKED; return; } if (OSSchedRoundRobinEn != DEF_TRUE) { /* Make sure round-robin has been enabled */ *p_err = OS_ERR_ROUND_ROBIN_DISABLED; return; } CPU_CRITICAL_ENTER(); p_rdy_list = &OSRdyList[OSPrioCur]; /* Can't yield if it's the only task at that priority */ if (p_rdy_list->NbrEntries < (OS_OBJ_QTY)2) { CPU_CRITICAL_EXIT(); *p_err = OS_ERR_ROUND_ROBIN_1; return; } OS_RdyListMoveHeadToTail(p_rdy_list); /* Move current OS_TCB to the end of the list */ p_tcb = p_rdy_list->HeadPtr; /* Point to new OS_TCB at head of the list */ if (p_tcb->TimeQuanta == (OS_TICK)0) { /* See if we need to use the default time slice */ p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta; } else { p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta; /* Load time slice counter with new time */ } CPU_CRITICAL_EXIT(); OSSched(); /* Run new task */ *p_err = OS_ERR_NONE; } #endif
OSTaskTimeQuantaSet ()
在创建任务的时候,可以通过设置参数 time_quanta 来设置任务的时间片。在创建完任务后,还可以通过 OSTaskTimeQuantaSet () 函数调整任务的时间片。OSTaskTimeQuantaSet ()函数的信息如下所示
OSTaskTimeQuantaSet () 函数的定义位于“os_task.c”:
#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u void OSTaskTimeQuantaSet (OS_TCB *p_tcb, OS_TICK time_quanta, OS_ERR *p_err) { CPU_SR_ALLOC(); #ifdef OS_SAFETY_CRITICAL if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return; } #endif #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Can't call this function from an ISR */ *p_err = OS_ERR_SET_ISR; return; } #endif CPU_CRITICAL_ENTER(); if (p_tcb == (OS_TCB *)0) { p_tcb = OSTCBCurPtr; } if (time_quanta == 0u) { p_tcb->TimeQuanta = OSSchedRoundRobinDfltTimeQuanta; } else { p_tcb->TimeQuanta = time_quanta; } if (p_tcb->TimeQuanta > p_tcb->TimeQuantaCtr) { p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta; } CPU_CRITICAL_EXIT(); *p_err = OS_ERR_NONE; } #endif
OSTaskRegSet ()
UC/OS-III 允许任务拥有给用户自己使用的任务寄存器。所谓任务寄存器,其实就是在任务的任务控制块里增加一个无符号 32 位整型的数组,用来给用户存放一些任务相关的数据。在 创 建 任 务 时 , 会 将 任 务 寄 存 器 全 部 置 0 。 要 使 用 任 务 寄 存 器 , 还 得 事 先 通 过OS_CFG_TASK_REG_TBL_SIZE(位于“os_cfg.h”)定义任务的任务寄存器数目,如下所示
#define OS_CFG_TASK_REG_TBL_SIZE 1u //定义任务指定的寄存器数目
通过 OSTaskRegSet () 函数可以设置一个任务的任务寄存器的值。OSTaskRegSet () 函数的信息如下所示。
OSTaskRegSet () 函数的定义位于“os_task.c”:
#if OS_CFG_TASK_REG_TBL_SIZE > 0u void OSTaskRegSet (OS_TCB *p_tcb, OS_REG_ID id, OS_REG value, OS_ERR *p_err) { CPU_SR_ALLOC(); #ifdef OS_SAFETY_CRITICAL if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return; } #endif #if OS_CFG_ARG_CHK_EN > 0u if (id >= OS_CFG_TASK_REG_TBL_SIZE) { *p_err = OS_ERR_REG_ID_INVALID; return; } #endif CPU_CRITICAL_ENTER(); if (p_tcb == (OS_TCB *)0) { p_tcb = OSTCBCurPtr; } p_tcb->RegTbl[id] = value; CPU_CRITICAL_EXIT(); *p_err = OS_ERR_NONE; } #endif