Presentation is loading. Please wait.

Presentation is loading. Please wait.

UcOS-II时间管理.

Similar presentations


Presentation on theme: "UcOS-II时间管理."— Presentation transcript:

1 ucOS-II时间管理

2 与时钟节拍有关的系统服务 μC/OS-Ⅱ(其它内核也一样)要求用户提供定时中断来实现延时与超时控制等功能。
这个定时中断叫做时钟节拍,它应该每秒发生10至100次,时钟节拍的实际频率是由用户的应用程序决定的。时钟节拍的频率越高,系统的负荷就越重。 五个与时钟节拍有关的系统服务(见OS_TIME.C文件): OSTimeDly() OSTimeDlyHMSM() OSTimeDlyResume() OSTimeGet() OSTimeSet()

3 任务延时函数OSTimeDly() μC/OS-Ⅱ提供了这样一个系统服务:申请该服务的任务可以延时一段时间,这段时间的长短是用时钟节拍的数目来确定的。 实现这个系统服务的函数叫做OSTimeDly(),调用该函数会使μC/OS-Ⅱ进行一次任务调度,并且执行下一个优先级最高的就绪态任务。 任务调用OSTimeDly()后,一旦规定的时间期满或者有其它的任务通过调用OSTimeDlyResume()取消了延时,它就会马上进入就绪状态。(只有当该任务在所有就绪任务中具有最高的优先级时,它才会立即运行。)

4 OSTimeDly()程序 void OSTimeDly (INT16U ticks) /通过提供延时的时钟节拍数ticks(1 到65535之间),来调用该函数。 { if (ticks > 0) {(1) /如果时钟节拍数ticks为0值,则表明用户不想延时任务,函数会立即返回到调用者。 OS_ENTER_CRITICAL(); if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {(2) /将当前任务从就绪表中移除 OSRdyGrp &= ~OSTCBCur->OSTCBBitY;} OSTCBCur->OSTCBDly = ticks;(3) /将延时节拍数被保存到当前任务的OS_TCB中,并且通过OSTimeTick()每隔一个时钟节拍就减少一个延时节拍数。 OS_EXIT_CRITICAL(); OSSched(); (4) /当任务已经不再处于就绪状态,任务调度程序会执行下一个优先级最高的就绪任务。 } }

5 延时过程分析 如果系统每隔10ms发生一次时钟节拍(100Hz)中断[下图(1)]。
假如用户没有执行其它的中断并且此时中断是开着的,时钟节拍中断服务就会发生[下图(2)]。 如果用户有几个高优先级的任务(HPT)在等待延时期满,它们会接着执行[下图(3)]。 接下来,低优先级任务(LPT)会得到执行的机会,该任务在执行完后马上调用[下图(4)] OSTimeDly(1)。 μC/OS-Ⅱ会使该任务处于休眠状态直至下一个节拍的到来。当下一个节拍到来后,时钟节拍中断服务子程序会执行[下图(5)],但是这一次由于没有高优先级的任务被执行,μC/OS-Ⅱ会立即执行申请延时一个时钟节拍的任务[下图(6)]。 该任务实际的延时少于一个节拍!在负荷很重的系统中,任务甚至有可能会在时钟中断即将发生时调用OSTimeDly(1),在这种情况下,任务几乎没有得到任何延时,因为任务马上又被重新调度了。如果用户的应用程序至少得延时一个节拍,必须要调用OSTimeDly(2),指定延时两个节拍!

6 延时过程分析图

7 按时分秒延时函数OSTimeDlyHMSM()
调用OSTimeDlyHMSM()函数也会使μC/OS-Ⅱ进行一次任务调度,并且执行下一个优先级最高的就绪态任务。 任务调用OSTimeDlyHMSM()后,一旦规定的时间期满或者有其它的任务通过调用OSTimeDlyResume()取消了延时,它就会马上处于就绪态。同样,只有当该任务在所有就绪态任务中具有最高的优先级时,它才会立即运行。

