zoukankan      html  css  js  c++  java
  • 时间管理

    延时函数,其实已经是 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
  • 相关阅读:
    修改Putty终端目录(ls命令)显示颜色
    在循环中进行提交的测试
    远程连接Redhat Linux配置
    如何部署Silverlight及Web Service
    SQL2008 的收缩日志
    WPF中DataGrid使用初步
    常用SQL
    DataGridView转datatable
    Ext程序规划入门
    下一代C#里的async和await
  • 原文地址:https://www.cnblogs.com/tianxxl/p/10365475.html
Copyright © 2011-2022 走看看