【UCOSii源码解析】时间管理

系列文章

  1. UCOSii启动流程以及平台相关文件分析
  2. 优先级算法及内核源码分析
  3. 任务管理
  4. 时间管理
  5. 事件控制块
  6. 内存管理
  7. 任务间通讯与同步

在这里插入图片描述

(一)UCOS计时系统

之前就已经讨论过了UCOS主要是依靠system_tick提供系统节拍。

void SysTick_Handler(void)
{	
	if(delay_osrunning==1)						//OS开始跑了,才执行正常的调度处理
	{
		OSIntEnter();							//进入中断
		OSTimeTick();       					//调用ucos的时钟服务程序               
		OSIntExit();       	 					//触发任务切换软中断
	}
}

之前我们一直关注的是第三句OSIntExit();因为这句话触发了底层的PendSV,那么第二句就是和时钟密切相关的函数。

OSTimeTick (void)


void  OSTimeTick (void)
{
    OS_TCB    *ptcb;
#if OS_TICK_STEP_EN > 0u
    BOOLEAN    step;
#endif
#if OS_CRITICAL_METHOD == 3u                               /* Allocate storage for CPU status register     */
    OS_CPU_SR  cpu_sr = 0u;
#endif



#if OS_TIME_TICK_HOOK_EN > 0u
    OSTimeTickHook();                                      /* Call user definable hook                     */
#endif
#if OS_TIME_GET_SET_EN > 0u
    OS_ENTER_CRITICAL();                                   /* Update the 32-bit tick counter               */
    OSTime++;
    OS_EXIT_CRITICAL();
#endif
    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();
        }
    }
}

OSTime++;是这个函数的关键.也就是说UCOS 中通过OSTime去确定已经运行的时间这就引出了下面这两个函数。
+ OSTImeGet()
+ OSTiimeSet()

229 INT32U OSTimeGet (void) //获取当前系统时钟数值
230 {
231 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
232 OS_CPU_SR cpu_sr;
233 #endif
234 INT32U ticks; //定义节拍数
235
236
237 OS_ENTER_CRITICAL(); //关闭中断
238 ticks = OSTime; //获取当前系统时钟数值
239 OS_EXIT_CRITICAL(); //打开中断
240 return (ticks); //返回系统时钟数值
241 }
242 #endif
243
244 /*
245 *********************************************************************************************************
246 * 设置当前系统时钟数值(SET SYSTEM CLOCK)
247 *
248 * 描述: 设置当前系统时钟数值。系统时钟是一个32位的计数器, 记录系统上电后或时钟重新设置后的时钟计数.
249 *
250 * 参数: ticks 要设置的时钟数,单位是时钟节拍数.
251 *
252 * 返回: 无
253 *********************************************************************************************************
254 */
255
256 #if OS_TIME_GET_SET_EN > 0 //允许生成OSTimeSet() 函数代码
257 void OSTimeSet (INT32U ticks) //设置当前系统时钟数值
258 {
259 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
260 OS_CPU_SR cpu_sr;
261 #endif
262
263
264 OS_ENTER_CRITICAL(); //关闭中断
265 OSTime = ticks; //设置当前系统时钟数值为多少个节拍数
266 OS_EXIT_CRITICAL(); //打开中断
267 }
268 #endif

(二)UCOSII延时函数分析

我们只分析

OSTimeDly (INT16U ticks),

INT8U OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U milli)
本质上也就是调用OSTimeDly 。

