时间管理

延时函数,其实已经是 uC/OS 操作系统时间管理的范畴了。这一章介绍的基本都是一些服务函数

OSTimeDly()

  OSTimeDly() 函数用于停止当前任务进行的运行,延时一段时间后再运行。OSTimeDly()函数的信息如下表所示。

    OSTimeDly() 函数的定义位于“os_time.c”。 

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;                               //错误类型为“无错误”
}
View Code

  OSTimeDly() 函数中,如果函数的实参和调用场合均合法,就会调用 OS_TickListInsert()函数将当前任务插入到节拍列表进行管理,这与上一章所讲的更新节拍列表是对应的。OS_TickListInsert() 函数的定义位于“os_tick.c”。要插入节拍列表的任务的等待时间有个门限 OS_TICK_TH_RDY,该宏为 0Xffff0000。如果以时钟节拍最高频率 1000 Hz 来算,该宏所代表时间都有 49 天(至少数),任务等待这么长的时间在实际应用中是不可能存在的,所以 uC/OS 设置了该门限,凡是超过该门限的等待时间均视为 0 延时,防止恶性等待,浪费资源。

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;                           //错误类型为“无错误”
}
View Code

  如果 OSTimeDly() 函数调用 OS_TickListInsert() 函数将当前任务插入节拍列表成功的话,就会调用 OS_RdyListRemove() 函数将当前任务从任务就绪列表中移除,并将系统切换至其他任务。OS_RdyListRemove() 函数属于任务管理范畴,该函数的原理可参考“任务管理”章节。 

OSTimeDlyHMSM()

  OSTimeDlyHMSM() 函数与 OSTimeDly() 函数的功能类似,也是用于停止当前任务进行的运行,延时一段时间后再运行。但是,用户若要使用 OSTimeDlyHMSM() 函数,得事先将宏 OS_CFG_TIME_DLY_HMSM_EN(位于“os_cfg.h”)设为 1。 

                                             /* -------------------------- TIME MANAGEMENT -------------------------- */
#define OS_CFG_TIME_DLY_HMSM_EN         1u   //使能/禁用 OSTimeDlyHMSM() 函数
#define OS_CFG_TIME_DLY_RESUME_EN       1u   //使能/禁用 OSTimeDlyResume() 函数
View Code

  OSTimeDlyHMSM () 函数的信息如下表所示。

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延时”
    }
}
View Code

  OSTimeDlyHMSM() 函 数 中 , 如 果 函 数 的 实 参 和 调 用 场 合 均 合 法 , 就 会 调 用OS_TickListInsert() 函数将当前任务插入到节拍列表进行管理。OS_TickListInsert() 函数的原理参考“OSTimeDly()”章节。
如果 OSTimeDlyHMSM() 函数调用 OS_TickListInsert() 函数将当前任务插入节拍列表成功的话,就会调用 OS_RdyListRemove() 函数将当前任务从任务就绪列表中移除,并将系统切换至其他任务。

OSTimeDlyResume() 

  OSTimeDlyResume () 函数用于直接结束其他任务(非当前任务)的延时。用户若要使用OSTimeDlyResume () 函数,得事先将宏 OS_CFG_TIME_DLY_RESUME_EN(位于“os_cfg.h”)设为 1

                                             /* -------------------------- TIME MANAGEMENT -------------------------- */
#define OS_CFG_TIME_DLY_HMSM_EN         1u   //使能/禁用 OSTimeDlyHMSM() 函数
#define OS_CFG_TIME_DLY_RESUME_EN       1u   //使能/禁用 OSTimeDlyResume() 函数
View Code

  OSTimeDlyResume () 函数的信息如下表所示。 

  OSTimeDlyResume () 函数的定义位于“os_time.c”。

#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
View Code

  如果任务的任务状态中包括延时,就调用 OS_TickListRemove() 函数将任务从节拍列表中移除。OS_TickListRemove() 函数的定义位于“os_tick.c”。

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
    }
}
View Code

OSTimeGet ()

  OSTimeGet () 函数用于获取当前的时钟节拍计数值。OSTimeGet () 函数的信息如下表所示。

OSTimeGet () 函数的定义位于“os_time.c”。

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);                     //返回当前的时钟节拍计数值
}
View Code

OSTimeSet ()

  OSTimeSet () 函数用于设置当前的时钟节拍计数值。OSTimeSet () 函数的信息如下表所示。

OSTimeSet () 函数的定义位于“os_time.c”。 

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;            //错误类型为“无错误” 
}
View Code

 

posted @ 2019-02-12 15:47  飞起的小田  阅读(697)  评论(0)    收藏  举报