大家好,又见面了,我是你们的朋友全栈君。
一,UCOSII的定时中断
绝大多数的内核要求提供定时中断,以实现延时与超时控制等功能。这个定时中断叫做时钟节拍。时钟的中断子程序ISR和时钟节拍函数OSTimeTick()该函数通知UCOSII,发生了时钟节拍中断。
二,UCOSII系统时钟函数
1,任务延时函数, OSTimeDly(INT16U ticks) 实现申请该服务的任务可以延时一段时间这个系统服务的函数叫做 OSTimeDly(),这段时间的长短是用时钟节拍的数目来确定的。调用该函数会使µC/OS-Ⅱ进行一次任务调度,并且执行下一个优先级最高的就绪态任务。
代码语言:javascript复制void OSTimeDly (INT32U ticks)
{
INT8U y;
#if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0u;
#endif
if (OSIntNesting > 0u)
{ /* See if trying to call from an ISR */
return;
}
if (OSLockNesting > 0u)
{ /* See if called with scheduler locked*/
return;
}
if (ticks > 0u)
{ /* 0 means no delay! */
OS_ENTER_CRITICAL();
y = OSTCBCur->OSTCBY; /* Delay current task */
OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
if (OSRdyTbl[y] == 0u)
{
OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
}
OSTCBCur->OSTCBDly = ticks; /* Load ticks in TCB */
OS_EXIT_CRITICAL();
OS_Sched(); /* Find next task to run! */
}
}
(1)任务调用 OSTimeDly()后,一旦规定的时间期满或者有其它的任务通过调用 OSTimeDlyResume()取消了延时,它就会马上进入就绪状态。
(2)参数分析:ticks:代表的是多少个时钟周期节拍
(3)实现过程: 把相应任务的就绪表中的位图的位置清零。把需要执行的等待节拍进行处理。 最后进行任务调度,寻找下一个这个时刻最高优先级的任务。
(4)在OS_TCB的结构体当中的Ticks填写相应的数字的时候通过OSTimeTick()函数可以把任务从就绪态变为等待的状态
代码语言:javascript复制void OSTimeTick (void)
{
OS_TCB *ptcb;
if (OSRunning == OS_TRUE) {
#if OS_TICK_STEP_EN > 0u
switch (OSTickStepState) { /* Determine whether we need to process a tick */
case OS_TICK_STEP_DIS: /* Yes, stepping is disabled */
step = OS_TRUE;
break;
case OS_TICK_STEP_WAIT: /* No, waiting for uC/OS-View to set ... */
step = OS_FALSE; /* .. OSTickStepState to OS_TICK_STEP_ONCE */
break;
case OS_TICK_STEP_ONCE: /* Yes, process tick once and wait for next ... */
step = OS_TRUE; /* ... step command from uC/OS-View */
OSTickStepState = OS_TICK_STEP_WAIT;
break;
default: /* Invalid case, correct situation */
step = OS_TRUE;
OSTickStepState = OS_TICK_STEP_DIS;
break;
}
if (step == OS_FALSE) { /* Return if waiting for step command */
return;
}
#endif
//此处为此任务运行的核心的代码:
ptcb = OSTCBList; /* Point at first TCB in TCB list */
while (ptcb->OSTCBPrio != OS_TASK_IDLE_PRIO) { /* Go through all TCBs in TCB list */
OS_ENTER_CRITICAL();
if (ptcb->OSTCBDly != 0u) { /* No, Delayed or waiting for event with TO */
ptcb->OSTCBDly--; /* Decrement nbr of ticks to end of delay */
if (ptcb->OSTCBDly == 0u) { /* Check for timeout */
if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {
ptcb->OSTCBStat &= (INT8U)~(INT8U)OS_STAT_PEND_ANY; /* Yes, Clear status flag */
ptcb->OSTCBStatPend = OS_STAT_PEND_TO; /* Indicate PEND timeout */
} else {
ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
}
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { /* Is task suspended? */
OSRdyGrp |= ptcb->OSTCBBitY; /* No, Make ready */
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
}
}
}
ptcb = ptcb->OSTCBNext; /* Point at next TCB in TCB list */
OS_EXIT_CRITICAL();
}
}
}
2,按时分秒延时函数 OSTimeDlyHMSM( INT8U hours, INT8U minutes, INT8U seconds, INT16U milli):
调用 OSTimeDlyHMSM()函数也会使µC/OS-Ⅱ进行一次任务调度,并且执行下一个优先级最高的就绪态任务。任务调用 OSTimeDlyHMSM()后,一旦规定的时间期满或者有其它的任务通过调用 OSTimeDlyResume()取消了延时,它就会马上处于就绪态。只有当该任务在所有就绪态任务中具有最高的优先级时,它才会立即运行。若将时钟频率(OS_TICKS_PER_SEC)设置成 100Hz(10ms),4ms 的延时不会产生任何延时!而 5ms 的延时就等于延时 10ms。µC/OS-Ⅱ支持的延时最长为 65,535 个节拍。要想支持更长时间的延时,OSTimeDlyHMSM()确定了用户想延时多少次超过 65,535 个节拍的数目和剩下的节拍数,超过的节拍数会被分为几次去延时。由于OSTimeDlyHMSM()的具体实现方法,用户不能结束延时调用 OSTimeDlyHMSM()要求延时超过 65535 个节拍的任务。
3,恢复延时的任务:OSTimeDlyResume():把那个全局的时间计数器变量设置为0
代码语言:javascript复制INT8U OSTimeDlyResume (INT8U prio)
{
OS_TCB *ptcb;
if (prio >= OS_LOWEST_PRIO) {
return (OS_ERR_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
ptcb = OSTCBPrioTbl[prio]; /* Make sure that task exist */
if (ptcb == (OS_TCB *)0) {
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_NOT_EXIST); /* The task does not exist */
}
if (ptcb == OS_TCB_RESERVED) {
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_NOT_EXIST); /* The task does not exist */
}
if (ptcb->OSTCBDly == 0u) { /* See if task is delayed */
OS_EXIT_CRITICAL();
return (OS_ERR_TIME_NOT_DLY); /* Indicate that task was not delayed */
}
ptcb->OSTCBDly = 0u; /* 清除任务计数器 */
if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {
ptcb->OSTCBStat &= ~OS_STAT_PEND_ANY; /* Yes, Clear status flag */
ptcb->OSTCBStatPend = OS_STAT_PEND_TO; /* Indicate PEND timeout */
} else {
ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
}
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { /* Is task suspended? */
OSRdyGrp |= ptcb->OSTCBBitY; /* No, Make ready */
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
OS_EXIT_CRITICAL();
OS_Sched(); /* See if this is new highest priority */
} else {
OS_EXIT_CRITICAL(); /* Task may be suspended */
}
return (OS_ERR_NONE);
}
4,让处在延时期的任务结束延时:OSTimeDlyResume( INT8U prio) 延时的任务可以不等待延时期满,而是通过其它任务取消延时来使自己处于就绪态。实际上,OSTimeDlyResume()也可以唤醒正在等待事件。
5,系统时间, OSTimeGet()函数和 OSTimeSet()函数:在访问 OSTime 的时候中断是关掉的。这是因为在大多数 8 位处理器上增加和拷贝一个 32位的数都需要数条指令,这些指令一般都需要一次执行完毕,而不能被中断等因素打断。 无论时钟节拍何时发生, µCOSⅡ会将一个 32 位的计数器加 1。这个计数器在用户调用 OSStart()初始化多任务和 4,294,967,295 个节拍执行完一遍的时候从 0 开始计数。在时钟节拍的频率等于 100Hz 的时候,这个 32 位的计数器每隔 497 天就重新开始计数。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/136895.html原文链接:https://javaforall.cn