17 *********************************************************************************************************
18 * 将一个任务延时若干个时钟节拍(DELAY TASK 'n' TICKS (n from 0 to 65535))
19 *
20 * 描述: 将一个任务延时若干个时钟节拍。如果延时时间大于0, 系统将立即进行任务调度. 延时时间的长度
21 * 可从065535个时钟节拍。延时时间0表示不进行延时,函数将立即返回调用者。延时的具体时间依
22 * 赖于系统每秒钟有多少时钟节拍(由文件SO_CFG.H中的常量OS_TICKS_PER_SEC设定)23 *
24 * 附加:调用该函数会使uC/OS-ii进行一次任务调度,并且执行下一个优先级最高的就绪态任务。任务调用
25 * OSTimeDly()后,一旦规定的时间期满或者有其它的任务通过调用OSTimeDlyResume()取消了延时,
26 * 它就会马上进入就绪状态。注意,只有当该任务在所有就绪任务中具有最高的优先级时,它才会立即
27 * 运行。
28 * 参数: ticks 为要延时的时钟节拍数。(一个165535之间的数)
29 *
30 * 返回:31 * 注意: 注意到延时时间0表示不进行延时操作,而立即返回调用者. 为了确保设定的延时时间,建议用户设定
32 * 的时钟节拍数加1。例如,希望延时10个时钟节拍,可设定参数为1133 *********************************************************************************************************
34 */
35 void OSTimeDly (INT16U ticks) //任务延时函数(时钟节拍数)
36 {
37 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
38 OS_CPU_SR cpu_sr;
39 #endif
40
41
42 if (ticks > 0) { //如果延时设定为0值,表示不想对任务延时,返回调用任务
43 OS_ENTER_CRITICAL(); //关闭中断
44 if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {
45 OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
46 }
47 //非0值会使得任务延时函数OSTimeDly()将当前任务从就绪表中移除
48 OSTCBCur->OSTCBDly = ticks; //接着,这个延时节拍数会被保存在当前任务的OS_TCB中
49 OS_EXIT_CRITICAL(); //打开中断
50 OS_Sched(); //既然任务已经不再处于就绪状态,(任务调度)
51 //任务调度程序会执行下一个优先级最高的就绪任务。
52 }
53 }

44 if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {
45 OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
46 }
这段之前讨论优先级的时候就看过了,就是将对应的X,Y位上置零。

我们定位到底48行,他将当前OSTCB块中的OSTCBDly 设置为ticks,就完成了延时!!
为啥嘞??
我猜可能每TICK一次这个当前任务的OSTCBDly 减一

在这里插入图片描述
在OSTimeTick中定位到这一段,和我想的一样,每TICK一下就减一个1,减到0以后就将该优先级的任务恢复到就绪。

(1)参数分析:
ticks:代表的是多少个时钟周期节拍

(2)实现过程:
把相应任务的就绪表中的位图的位置清零。
把需要执行的等待节拍进行处理。
最后进行任务调度,寻找下一个这个时刻最高优先级的任务。

(三)其他函数

INT8U OSTimeDlyResume (INT8U prio)

