os_time.c

来源:互联网 发布:小米笔记本装mac系统 编辑:程序博客网 时间:2024/06/08 13:12

  定位到uCOS-II/Source/os_time.c,该文件是系统时间相关。

  由于嵌入式系统的任务是一个无限循环,而uCOS-II是一个抢占式内核,所以为了能让高优先级的任务不一直独占CPU,应该适当的让出CPU以给其他优先级较低的任务获得CPU得以执行。所谓“让出”即使任务进入延时,在延时期间让出CPU。

1. 延时函数OSTimeDly()

void  OSTimeDly (INT32U ticks){    INT8U      y;#if OS_CRITICAL_METHOD == 3u    /* 临界区保护,需要使用变量cpu_sr */    OS_CPU_SR  cpu_sr = 0u;#endif    if (OSIntNesting > 0u) {    /* OSIntNesting为中断嵌套的层数,表示是在某个ISR调用的 */        return;    }    if (OSLockNesting > 0u) {   /* 加锁时OSLockNesting会大于0 */        return;    }    if (ticks > 0u) {           /* 大于0才是有效延时 */        OS_ENTER_CRITICAL();        y            =  OSTCBCur->OSTCBY;   /* 将当前任务在任务就绪表中标志位非就绪态,让出CPU */        OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;        if (OSRdyTbl[y] == 0u) {            OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;        }        OSTCBCur->OSTCBDly = ticks; /* 延时节拍数存入当前任务的TCB */        OS_EXIT_CRITICAL();         /* 退出临界区 */        OS_Sched();                 /* 当前任务已经处于挂起态,调度后轮到次于当前优先级的就绪任务执行 */    }}

  函数的参数ticks是以系统节拍数为单位的延时时间设置值,延时期间会让出CPU供其他任务使用。一般我们设置硬件tick为10ms产生一次sysytick中断,所以此函数存在缺陷:不能延时小于10ms且延时的时间需是10ms的整数倍。

2. 延时函数OSTimeDlyHMSM()

#if OS_TIME_DLY_HMSM_EN > 0uINT8U  OSTimeDlyHMSM (INT8U   hours,                      INT8U   minutes,                      INT8U   seconds,                      INT16U  ms){    INT32U ticks;    if (OSIntNesting > 0u) {                 return (OS_ERR_TIME_DLY_ISR);    }    if (OSLockNesting > 0u) {        return (OS_ERR_SCHED_LOCKED);    }#if OS_ARG_CHK_EN > 0u      //OS_ARG_CHK_EN为参数检查宏    //hours、minutes、seconds、ms都为0那就不要延时了    if (hours == 0u) {        if (minutes == 0u) {            if (seconds == 0u) {                if (ms == 0u) {                    return (OS_ERR_TIME_ZERO_DLY);                }            }        }    }    //参数合法检查    if (minutes > 59u) {        return (OS_ERR_TIME_INVALID_MINUTES);      }    if (seconds > 59u) {        return (OS_ERR_TIME_INVALID_SECONDS);    }    if (ms > 999u) {        return (OS_ERR_TIME_INVALID_MS);    }#endif    /* 根据输入参数,四舍五入推算tick数 */    ticks = ((INT32U)hours * 3600uL + (INT32U)minutes * 60uL + (INT32U)seconds) * OS_TICKS_PER_SEC          + OS_TICKS_PER_SEC * ((INT32U)ms + 500uL / OS_TICKS_PER_SEC) / 1000uL;    /* 调用上面的延时函数OSTimeDly() */    OSTimeDly(ticks);    return (OS_ERR_NONE);}#endif

  为了能使用日常习惯的方法来使任务延时,uCOS-II还提供了OSTimeDlyHMSM函数,该函数可以指定时分秒、毫秒进行延时。其中OS_TICKS_PER_SEC变量指明每秒钟发生几次systick,1ms产生一次systick,那么1秒就是1000次。

3. 中止任务继续延时函数OSTimeDlyResume()

#if OS_TIME_DLY_RESUME_EN > 0uINT8U  OSTimeDlyResume (INT8U prio){    OS_TCB    *ptcb;#if OS_CRITICAL_METHOD == 3u     OS_CPU_SR  cpu_sr = 0u;#endif    if (prio >= OS_LOWEST_PRIO) {       //参数合法性判断        return (OS_ERR_PRIO_INVALID);    }    OS_ENTER_CRITICAL();                //进入临界区    ptcb = OSTCBPrioTbl[prio];          //从就绪表中取出任务的TCB    if (ptcb == (OS_TCB *)0) {          //为NULL表就绪表中没有此任务        OS_EXIT_CRITICAL();        return (OS_ERR_TASK_NOT_EXIST);     }    if (ptcb == OS_TCB_RESERVED) {      //为OS_TCB_RESERVED表该不存在该任务,任务块ptcb被其他任务占用        OS_EXIT_CRITICAL();        return (OS_ERR_TASK_NOT_EXIST);     }    if (ptcb->OSTCBDly == 0u) {         //为0表示不延时        OS_EXIT_CRITICAL();        return (OS_ERR_TIME_NOT_DLY);       }    ptcb->OSTCBDly = 0u;   /* OSTCBDly被赋值为0,表不再延时 */    //阻塞和挂起的判断:    if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {                  //判断是否是因为等待某事件的到来而延时,不等则说明是        ptcb->OSTCBStat     &= ~OS_STAT_PEND_ANY;              /* 清除挂起标志 */        ptcb->OSTCBStatPend  =  OS_STAT_PEND_TO;               /* 指示不再等待的原因是因为超时  */    } 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);}#endif

  任务调用了OSTimeDly()/OSTimeDlyHMSM()函数,当规定的延时时间超时,或者其他任务调用OSTimeDlyResume()取消其延时,该任务就会进入就绪状态。参数prio用于指定被取消延时的任务的优先级。

  在这里,总结PEND和SUSPEND状态的差别:
  (1) PEND为阻塞之意,任务在PEND过程中会释放CPU资源,其它任务可以得到执行。PEND一般在等待某个事件的出现。SUSPEND为暂停、挂起之意,任务在SUSPEND过程中不释放CPU资源。一般挂起用于程序调试中的条件中断,即出现某个条件的情况下挂起,然后进行单步调试。

  (2) 挂起是一种主动行为,因此恢复也应该主动完成。阻塞是一种被动行为,被阻塞的任务不知道自己什么时候被挂起了,也不知道什么时候能恢复。

  (3) PEND和NOTPEND/PEND_OK/PEND_TO对应

  (4) SUSPEND和RDY对应

4. 读取时间函数OSTimeGet()

#if OS_TIME_GET_SET_EN > 0INT32U  OSTimeGet (void){    INT32U     ticks;#if OS_CRITICAL_METHOD == 3      OS_CPU_SR  cpu_sr = 0;#endif    OS_ENTER_CRITICAL();    ticks = OSTime;    OS_EXIT_CRITICAL();    return (ticks);}#endif

  为了方便,系统定义了一个INT32U类型的全局变量OSTime来记录系统发生的时钟节拍数。OSTime在应用程序中调用的OSStart()时被初始化为0,之后每发生一个时钟节拍,OSTime的值就会被加1。OSTimeGet()的返回OSTimeGet的值。

5. 设置时间函数OSTimeSet()

#if OS_TIME_GET_SET_EN > 0void  OSTimeSet (INT32U ticks){#if OS_CRITICAL_METHOD == 3    OS_CPU_SR  cpu_sr = 0;#endif    OS_ENTER_CRITICAL();    OSTime = ticks;    OS_EXIT_CRITICAL();}#endif

  OSTimeSet()用于设置OSTime的值。

  这5个函数还是比较简单,都是c语言基础,个人觉得关键主要还是在PEND和SUSPEND的理解。

原创粉丝点击