8 OSTimeDlyHMSM()程序 INT8U OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U milli) {INT32U ticks; INT16U loops;   if (hours > 0 || minutes > 0 || seconds > 0 || milli > 0) { (1) /检验参数定义是否为有效的值 if (minutes > 59) {return(OS_TIME_INVALID_MINUTES); } if (seconds > 59) {return (OS_TIME_INVALID_SECONDS);} if (milli > 999) {return (OS_TIME_INVALID_MILLI);}

9 OSTimeDlyHMSM()程序(续)
ticks = (INT32U)hours * 3600L * OS_TICKS_PER_SEC (2) /支持更长时间的延时 + (INT32U)minutes * 60L * OS_TICKS_PER_SEC + (INT32U)seconds * OS_TICKS_PER_SEC + OS_TICKS_PER_SEC * ((INT32U)milli + 500L/OS_TICKS_PER_SEC) / 1000L; (3) /需要延迟的时间所对应的时钟节拍总数(从指定的时间中计算出节拍总数 ) loops = ticks / 65536L; (4) /延时多少次超过65,535个节拍的数目 ticks = ticks % 65536L; (5) /和剩下的节拍数 OSTimeDly(ticks); (6) / OSTimeDlyHMSM()首先考虑剩下的节拍 while (loops > 0) {(7) /若OS_TICKS_PER_SEC的值为100,用户想延时15分钟,则OSTimeDlyHMSM()会延时15x60x100=90,000个时钟。这个延时会被分割成两次32,768个节拍的延时(因为用户只能延时65,535个节拍而不是65536个节拍)和一次24,464个节拍的延时。在这种情况下,OSTimeDlyHMSM()首先考虑剩下的节拍,然后是超过65,535的节拍数 OSTimeDly(32768); (8) OSTimeDly(32768); loops--; } return (OS_NO_ERR); } else {return (OS_TIME_ZERO_DLY); (9) /如果用户没有定义延时,则返回。 } } 例如,若OS_TICKS_PER_SEC的值为100,用户想延时15分钟,则OSTimeDlyHMSM()会延时15x60x100=90,000个时钟。这个延时会被分割成两次32,768个节拍的延时(因为用户只能延时65,535个节拍而不是65536个节拍)和一次24,464个节拍的延时。在这种情况下,OSTimeDlyHMSM()首先考虑剩下的节拍,然后是超过65,535的节拍数[L5.2(7)和(8)](即两个32,768个节拍延时)。

10 让处在延时期的任务结束延时OSTimeDlyResume()

11 恢复正在延时的任务OSTimeDlyResume()程序
INT8U OSTimeDlyResume (INT8U prio) { OS_TCB *ptcb;  if (prio >= OS_LOWEST_PRIO) {(1) /确保指定的任务优先级有效 return (OS_PRIO_INVALID); } OS_ENTER_CRITICAL(); ptcb = (OS_TCB *)OSTCBPrioTbl[prio]; if (ptcb != (OS_TCB *)0) {(2) /确认要结束延时的任务是确实存在的 if (ptcb->OSTCBDly != 0) {(3) /如果任务存在,则检验任务是否在等待延时期满,只要OS_TCB域中的OSTCBDly包含非0值就表明任务正在等待延时期满。 ptcb->OSTCBDly = 0; (4) /通过强制命令OSTCBDly为0来取消延时

12 恢复正在延时的任务OSTimeDlyResume()程序(续)
if (!(ptcb->OSTCBStat & OS_STAT_SUSPEND)) {(5) /任务只有在没被挂起的情况下才能处于就绪状态 OSRdyGrp |= ptcb->OSTCBBitY; (6) /当上面的条件都满足后,任务就会被放在就绪表中 OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; OS_EXIT_CRITICAL(); OSSched(); (7) /调用任务调度程序来看被恢复的任务是否拥有比当前任务更高的优先级,如果是的话则引起任务切换。 } else {OS_EXIT_CRITICAL(); } return (OS_NO_ERR);} else {OS_EXIT_CRITICAL(); return (OS_TIME_NOT_DLY);} } else {OS_EXIT_CRITICAL(); return (OS_TASK_NOT_EXIST);} }

13 系统时间OSTimeGet()和OSTimeSet()
无论时钟节拍何时发生,μC/OS-Ⅱ都会将一个32位的计数器加1。这个计数器在用户调用OSStart()初始化多任务和 (0~4,294,967,295)个节拍执行完一遍时,重新从0开始计数。 当时钟节拍的频率等于100Hz的时候,这个32位的计数器每隔 =497天就重新开始计数。 通过调用OSTimeGet()可以获得该计数器的当前值,也可以通过调用OSTimeSet()来改变该计数器的值。 注意,在访问OSTime的时候中断是关掉的。这是因为在大多数8位处理器上增加和拷贝一个32位的数都需要数条指令,这些指令一般都需要一次执行完毕,而不能被中断等因素打断。

14 得到和改变系统时间OSTimeGet()和OSTimeSet()程序
INT32U OSTimeGet (void) { INT32U ticks;  OS_ENTER_CRITICAL(); ticks = OSTime; OS_EXIT_CRITICAL(); return (ticks); }  void OSTimeSet (INT32U ticks) { OS_ENTER_CRITICAL(); OSTime = ticks; OS_EXIT_CRITICAL(); }


Download ppt "UcOS-II时间管理."

Similar presentations


Ads by Google