134 *********************************************************************************************************
135 * 唤醒一个用OSTimeDly()OSTimeDlyHMSM()函数延时的任务(RESUME A DELAYED TASK)
136 *
137 * 描述: 唤醒一个用OSTimeDly()OSTimeDlyHMSM()函数延时的任务
138 * OSTimeDlyResume()函数不能唤醒一个用OSTimeDlyHMSM()延时,且延时时间总计超过65535个时钟节拍的
139 * 任务。例如,如果系统时钟为100Hz,OSTimeDlyResume()不能唤醒延时OSTimeDlyHMSM(01055350)
140 * 或更长时间的任务。
141 * (OSTimeDlyHMSM(01055350)共延时[10 minutes * 60 + (55+0.35)seconds ] * 100 = 65,535次时
142 * 钟节拍---译者注)
143 *
144 * 参数: prio 为指定要唤醒任务的优先级
145 *
146 * 返回: OS_NO_ERR 函数调用成功
147 * OS_PRIO_INVALID 参数指定的优先级大于OS_LOWEST_PRIO
148 * OS_TIME_NOT_DLY 要唤醒的任务不在延时状态
149 * OS_TASK_NOT_EXIST 指定的任务不存在
150 *
151 * 注意:用户不应该用OSTimeDlyResume()去唤醒一个设置了等待超时操作,并且正在等待事件发生的任务。操作的
152 * 结果是使该任务结束等待,除非的确希望这么做。
153 *********************************************************************************************************
154 * uC/OS-ii允许用户结束延时正处于延时期的任务。延时的任务可以不等待延时期满,而是通过其它任务取
155 * 消延时来使自己处于就绪态。这可以通过调用OSTimeDlyResume()和指定要恢复的任务的优先级来完成。
156 * 实际上,OSTimeDlyResume()也可以唤醒正在等待事件(参看任务间的通讯和同步)的任务,虽然这一点并
157 * 没有提到过。在这种情况下,等待事件发生的任务会考虑是否终止等待事件。
158 *  OSTimeDlyResume()的代码如程序,它首先要确保指定的任务优先级有效。接着,OSTimeDlyResume()要确
159 * 认要结束延时的任务是确实存在的。如果任务存在,OSTimeDlyResume()会检验任务是否在等待延时期满。
160 * 只要OS_TCB域中的OSTCBDly包含非0值就表明任务正在等待延时期满,因为任务调用了OSTimeDly()161 * OSTimeDlyHMSM()或其它在第六章中所描述的PEND函数。然后延时就可以通过强制命令OSTCBDly为0来取消
162 * 。延时的任务有可能已被挂起了,这样的话,任务只有在没有被挂起的情况下才能处于就绪状态。当上面
163 * 的条件都满足后,任务就会被放在就绪表中。这时,OSTimeDlyResume()会调用任务调度程序来看被恢复
164 * 的任务是否拥有比当前任务更高的优先级。这会导致任务的切换。
165 *********************************************************************************************************
166 */
168 #if OS_TIME_DLY_RESUME_EN > 0 //允许生成OSTimeDlyResume() 函数代码
169 INT8U OSTimeDlyResume (INT8U prio) //唤醒一个用OSTimeDly()或OSTimeDlyHMSM()函数的任务(优先级)
170 {
171 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
172 OS_CPU_SR cpu_sr;
173 #endif
174 OS_TCB *ptcb; //定义任务控制块优先级表变量
175
176
177 if (prio >= OS_LOWEST_PRIO) { //当任务指针大于等于最低(大)优先级时,确保优先级有效
178 return (OS_PRIO_INVALID); //返回(参数指定的优先级大于OS_LOWEST_PRIO)
179 }
180 OS_ENTER_CRITICAL(); //关闭中断
181 ptcb = (OS_TCB *)OSTCBPrioTbl[prio]; //ptcb = 任务控制块优先级表当前优先级
182 if (ptcb != (OS_TCB *)0) { //确保要结束的延时的任务是确实存在的
183 if (ptcb->OSTCBDly != 0) { //如果任务存在,程序会检验任务是否在等待延时期满,只要任务
184 //控制块的.OSTCBDly域非0值,就表明任务正在等待延时期满,因
185 //为任务调用了OSTimeDly()、OSTimeDlyHMSM()或其它的pend函数
186 ptcb->OSTCBDly = 0; //通过使 .OSTCBDly为0而取消延时
187 if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == 0x00) {
188 //延时的任务有可能已被挂起,然而任务在没有被挂起的情况下,
189 //才能处于就绪态
190 OSRdyGrp |= ptcb->OSTCBBitY;
191 OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
192 //当上面的条件都满足时,任务就会被放在就绪表中
193 OS_EXIT_CRITICAL(); //打开中断
194 OS_Sched(); //任务调度程序会执行下一个优先级最高的就绪任务(任务调度)
195 } else { //不然
196 OS_EXIT_CRITICAL(); //打开中断
197 }
198 return (OS_NO_ERR); //函数调用成功
199 } else { //否则
200 OS_EXIT_CRITICAL(); //打开中断
201 return (OS_TIME_NOT_DLY); //返回(要唤醒的任务不在延时状态)
202 }
203 }
204 OS_EXIT_CRITICAL(); //打开中断
205 return (OS_TASK_NOT_EXIST); //返回(指定的任务不存在)
206 }
207 #endif

这个函数就是将ptcb->OSTCBDly 变成0

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

与光同程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值