μC/OS-III---I笔记3---时间管理
时间管理相关函数,其实深入根本的理解就是一些对时间任务相关变量,数据结果进行修改的函数这样方便对应任务查找延时等时间相关的任务有没有到期。前面的时间相关的函数是这些操作的基
1.延时函数 OsTImeDly
函数是一个按时钟节拍定时的延时函数 ,默认是将当前执行的任务延时一定时钟节拍。
OS_OPT_TIME_DLY 此选项为相对延时 比如5S后
OS_OPT_TIME_TIMEOUT 同上
OS_OPT_TIME_MATCH 绝对延时 比如延时到系统开始运行后的一个时钟节拍点
OS_OPT_TIME_PERIODIC 周期延时 与相对延时差不多但是相对长时间周期性延时时更准确一些
void OSTimeDly (OS_TICK dly, OS_OPT opt, 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)0u) { /* Not allowed to call from an ISR */ *p_err = OS_ERR_TIME_DLY_ISR; return; } #endif if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0u) { /* Can't delay when the scheduler is locked */ *p_err = OS_ERR_SCHED_LOCKED; return; } switch (opt) { case OS_OPT_TIME_DLY: case OS_OPT_TIME_TIMEOUT: case OS_OPT_TIME_PERIODIC: if (dly == (OS_TICK)0u) { /* 0 means no delay! */ *p_err = OS_ERR_TIME_ZERO_DLY; return; } break; case OS_OPT_TIME_MATCH: break; default: *p_err = OS_ERR_OPT_INVALID; return; } OS_CRITICAL_ENTER(); OSTCBCurPtr->TaskState = OS_TASK_STATE_DLY; OS_TickListInsert(OSTCBCurPtr, dly, opt, p_err); if (*p_err != OS_ERR_NONE) { OS_CRITICAL_EXIT_NO_SCHED(); return; } OS_RdyListRemove(OSTCBCurPtr); /* Remove current task from ready list */ OS_CRITICAL_EXIT_NO_SCHED(); OSSched(); /* Find next task to run! */ *p_err = OS_ERR_NONE; }
2.OSTimeDlyHMSM
函数是一个按时间定时的延时函数 ,默认是将当前执行的任务延时一段时间。
void OSTimeDlyHMSM (CPU_INT16U hours, CPU_INT16U minutes, CPU_INT16U seconds, CPU_INT32U milli, OS_OPT opt, OS_ERR *p_err) { #if OS_CFG_ARG_CHK_EN > 0u CPU_BOOLEAN opt_invalid; CPU_BOOLEAN opt_non_strict; #endif OS_OPT opt_time; OS_RATE_HZ tick_rate; OS_TICK ticks; 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)0u) { /* Not allowed to call from an ISR */ *p_err = OS_ERR_TIME_DLY_ISR; return; } #endif if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0u) { /* Can't delay when the scheduler is locked */ *p_err = OS_ERR_SCHED_LOCKED; return; } opt_time = opt & OS_OPT_TIME_MASK; /* Retrieve time options only. */ switch (opt_time) { case OS_OPT_TIME_DLY: case OS_OPT_TIME_TIMEOUT: case OS_OPT_TIME_PERIODIC: if (milli == (CPU_INT32U)0u) { /* Make sure we didn't specify a 0 delay */ if (seconds == (CPU_INT16U)0u) { if (minutes == (CPU_INT16U)0u) { if (hours == (CPU_INT16U)0u) { *p_err = OS_ERR_TIME_ZERO_DLY; return; } } } } break; case OS_OPT_TIME_MATCH: break; default: *p_err = OS_ERR_OPT_INVALID; return; } #if OS_CFG_ARG_CHK_EN > 0u /* Validate arguments to be within range */ opt_invalid = DEF_BIT_IS_SET_ANY(opt, ~OS_OPT_TIME_OPTS_MASK); if (opt_invalid == DEF_YES) { *p_err = OS_ERR_OPT_INVALID; return; } opt_non_strict = DEF_BIT_IS_SET(opt, OS_OPT_TIME_HMSM_NON_STRICT); if (opt_non_strict != DEF_YES) { if (milli > (CPU_INT32U)999u) { *p_err = OS_ERR_TIME_INVALID_MILLISECONDS; return; } if (seconds > (CPU_INT16U)59u) { *p_err = OS_ERR_TIME_INVALID_SECONDS; return; } if (minutes > (CPU_INT16U)59u) { *p_err = OS_ERR_TIME_INVALID_MINUTES; return; } if (hours > (CPU_INT16U)99u) { *p_err = OS_ERR_TIME_INVALID_HOURS; return; } } else { if (minutes > (CPU_INT16U)9999u) { *p_err = OS_ERR_TIME_INVALID_MINUTES; return; } if (hours > (CPU_INT16U)999u) { *p_err = OS_ERR_TIME_INVALID_HOURS; return; } } #endif /* Compute the total number of clock ticks required.. */ /* .. (rounded to the nearest tick) */ tick_rate = OSCfg_TickRate_Hz; ticks = ((OS_TICK)hours * (OS_TICK)3600u + (OS_TICK)minutes * (OS_TICK)60u + (OS_TICK)seconds) * tick_rate + (tick_rate * ((OS_TICK)milli + (OS_TICK)500u / tick_rate)) / (OS_TICK)1000u; if (ticks > (OS_TICK)0u) { OS_CRITICAL_ENTER(); OSTCBCurPtr->TaskState = OS_TASK_STATE_DLY; OS_TickListInsert(OSTCBCurPtr, ticks, opt_time, p_err); if (*p_err != OS_ERR_NONE) { OS_CRITICAL_EXIT_NO_SCHED(); return; } OS_RdyListRemove(OSTCBCurPtr); /* Remove current task from ready list */ OS_CRITICAL_EXIT_NO_SCHED(); OSSched(); /* Find next task to run! */ *p_err = OS_ERR_NONE; } else { *p_err = OS_ERR_TIME_ZERO_DLY; } }
3.任务插入节拍列表操作
void OS_TickListInsert (OS_TCB *p_tcb, OS_TICK time, OS_OPT opt, OS_ERR *p_err) { OS_TICK tick_delta; OS_TICK tick_next; OS_TICK_SPOKE *p_spoke; OS_TCB *p_tcb0; OS_TCB *p_tcb1; OS_TICK_SPOKE_IX spoke; if (opt == OS_OPT_TIME_MATCH) { /* Task time is absolute. */ tick_delta = time - OSTickCtr - 1u; if (tick_delta > OS_TICK_TH_RDY) { /* If delay already occurred, ... */ p_tcb->TickCtrMatch = (OS_TICK )0u; p_tcb->TickRemain = (OS_TICK )0u; p_tcb->TickSpokePtr = (OS_TICK_SPOKE *)0; *p_err = OS_ERR_TIME_ZERO_DLY; /* ... do NOT delay. */ return; } p_tcb->TickCtrMatch = time; p_tcb->TickRemain = tick_delta + 1u; } else if (time > (OS_TICK)0u) { if (opt == OS_OPT_TIME_PERIODIC) { /* Task time is periodic. */ tick_next = p_tcb->TickCtrPrev + time; tick_delta = tick_next - OSTickCtr - 1u; if (tick_delta < time) { /* If next periodic delay did NOT already occur, ... */ p_tcb->TickCtrMatch = tick_next; /* ... set next periodic delay; ... */ } else { p_tcb->TickCtrMatch = OSTickCtr + time; /* ... else reset periodic delay. */ } p_tcb->TickRemain = p_tcb->TickCtrMatch - OSTickCtr; p_tcb->TickCtrPrev = p_tcb->TickCtrMatch; } else { /* Task time is relative to current. */ p_tcb->TickCtrMatch = OSTickCtr + time; p_tcb->TickRemain = time; } } else { /* Zero time delay; ... */ p_tcb->TickCtrMatch = (OS_TICK )0u; p_tcb->TickRemain = (OS_TICK )0u; p_tcb->TickSpokePtr = (OS_TICK_SPOKE *)0; *p_err = OS_ERR_TIME_ZERO_DLY; /* ... do NOT delay. */ return; } spoke = (OS_TICK_SPOKE_IX)(p_tcb->TickCtrMatch % OSCfg_TickWheelSize); p_spoke = &OSCfg_TickWheel[spoke]; if (p_spoke->NbrEntries == (OS_OBJ_QTY)0u) { /* First entry in the spoke */ p_tcb->TickNextPtr = (OS_TCB *)0; p_tcb->TickPrevPtr = (OS_TCB *)0; p_spoke->FirstPtr = p_tcb; p_spoke->NbrEntries = (OS_OBJ_QTY)1u; } else { p_tcb1 = p_spoke->FirstPtr; /* Point to current first TCB in the list */ while (p_tcb1 != (OS_TCB *)0) { p_tcb1->TickRemain = p_tcb1->TickCtrMatch /* Compute time remaining of current TCB in list */ - OSTickCtr; if (p_tcb->TickRemain > p_tcb1->TickRemain) { /* Do we need to insert AFTER current TCB in list? */ if (p_tcb1->TickNextPtr != (OS_TCB *)0) { /* Yes, are we pointing at the last TCB in the list? */ p_tcb1 = p_tcb1->TickNextPtr; /* No, Point to next TCB in the list */ } else { p_tcb->TickNextPtr = (OS_TCB *)0; p_tcb->TickPrevPtr = p_tcb1; p_tcb1->TickNextPtr = p_tcb; /* Yes, TCB to add is now new last entry in the list */ p_tcb1 = (OS_TCB *)0; /* Break loop */ } } else { /* Insert before the current TCB */ if (p_tcb1->TickPrevPtr == (OS_TCB *)0) { /* Are we inserting before the first TCB? */ p_tcb->TickPrevPtr = (OS_TCB *)0; p_tcb->TickNextPtr = p_tcb1; p_tcb1->TickPrevPtr = p_tcb; p_spoke->FirstPtr = p_tcb; } else { /* Insert in between 2 TCBs already in the list */ p_tcb0 = p_tcb1->TickPrevPtr; p_tcb->TickPrevPtr = p_tcb0; p_tcb->TickNextPtr = p_tcb1; p_tcb0->TickNextPtr = p_tcb; p_tcb1->TickPrevPtr = p_tcb; } p_tcb1 = (OS_TCB *)0; /* Break loop */ } } p_spoke->NbrEntries++; } if (p_spoke->NbrEntriesMax < p_spoke->NbrEntries) { /* Keep track of maximum # of entries in each spoke */ p_spoke->NbrEntriesMax = p_spoke->NbrEntries; } p_tcb->TickSpokePtr = p_spoke; /* Link back to tick spoke */ *p_err = OS_ERR_NONE; }
4.取消任务延时
#if OS_CFG_TIME_DLY_RESUME_EN > 0u void OSTimeDlyResume (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)0u) { /* Not allowed to call from an ISR */ *p_err = OS_ERR_TIME_DLY_RESUME_ISR; return; } #endif #if OS_CFG_ARG_CHK_EN > 0u if (p_tcb == (OS_TCB *)0) { /* Not possible for the running task to be delayed! */ *p_err = OS_ERR_TASK_NOT_DLY; return; } #endif CPU_CRITICAL_ENTER(); if (p_tcb == OSTCBCurPtr) { /* Not possible for the running task to be delayed! */ *p_err = OS_ERR_TASK_NOT_DLY; CPU_CRITICAL_EXIT(); return; } switch (p_tcb->TaskState) { case OS_TASK_STATE_RDY: /* Cannot Abort delay if task is ready */ CPU_CRITICAL_EXIT(); *p_err = OS_ERR_TASK_NOT_DLY; break; case OS_TASK_STATE_DLY: OS_CRITICAL_ENTER_CPU_EXIT(); p_tcb->TaskState = OS_TASK_STATE_RDY; OS_TickListRemove(p_tcb); /* Remove task from tick list */ OS_RdyListInsert(p_tcb); /* Add to ready list */ OS_CRITICAL_EXIT_NO_SCHED(); *p_err = OS_ERR_NONE; break; case OS_TASK_STATE_PEND: CPU_CRITICAL_EXIT(); *p_err = OS_ERR_TASK_NOT_DLY; break; case OS_TASK_STATE_PEND_TIMEOUT: CPU_CRITICAL_EXIT(); *p_err = OS_ERR_TASK_NOT_DLY; break; case OS_TASK_STATE_SUSPENDED: CPU_CRITICAL_EXIT(); *p_err = OS_ERR_TASK_NOT_DLY; break; case OS_TASK_STATE_DLY_SUSPENDED: OS_CRITICAL_ENTER_CPU_EXIT(); p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; OS_TickListRemove(p_tcb); /* Remove task from tick list */ OS_CRITICAL_EXIT_NO_SCHED(); *p_err = OS_ERR_TASK_SUSPENDED; break; case OS_TASK_STATE_PEND_SUSPENDED: CPU_CRITICAL_EXIT(); *p_err = OS_ERR_TASK_NOT_DLY; break; case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED: CPU_CRITICAL_EXIT(); *p_err = OS_ERR_TASK_NOT_DLY; break; default: CPU_CRITICAL_EXIT(); *p_err = OS_ERR_STATE_INVALID; break; } OSSched(); } #endif
TickList数据结构:
μC/OS在一些变量 的处理上用到了一个技巧:
#ifdef OS_GLOBALS #define OS_EXT #else #define OS_EXT extern #endif
#if OS_CFG_APP_HOOKS_EN > 0u OS_EXT OS_APP_HOOK_TCB OS_AppTaskCreateHookPtr; /* Application hooks */ OS_EXT OS_APP_HOOK_TCB OS_AppTaskDelHookPtr; OS_EXT OS_APP_HOOK_TCB OS_AppTaskReturnHookPtr; OS_EXT OS_APP_HOOK_VOID OS_AppIdleTaskHookPtr; OS_EXT OS_APP_HOOK_VOID OS_AppStatTaskHookPtr; OS_EXT OS_APP_HOOK_VOID OS_AppTaskSwHookPtr; OS_EXT OS_APP_HOOK_VOID OS_AppTimeTickHookPtr; #endif /* IDLE TASK -------------------------------- */ OS_EXT OS_IDLE_CTR OSIdleTaskCtr; OS_EXT OS_TCB OSIdleTaskTCB; /* MISCELLANEOUS ---------------------------- */ OS_EXT OS_NESTING_CTR OSIntNestingCtr; /* Interrupt nesting level */ #ifdef CPU_CFG_INT_DIS_MEAS_EN OS_EXT CPU_TS OSIntDisTimeMax; /* Overall interrupt disable time */ #endif OS_EXT OS_STATE OSRunning; /* Flag indicating that kernel is running */ /* ISR HANDLER TASK ------------------------- */ #if OS_CFG_ISR_POST_DEFERRED_EN > 0u OS_EXT OS_INT_Q *OSIntQInPtr; OS_EXT OS_INT_Q *OSIntQOutPtr; OS_EXT OS_OBJ_QTY OSIntQNbrEntries; OS_EXT OS_OBJ_QTY OSIntQNbrEntriesMax; OS_EXT OS_OBJ_QTY OSIntQOvfCtr; OS_EXT OS_TCB OSIntQTaskTCB; OS_EXT CPU_TS OSIntQTaskTimeMax; #endif
对于声明了OS_GLOBALS的文件内后面的变量就是定义,否则就是声明;