延时函数,其实已经是 uC/OS 操作系统时间管理的范畴了。这一章介绍的基本都是一些服务函数
OSTimeDly()
OSTimeDly() 函数用于停止当前任务进行的运行,延时一段时间后再运行。OSTimeDly()函数的信息如下表所示。
OSTimeDly() 函数的定义位于“os_time.c”。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void OSTimeDly (OS_TICK dly, //延时的时钟节拍数 OS_OPT opt, //选项 OS_ERR *p_err) //返回错误类型 { CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必需该宏,该宏声明和定义一个局部变 //量,用于保存关中断前的 CPU 状态寄存器 SR(临界段关中断只需保存SR) //,开中断时将该值还原。 #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) { //如果该延时函数是在中断中被调用 *p_err = OS_ERR_TIME_DLY_ISR; //错误类型为“在中断函数中延时” return; //返回,不执行延时操作 } #endif /* 当调度器被锁时任务不能延时 */ if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0u) { //如果调度器被锁 *p_err = OS_ERR_SCHED_LOCKED; //错误类型为“调度器被锁” return; //返回,不执行延时操作 } switch (opt) { //根据延时选项参数 opt 分类操作 case OS_OPT_TIME_DLY: //如果选择相对时间(从现在起延时多长时间) case OS_OPT_TIME_TIMEOUT: //如果选择超时(实际同上) case OS_OPT_TIME_PERIODIC: //如果选择周期性延时 if (dly == (OS_TICK)0u) { //如果参数 dly 为0(0意味不延时) *p_err = OS_ERR_TIME_ZERO_DLY; //错误类型为“0延时” return; //返回,不执行延时操作 } break; case OS_OPT_TIME_MATCH: //如果选择绝对时间(匹配系统开始运行(OSStart())后的时钟节拍数) 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); //从就绪列表移除当前任务 OS_CRITICAL_EXIT_NO_SCHED(); //退出临界段(无调度) OSSched(); //任务切换 *p_err = OS_ERR_NONE; //错误类型为“无错误” }
OSTimeDly() 函数中,如果函数的实参和调用场合均合法,就会调用 OS_TickListInsert()函数将当前任务插入到节拍列表进行管理,这与上一章所讲的更新节拍列表是对应的。OS_TickListInsert() 函数的定义位于“os_tick.c”。要插入节拍列表的任务的等待时间有个门限 OS_TICK_TH_RDY,该宏为 0Xffff0000。如果以时钟节拍最高频率 1000 Hz 来算,该宏所代表时间都有 49 天(至少数),任务等待这么长的时间在实际应用中是不可能存在的,所以 uC/OS 设置了该门限,凡是超过该门限的等待时间均视为 0 延时,防止恶性等待,浪费资源。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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) { //如果 time 是个绝对时间 tick_delta = time - OSTickCtr - 1u; //计算离到期还有多长时间 if (tick_delta > OS_TICK_TH_RDY) { //如果延时时间超过了门限 p_tcb->TickCtrMatch = (OS_TICK )0u; //将任务的时钟节拍的匹配变量置0 p_tcb->TickRemain = (OS_TICK )0u; //将任务的延时还需时钟节拍数置0 p_tcb->TickSpokePtr = (OS_TICK_SPOKE *)0; //该任务不插入节拍列表 *p_err = OS_ERR_TIME_ZERO_DLY; //错误类型相当于“0延时” return; //返回,不将任务插入节拍列表 } p_tcb->TickCtrMatch = time; //任务等待的匹配点为 OSTickCtr = time p_tcb->TickRemain = tick_delta + 1u; //计算任务离到期还有多长时间 } else if (time > (OS_TICK)0u) { //如果 time > 0 if (opt == OS_OPT_TIME_PERIODIC) { //如果 time 是周期性时间 tick_next = p_tcb->TickCtrPrev + time; //计算任务接下来要匹配的时钟节拍总计数 tick_delta = tick_next - OSTickCtr - 1u; //计算任务离匹配还有个多长时间 if (tick_delta < time) { //如果 p_tcb->TickCtrPrev < OSTickCtr + 1 p_tcb->TickCtrMatch = tick_next; //将 p_tcb->TickCtrPrev + time 设为时钟节拍匹配点 } else { //如果 p_tcb->TickCtrPrev >= OSTickCtr + 1 p_tcb->TickCtrMatch = OSTickCtr + time; //将 OSTickCtr + time 设为时钟节拍匹配点 } p_tcb->TickRemain = p_tcb->TickCtrMatch - OSTickCtr; //计算任务离到期还有多长时间 p_tcb->TickCtrPrev = p_tcb->TickCtrMatch; //保存当前匹配值为下一周期延时用 } else { //如果 time 是相对时间 p_tcb->TickCtrMatch = OSTickCtr + time; //任务等待的匹配点为 OSTickCtr + time p_tcb->TickRemain = time; //计算任务离到期的时间就是 time } } else { //如果 time = 0 p_tcb->TickCtrMatch = (OS_TICK )0u; //将任务的时钟节拍的匹配变量置0 p_tcb->TickRemain = (OS_TICK )0u; //将任务的延时还需时钟节拍数置0 p_tcb->TickSpokePtr = (OS_TICK_SPOKE *)0; //该任务不插入节拍列表 *p_err = OS_ERR_TIME_ZERO_DLY; //错误类型为“0延时” return; //返回,不将任务插入节拍列表 } spoke = (OS_TICK_SPOKE_IX)(p_tcb->TickCtrMatch % OSCfg_TickWheelSize); //使用哈希算法(取余)来决定任务存于数组 p_spoke = &OSCfg_TickWheel[spoke]; //OSCfg_TickWheel的哪个元素(组织一个节拍列表), //与更新节拍列表相对应,可方便查找到期任务。 if (p_spoke->NbrEntries == (OS_OBJ_QTY)0u) { //如果当前节拍列表为空 p_tcb->TickNextPtr = (OS_TCB *)0; //任务中指向节拍列表中下一个任务的指针置空 p_tcb->TickPrevPtr = (OS_TCB *)0; //任务中指向节拍列表中前一个任务的指针置空 p_spoke->FirstPtr = p_tcb; //当前任务被列为该节拍列表的第一个任务 p_spoke->NbrEntries = (OS_OBJ_QTY)1u; //节拍列表中的元素数目为1 } else { //如果当前节拍列表非空 p_tcb1 = p_spoke->FirstPtr; //获取列表中的第一个任务 while (p_tcb1 != (OS_TCB *)0) { //如果该任务存在 p_tcb1->TickRemain = p_tcb1->TickCtrMatch //计算该任务的剩余等待时间 - OSTickCtr; if (p_tcb->TickRemain > p_tcb1->TickRemain) { //如果当前任务的剩余等待时间大于该任务的 if (p_tcb1->TickNextPtr != (OS_TCB *)0) { //如果该任务不是列表的最后一个元素 p_tcb1 = p_tcb1->TickNextPtr; //让当前任务继续与该任务的下一个任务作比较 } else { //如果该任务是列表的最后一个元素 p_tcb->TickNextPtr = (OS_TCB *)0; //当前任务为列表的最后一个元素 p_tcb->TickPrevPtr = p_tcb1; //该任务是当前任务的前一个元素 p_tcb1->TickNextPtr = p_tcb; //当前任务是该任务的后一个元素 p_tcb1 = (OS_TCB *)0; //插入完成,退出 while 循环 } } else { //如果当前任务的剩余等待时间不大于该任务的 if (p_tcb1->TickPrevPtr == (OS_TCB *)0) { //如果该任务是列表的第一个元素 p_tcb->TickPrevPtr = (OS_TCB *)0; //当前任务就作为列表的第一个元素 p_tcb->TickNextPtr = p_tcb1; //该任务是当前任务的后一个元素 p_tcb1->TickPrevPtr = p_tcb; //当前任务是该任务的前一个元素 p_spoke->FirstPtr = p_tcb; //当前任务是列表的第一个元素 } else { //如果该任务也不是是列表的第一个元素 p_tcb0 = p_tcb1->TickPrevPtr; // p_tcb0 暂存该任务的前一个任务 p_tcb->TickPrevPtr = p_tcb0; //该任务的前一个任务作为当前任务的前一个任务 p_tcb->TickNextPtr = p_tcb1; //该任务作为当前任务的后一个任务 p_tcb0->TickNextPtr = p_tcb; // p_tcb0 暂存的任务的下一个任务改为当前任务 p_tcb1->TickPrevPtr = p_tcb; // 该任务的前一个任务也改为当前任务 } p_tcb1 = (OS_TCB *)0; //插入完成,退出 while 循环 } } p_spoke->NbrEntries++; //节拍列表中的元素数目加1 } if (p_spoke->NbrEntriesMax < p_spoke->NbrEntries) { //更新节拍列表的元素数目的最大记录 p_spoke->NbrEntriesMax = p_spoke->NbrEntries; } p_tcb->TickSpokePtr = p_spoke; //记录当前任务存放于哪个节拍列表 *p_err = OS_ERR_NONE; //错误类型为“无错误” }
如果 OSTimeDly() 函数调用 OS_TickListInsert() 函数将当前任务插入节拍列表成功的话,就会调用 OS_RdyListRemove() 函数将当前任务从任务就绪列表中移除,并将系统切换至其他任务。OS_RdyListRemove() 函数属于任务管理范畴,该函数的原理可参考“任务管理”章节。
OSTimeDlyHMSM()
OSTimeDlyHMSM() 函数与 OSTimeDly() 函数的功能类似,也是用于停止当前任务进行的运行,延时一段时间后再运行。但是,用户若要使用 OSTimeDlyHMSM() 函数,得事先将宏 OS_CFG_TIME_DLY_HMSM_EN(位于“os_cfg.h”)设为 1。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* -------------------------- TIME MANAGEMENT -------------------------- */ #define OS_CFG_TIME_DLY_HMSM_EN 1u //使能/禁用 OSTimeDlyHMSM() 函数 #define OS_CFG_TIME_DLY_RESUME_EN 1u //使能/禁用 OSTimeDlyResume() 函数
OSTimeDlyHMSM () 函数的信息如下表所示。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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) { //如果该延时函数是在中断中被调用 *p_err = OS_ERR_TIME_DLY_ISR; //错误类型为“在中断函数中延时” return; //返回,不执行延时操作 } #endif /* 当调度器被锁时任务不能延时 */ if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0u) { //如果调度器被锁 *p_err = OS_ERR_SCHED_LOCKED; //错误类型为“调度器被锁” return; //返回,不执行延时操作 } opt_time = opt & OS_OPT_TIME_MASK; //检测除选项中与延时时间性质有关的位 switch (opt_time) { //根据延时选项参数 opt 分类操作 case OS_OPT_TIME_DLY: //如果选择相对时间(从现在起延时多长时间) case OS_OPT_TIME_TIMEOUT: //如果选择超时(实际同上) case OS_OPT_TIME_PERIODIC: //如果选择周期性延时 if (milli == (CPU_INT32U)0u) { //如果毫秒数为0 if (seconds == (CPU_INT16U)0u) { //如果秒数为0 if (minutes == (CPU_INT16U)0u) { //如果分钟数为0 if (hours == (CPU_INT16U)0u) { //如果小时数为0 *p_err = OS_ERR_TIME_ZERO_DLY; //错误类型为“0延时” return; //返回,不执行延时操作 } } } } break; case OS_OPT_TIME_MATCH: //如果选择绝对时间(把系统开始运行(OSStart()时做为起点) break; default: //如果选项超出范围 *p_err = OS_ERR_OPT_INVALID; //错误类型为“选项非法” return; //返回,不执行延时操作 } #if OS_CFG_ARG_CHK_EN > 0u //如果使能(默认使能)了参数检测功能 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) { //如果选项选择了 OS_OPT_TIME_HMSM_STRICT if (milli > (CPU_INT32U)999u) { //如果毫秒数>999 *p_err = OS_ERR_TIME_INVALID_MILLISECONDS; //错误类型为“毫秒数不可用” return; //返回,不执行延时操作 } if (seconds > (CPU_INT16U)59u) { //如果秒数>59 *p_err = OS_ERR_TIME_INVALID_SECONDS; //错误类型为“秒数不可用” return; //返回,不执行延时操作 } if (minutes > (CPU_INT16U)59u) { //如果分钟数>59 *p_err = OS_ERR_TIME_INVALID_MINUTES; //错误类型为“分钟数不可用” return; //返回,不执行延时操作 } if (hours > (CPU_INT16U)99u) { //如果小时数>99 *p_err = OS_ERR_TIME_INVALID_HOURS; //错误类型为“小时数不可用” return; //返回,不执行延时操作 } } else { //如果选项选择了 OS_OPT_TIME_HMSM_ NON_STRICT if (minutes > (CPU_INT16U)9999u) { //如果分钟数>9999 *p_err = OS_ERR_TIME_INVALID_MINUTES; //错误类型为“分钟数不可用” return; //返回,不执行延时操作 } if (hours > (CPU_INT16U)999u) { //如果小时数>999 *p_err = OS_ERR_TIME_INVALID_HOURS; //错误类型为“小时数不可用” return; //返回,不执行延时操作 } } #endif /*将延时时间转换成时钟节拍数*/ 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) { //如果延时节拍数>0 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); //从就绪列表移除当前任务 OS_CRITICAL_EXIT_NO_SCHED(); //退出临界段(无调度) OSSched(); //任务切换 *p_err = OS_ERR_NONE; //错误类型为“无错误” } else { //如果延时节拍数=0 *p_err = OS_ERR_TIME_ZERO_DLY; //错误类型为“0延时” } }
OSTimeDlyHMSM() 函 数 中 , 如 果 函 数 的 实 参 和 调 用 场 合 均 合 法 , 就 会 调 用OS_TickListInsert() 函数将当前任务插入到节拍列表进行管理。OS_TickListInsert() 函数的原理参考“OSTimeDly()”章节。
如果 OSTimeDlyHMSM() 函数调用 OS_TickListInsert() 函数将当前任务插入节拍列表成功的话,就会调用 OS_RdyListRemove() 函数将当前任务从任务就绪列表中移除,并将系统切换至其他任务。
OSTimeDlyResume()
OSTimeDlyResume () 函数用于直接结束其他任务(非当前任务)的延时。用户若要使用OSTimeDlyResume () 函数,得事先将宏 OS_CFG_TIME_DLY_RESUME_EN(位于“os_cfg.h”)设为 1。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* -------------------------- TIME MANAGEMENT -------------------------- */ #define OS_CFG_TIME_DLY_HMSM_EN 1u //使能/禁用 OSTimeDlyHMSM() 函数 #define OS_CFG_TIME_DLY_RESUME_EN 1u //使能/禁用 OSTimeDlyResume() 函数
OSTimeDlyResume () 函数的信息如下表所示。
OSTimeDlyResume () 函数的定义位于“os_time.c”。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#if OS_CFG_TIME_DLY_RESUME_EN > 0u //如果使能(默认使能)了 OSTimeDlyResume() 函数 void OSTimeDlyResume (OS_TCB *p_tcb, //任务控制块 OS_ERR *p_err) //错误类型 { CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必需该宏,该宏声明和定义一个局部变 //量,用于保存关中断前的 CPU 状态寄存器 SR(临界段关中断只需保存SR) //,开中断时将该值还原。 #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) { //如果函数是在中断中被调用 *p_err = OS_ERR_TIME_DLY_RESUME_ISR; //错误类型为“在中断中结束延时” return; //返回,函数执行不成功 } #endif #if OS_CFG_ARG_CHK_EN > 0u //如果使能(默认使能)了参数检测功能 if (p_tcb == (OS_TCB *)0) { //如果任务为空 *p_err = OS_ERR_TASK_NOT_DLY; //错误类型为“任务不在延时” return; //返回,函数执行不成功 } #endif CPU_CRITICAL_ENTER(); //关中断 if (p_tcb == OSTCBCurPtr) { //如果任务为当前任务 *p_err = OS_ERR_TASK_NOT_DLY; //错误类型为“任务不在延时” CPU_CRITICAL_EXIT(); //开中断 return; //返回,函数执行不成功 } switch (p_tcb->TaskState) { //根据任务的任务状态分类处理 case OS_TASK_STATE_RDY: //如果任务处于就绪状态 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); //将该任务从节拍列表移除 OS_RdyListInsert(p_tcb); //将该任务插入到就绪列表 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); //将该任务从节拍列表移除 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
如果任务的任务状态中包括延时,就调用 OS_TickListRemove() 函数将任务从节拍列表中移除。OS_TickListRemove() 函数的定义位于“os_tick.c”。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void OS_TickListRemove (OS_TCB *p_tcb) //把任务从节拍列表移除 { OS_TICK_SPOKE *p_spoke; OS_TCB *p_tcb1; OS_TCB *p_tcb2; p_spoke = p_tcb->TickSpokePtr; //获取任务位于哪个节拍列表 if (p_spoke != (OS_TICK_SPOKE *)0) { //如果任务的确在节拍列表中 p_tcb->TickRemain = (OS_TICK)0u; //将任务的延时还需时钟节拍数置0 if (p_spoke->FirstPtr == p_tcb) { //如果任务为节拍列表的第一个任务 p_tcb1 = (OS_TCB *)p_tcb->TickNextPtr; //获取任务的后一个任务为 p_tcb1 p_spoke->FirstPtr = p_tcb1; //把 p_tcb1 作为节拍列表的第一个任务 if (p_tcb1 != (OS_TCB *)0) { //如果 p_tcb1 非空 p_tcb1->TickPrevPtr = (OS_TCB *)0; //p_tcb1 前面已不存在任务 } } else { //如果任务不为节拍列表的第一个任务 p_tcb1 = p_tcb->TickPrevPtr; //获取任务的前一个任务为 p_tcb1 p_tcb2 = p_tcb->TickNextPtr; //获取任务的后一个任务为 p_tcb2 p_tcb1->TickNextPtr = p_tcb2; //将 p_tcb2 作为 p_tcb1 的后一个任务 if (p_tcb2 != (OS_TCB *)0) { //如果 p_tcb2 非空 p_tcb2->TickPrevPtr = p_tcb1; //把 p_tcb1 作为 p_tcb2 的前一个任务 } } p_tcb->TickNextPtr = (OS_TCB *)0; //清空任务的后一个任务 p_tcb->TickPrevPtr = (OS_TCB *)0; //清空任务的前一个任务 p_tcb->TickSpokePtr = (OS_TICK_SPOKE *)0; //任务不再属于任何节拍列表 p_tcb->TickCtrMatch = (OS_TICK )0u; //将任务的时钟节拍的匹配变量置0 p_spoke->NbrEntries--; //节拍列表中的元素数目减1 } }
OSTimeGet ()
OSTimeGet () 函数用于获取当前的时钟节拍计数值。OSTimeGet () 函数的信息如下表所示。
OSTimeGet () 函数的定义位于“os_time.c”。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
OS_TICK OSTimeGet (OS_ERR *p_err) //获取当前的时钟节拍计数值 { OS_TICK ticks; CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必需该宏,该宏声明和定义一个局部变 //量,用于保存关中断前的 CPU 状态寄存器 SR(临界段关中断只需保存SR) //,开中断时将该值还原。 #ifdef OS_SAFETY_CRITICAL //如果使能(默认禁用)了安全检测 if (p_err == (OS_ERR *)0) { //如果错误类型实参为空 OS_SAFETY_CRITICAL_EXCEPTION(); //执行安全检测异常函数 return ((OS_TICK)0); //返回0,函数执行不成功 } #endif CPU_CRITICAL_ENTER(); //关中断 ticks = OSTickCtr; //获取当前的时钟节拍计数值 CPU_CRITICAL_EXIT(); //开中断 *p_err = OS_ERR_NONE; //错误类型为“无错误” return (ticks); //返回当前的时钟节拍计数值 }
OSTimeSet ()
OSTimeSet () 函数用于设置当前的时钟节拍计数值。OSTimeSet () 函数的信息如下表所示。
OSTimeSet () 函数的定义位于“os_time.c”。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void OSTimeSet (OS_TICK ticks, //设置当前的时钟节拍计数值 OS_ERR *p_err) //返回错误类型 { CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必需该宏,该宏声明和定义一个局部变 //量,用于保存关中断前的 CPU 状态寄存器 SR(临界段关中断只需保存SR) //,开中断时将该值还原。 #ifdef OS_SAFETY_CRITICAL //如果使能(默认禁用)了安全检测 if (p_err == (OS_ERR *)0) { //如果错误类型实参为空 OS_SAFETY_CRITICAL_EXCEPTION(); //执行安全检测异常函数 return; //返回,函数执行不成功 } #endif CPU_CRITICAL_ENTER(); //关中断 OSTickCtr = ticks; //设置当前的时钟节拍计数值 CPU_CRITICAL_EXIT(); //开中断 *p_err = OS_ERR_NONE; //错误类型为“无错误” }