软件定时器

  软件定时器是 uC/OS 操作系统的一个内核对象,软件定时器是基于时钟节拍和系统管理创建的软件性定时器,理论上可以创建无限多个,但精准度肯定比硬件定时稍逊一筹。使用硬件定时器往往需要查阅芯片的相关数据手册,比较繁琐,而使用 uC/OS 的软件定时非常方便。
  软件定时器启动之后是由软件定时器任务 OS_TmrTask() 统一管理,在创建软件定时器之前必须先使能软件定时器和配置软件定时器的相关参数。
  软件定时器的使能位于“os_cfg.h”:

                                             /* ------------------------- TIMER MANAGEMENT -------------------------- */
#define OS_CFG_TMR_EN                   1u   //使能/禁用软件定时器

  其有关参数的配置位于“os_cfg_app.h”:

                                                            /* ----------------------- TIMERS ----------------------- */
#define  OS_CFG_TMR_TASK_PRIO             11u               //定时器任务的优先级
#define  OS_CFG_TMR_TASK_RATE_HZ          10u               //定时器的时基 (一般不能大于 OS_CFG_TICK_RATE_HZ )
#define  OS_CFG_TMR_TASK_STK_SIZE        128u               //定时器任务的栈空间大小(单位:CPU_STK)
#define  OS_CFG_TMR_WHEEL_SIZE            17u               // OSCfg_TmrWheel 数组的大小,推荐使用任务总数/4,且为质数

OSTmrCreate ()
  要使用 uC/OS 的软件定时器必须先声明和创建软件定时器,调用 OSTmrCreate () 函数可以创建一个软件定时器。OSTmrCreate () 函数的信息如下表所示。

  OSTmrCreate () 函数的定义位于“os_tmr.c”:

void  OSTmrCreate (OS_TMR               *p_tmr,          //定时器控制块指针
                   CPU_CHAR             *p_name,         //命名定时器,有助于调试
                   OS_TICK               dly,            //初始定时节拍数
                   OS_TICK               period,         //周期定时重载节拍数
                   OS_OPT                opt,            //选项
                   OS_TMR_CALLBACK_PTR   p_callback,     //定时到期时的回调函数
                   void                 *p_callback_arg, //传给回调函数的参数
                   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

#ifdef OS_SAFETY_CRITICAL_IEC61508               //如果使能(默认禁用)了安全关键
    if (OSSafetyCriticalStartFlag == DEF_TRUE) { //如果是在调用 OSSafetyCriticalStart() 后创建该定时器
       *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;  //错误类型为“非法创建内核对象”
        return;                                  //返回,不执行定时操作
    }
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u          //如果使能(默认使能)了中断中非法调用检测
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {  //如果该函数是在中断中被调用
       *p_err = OS_ERR_TMR_ISR;                 //错误类型为“在中断函数中定时”
        return;                                 //返回,不执行定时操作
    }
#endif

#if OS_CFG_ARG_CHK_EN > 0u                          //如果使能(默认使能)了参数检测
    if (p_tmr == (OS_TMR *)0) {                     //如果参数 p_tmr 为空
       *p_err = OS_ERR_OBJ_PTR_NULL;                //错误类型为“定时器对象为空”
        return;                                     //返回,不执行定时操作
    }

    switch (opt) {                                  //根据延时选项参数 opt 分类操作
        case OS_OPT_TMR_PERIODIC:                   //如果选择周期性定时
             if (period == (OS_TICK)0) {            //如果周期重载实参为0
                *p_err = OS_ERR_TMR_INVALID_PERIOD; //错误类型为“周期重载实参无效”
                 return;                            //返回,不执行定时操作
             }
             break;

        case OS_OPT_TMR_ONE_SHOT:                   //如果选择一次性定时
             if (dly == (OS_TICK)0) {               //如果定时初始实参为0
                *p_err = OS_ERR_TMR_INVALID_DLY;    //错误类型为“定时初始实参无效”
                 return;                            //返回,不执行定时操作
             }
             break;

        default:                                    //如果选项超出预期
            *p_err = OS_ERR_OPT_INVALID;            //错误类型为“选项非法”
             return;                                //返回,不执行定时操作
    }
#endif

    OS_CRITICAL_ENTER();         //进入临界段
    p_tmr->State          = (OS_STATE           )OS_TMR_STATE_STOPPED;  //初始化定时器指标
    p_tmr->Type           = (OS_OBJ_TYPE        )OS_OBJ_TYPE_TMR;
    p_tmr->NamePtr        = (CPU_CHAR          *)p_name;
    p_tmr->Dly            = (OS_TICK            )dly;
    p_tmr->Match          = (OS_TICK            )0;
    p_tmr->Remain         = (OS_TICK            )0;
    p_tmr->Period         = (OS_TICK            )period;
    p_tmr->Opt            = (OS_OPT             )opt;
    p_tmr->CallbackPtr    = (OS_TMR_CALLBACK_PTR)p_callback;
    p_tmr->CallbackPtrArg = (void              *)p_callback_arg;
    p_tmr->NextPtr        = (OS_TMR            *)0;
    p_tmr->PrevPtr        = (OS_TMR            *)0;

#if OS_CFG_DBG_EN > 0u           //如果使能(默认使能)了调试代码和变量
    OS_TmrDbgListAdd(p_tmr);     //将该定时添加到定时器双向调试链表
#endif
    OSTmrQty++;                  //定时器个数加1

    OS_CRITICAL_EXIT_NO_SCHED(); //退出临界段(无调度)
   *p_err = OS_ERR_NONE;         //错误类型为“无错误”
}

OSTmrStart ()

  创建完软件定时器后,如果要使用该软件定时器,需要调用 OSTmrStart () 函数启动该软件定时器。OSTmrStart () 函数的信息如下表所示。

  OSTmrCreate () 函数的定义也位于“os_tmr.c”。:

CPU_BOOLEAN  OSTmrStart (OS_TMR  *p_tmr,  //定时器控制块指针
                         OS_ERR  *p_err)  //返回错误类型
{
    OS_ERR       err;
    CPU_BOOLEAN  success; //暂存函数执行结果

#ifdef OS_SAFETY_CRITICAL               //如果使能(默认禁用)了安全检测
    if (p_err == (OS_ERR *)0) {         //如果错误类型实参为空
        OS_SAFETY_CRITICAL_EXCEPTION(); //执行安全检测异常函数
        return (DEF_FALSE);             //返回 DEF_FALSE,不继续执行
    }
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u         //如果使能(默认使能)了中断中非法调用检测
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) { //如果该函数是在中断中被调用
       *p_err = OS_ERR_TMR_ISR;                //错误类型为“在中断函数中定时”
        return (DEF_FALSE);                    //返回 DEF_FALSE,不继续执行
    }
#endif

#if OS_CFG_ARG_CHK_EN > 0u           //如果使能(默认使能)了参数检测
    if (p_tmr == (OS_TMR *)0) {      //如果使能 p_tmr 的实参为空
       *p_err = OS_ERR_TMR_INVALID;  //错误类型为“无效的定时器”
        return (DEF_FALSE);          //返回 DEF_FALSE,不继续执行
    }
#endif

#if OS_CFG_OBJ_TYPE_CHK_EN > 0u           //如果使能(默认使能)了对象类型检测
    if (p_tmr->Type != OS_OBJ_TYPE_TMR) { //如果该定时器的对象类型有误
       *p_err = OS_ERR_OBJ_TYPE;          //错误类型为“对象类型错误”
        return (DEF_FALSE);               //返回 DEF_FALSE,不继续执行
    }
#endif

    OSSchedLock(&err);                            //锁住调度器
    switch (p_tmr->State) {                       //根据定时器的状态分类处理
        case OS_TMR_STATE_RUNNING:                //如果定时器正在运行,则重启
             OS_TmrUnlink(p_tmr);                 //从定时器轮里移除该定时器
             OS_TmrLink(p_tmr, OS_OPT_LINK_DLY);  //将该定时器重新插入到定时器轮
             OSSchedUnlock(&err);                 //解锁调度器
            *p_err   = OS_ERR_NONE;               //错误类型为“无错误”
             success = DEF_TRUE;                  //执行结果暂为 DEF_TRUE
             break;

        case OS_TMR_STATE_STOPPED:                //如果定时器已被停止,则开启
        case OS_TMR_STATE_COMPLETED:              //如果定时器已完成了,则开启
             OS_TmrLink(p_tmr, OS_OPT_LINK_DLY);  //将该定时器重新插入到定时器轮
             OSSchedUnlock(&err);                 //解锁调度器
            *p_err   = OS_ERR_NONE;               //错误类型为“无错误”
             success = DEF_TRUE;                  //执行结果暂为 DEF_TRUE
             break;

        case OS_TMR_STATE_UNUSED:                 //如果定时器未被创建
             OSSchedUnlock(&err);                 //解锁调度器
            *p_err   = OS_ERR_TMR_INACTIVE;       //错误类型为“定时器未激活”
             success = DEF_FALSE;                 //执行结果暂为 DEF_FALSE
             break;

        default:                                  //如果定时器的状态超出预期
             OSSchedUnlock(&err);                 //解锁调度器
            *p_err = OS_ERR_TMR_INVALID_STATE;    //错误类型为“定时器无效”
             success = DEF_FALSE;                 //执行结果暂为 DEF_FALSE
             break;
    }
    return (success);                             //返回执行结果
}

  这里涉及到两个函数,OS_TmrLink() 和 OS_TmrUnlink()。所有的软件定时器是通过定时器轮来实现管理的,定时器轮与时钟节拍列表数组一样,就是有若干个定时器列表组成的数组。OS_TmrLink() 函数是将软件定时器插入到定时器轮的列表,相反 OS_TmrUnlink() 函数是将软件定时器从定时器轮的列表移除。该操作与时钟节拍插入和移除节拍列表类似。

  OS_TmrLink() 函数的定义位于“os_tmr.c :

void  OS_TmrLink (OS_TMR  *p_tmr,  //定时器控制块指针
                  OS_OPT   opt)    //选项
{
    OS_TMR_SPOKE     *p_spoke;
    OS_TMR           *p_tmr0;
    OS_TMR           *p_tmr1;
    OS_TMR_SPOKE_IX   spoke;

    p_tmr->State = OS_TMR_STATE_RUNNING;                           //重置定时器为运行状态
    if (opt == OS_OPT_LINK_PERIODIC) {                             //如果定时器是再次插入
        p_tmr->Match = p_tmr->Period + OSTmrTickCtr;               //匹配时间加个周期重载值
    } else {                                                       //如果定时器是首次插入
        if (p_tmr->Dly == (OS_TICK)0) {                            //如果定时器的 Dly = 0
            p_tmr->Match = p_tmr->Period + OSTmrTickCtr;           //匹配时间加个周期重载值
        } else {                                                   //如果定时器的 Dly != 0
            p_tmr->Match = p_tmr->Dly    + OSTmrTickCtr;           //匹配时间加个 Dly
        }
    }
    spoke  = (OS_TMR_SPOKE_IX)(p_tmr->Match % OSCfg_TmrWheelSize); //通过哈希算法觉得将该定时器
    p_spoke = &OSCfg_TmrWheel[spoke];                              //插入到定时器轮的哪个列表。

    if (p_spoke->FirstPtr ==  (OS_TMR *)0) {                //如果列表为空,
        p_tmr->NextPtr      = (OS_TMR *)0;                  //直接将该定时器作为列表的第一个元素。
        p_tmr->PrevPtr      = (OS_TMR *)0;
        p_spoke->FirstPtr   = p_tmr;
        p_spoke->NbrEntries = 1u;
    } else {                                                //如果列表非空
        p_tmr->Remain  = p_tmr->Match                       //算出定时器 p_tmr 的剩余时间
                       - OSTmrTickCtr;
        p_tmr1         = p_spoke->FirstPtr;                 //取列表的首个元素到 p_tmr1
        while (p_tmr1 != (OS_TMR *)0) {                     //如果 p_tmr1 非空
            p_tmr1->Remain = p_tmr1->Match                  //算出 p_tmr1 的剩余时间
                           - OSTmrTickCtr;
            if (p_tmr->Remain > p_tmr1->Remain) {           //如果 p_tmr 的剩余时间大于 p_tmr1 的
                if (p_tmr1->NextPtr  != (OS_TMR *)0) {      //如果 p_tmr1 后面非空
                    p_tmr1            = p_tmr1->NextPtr;    //取p_tmr1后一个定时器为新的p_tmr1进行下一次循环
                } else {                                    //如果 p_tmr1 后面为空
                    p_tmr->NextPtr    = (OS_TMR *)0;        //将 p_tmr 插到 p_tmr1 的后面,结束循环
                    p_tmr->PrevPtr    =  p_tmr1;
                    p_tmr1->NextPtr   =  p_tmr;
                    p_tmr1            = (OS_TMR *)0;
                }
            } else {                                        //如果 p_tmr 的剩余时间不大于 p_tmr1 的,
                if (p_tmr1->PrevPtr == (OS_TMR *)0) {       //将 p_tmr 插入到 p_tmr1 的前一个,结束循环。
                    p_tmr->PrevPtr    = (OS_TMR *)0;
                    p_tmr->NextPtr    = p_tmr1;
                    p_tmr1->PrevPtr   = p_tmr;
                    p_spoke->FirstPtr = p_tmr;
                } else {
                    p_tmr0            = p_tmr1->PrevPtr;
                    p_tmr->PrevPtr    = p_tmr0;
                    p_tmr->NextPtr    = p_tmr1;
                    p_tmr0->NextPtr   = p_tmr;
                    p_tmr1->PrevPtr   = p_tmr;
                }
                p_tmr1 = (OS_TMR *)0;
            }
        }
        p_spoke->NbrEntries++;                              //列表元素成员数加1
    }
    if (p_spoke->NbrEntriesMax < p_spoke->NbrEntries) {     //更新列表成员数最大值历史记录
        p_spoke->NbrEntriesMax = p_spoke->NbrEntries;
    }
}

OSTmrStop ()

  OSTmrStop () 函数用于停止一个软件定时器。软件定时器被停掉之后可以调用OSTmrStart () 函数重启,但是重启之后定时器是从头计时,而不是接着上次停止的时刻继续计时。OSTmrStop () 函数的信息如下表所示。

  OSTmrStop () 函数的定义也位于“os_tmr.c”。

CPU_BOOLEAN  OSTmrStop (OS_TMR  *p_tmr,          //定时器控制块指针
                        OS_OPT   opt,            //选项
                        void    *p_callback_arg, //传给回调函数的新参数
                        OS_ERR  *p_err)          //返回错误类型
{
    OS_TMR_CALLBACK_PTR  p_fnct;
    OS_ERR               err;
    CPU_BOOLEAN          success;  //暂存函数执行结果

#ifdef OS_SAFETY_CRITICAL                //如果使能(默认禁用)了安全检测
    if (p_err == (OS_ERR *)0) {          //如果错误类型实参为空
        OS_SAFETY_CRITICAL_EXCEPTION();  //执行安全检测异常函数
        return (DEF_FALSE);              //返回 DEF_FALSE,不继续执行
    }
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u         //如果使能(默认使能)了中断中非法调用检测
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) { //如果该函数是在中断中被调用
       *p_err = OS_ERR_TMR_ISR;                //错误类型为“在中断函数中定时”
        return (DEF_FALSE);                    //返回 DEF_FALSE,不继续执行
    }
#endif

#if OS_CFG_ARG_CHK_EN > 0u          //如果使能(默认使能)了参数检测
    if (p_tmr == (OS_TMR *)0) {     //如果使能 p_tmr 的实参为空
       *p_err = OS_ERR_TMR_INVALID; //错误类型为“无效的定时器”
        return (DEF_FALSE);         //返回 DEF_FALSE,不继续执行
    }
#endif

#if OS_CFG_OBJ_TYPE_CHK_EN > 0u            //如果使能(默认使能)了对象类型检测
    if (p_tmr->Type != OS_OBJ_TYPE_TMR) {  //如果该定时器的对象类型有误
       *p_err = OS_ERR_OBJ_TYPE;           //错误类型为“对象类型错误”
        return (DEF_FALSE);                //返回 DEF_FALSE,不继续执行
    }
#endif

    OSSchedLock(&err);                                                   //锁住调度器
    switch (p_tmr->State) {                                              //根据定时器的状态分类处理
        case OS_TMR_STATE_RUNNING:                                       //如果定时器正在运行
             OS_TmrUnlink(p_tmr);                                        //从定时器轮列表里移除该定时器
            *p_err = OS_ERR_NONE;                                        //错误类型为“无错误”
             switch (opt) {                                              //根据选项分类处理
                 case OS_OPT_TMR_CALLBACK:                               //执行回调函数,使用创建定时器时的实参
                      p_fnct = p_tmr->CallbackPtr;                       //取定时器的回调函数
                      if (p_fnct != (OS_TMR_CALLBACK_PTR)0) {            //如果回调函数存在
                        (*p_fnct)((void *)p_tmr, p_tmr->CallbackPtrArg); //使用创建定时器时的实参执行回调函数
                      } else {                                           //如果回调函数不存在
                         *p_err = OS_ERR_TMR_NO_CALLBACK;                //错误类型为“定时器没有回调函数”
                      }
                      break;

                 case OS_OPT_TMR_CALLBACK_ARG:                    //执行回调函数,使用 p_callback_arg 作为实参
                      p_fnct = p_tmr->CallbackPtr;                //取定时器的回调函数
                      if (p_fnct != (OS_TMR_CALLBACK_PTR)0) {     //如果回调函数存在
                        (*p_fnct)((void *)p_tmr, p_callback_arg); //使用 p_callback_arg 作为实参执行回调函数
                      } else {                                    //如果回调函数不存在
                         *p_err = OS_ERR_TMR_NO_CALLBACK;         //错误类型为“定时器没有回调函数”
                      }
                      break;

                 case OS_OPT_TMR_NONE:           //只需停掉定时器
                      break;

                 default:                        //情况超出预期
                     OSSchedUnlock(&err);        //解锁调度器
                    *p_err = OS_ERR_OPT_INVALID; //错误类型为“选项无效”
                     return (DEF_FALSE);         //返回 DEF_FALSE,不继续执行
             }
             OSSchedUnlock(&err);
             success = DEF_TRUE;
             break;

        case OS_TMR_STATE_COMPLETED:            //如果定时器已完成第一次定时
        case OS_TMR_STATE_STOPPED:              //如果定时器已被停止
             OSSchedUnlock(&err);               //解锁调度器
            *p_err   = OS_ERR_TMR_STOPPED;      //错误类型为“定时器已被停止”
             success = DEF_TRUE;                //执行结果暂为 DEF_TRUE
             break;

        case OS_TMR_STATE_UNUSED:               //如果该定时器未被创建过
             OSSchedUnlock(&err);               //解锁调度器
            *p_err   = OS_ERR_TMR_INACTIVE;     //错误类型为“定时器未激活”
             success = DEF_FALSE;               //执行结果暂为 DEF_FALSE
             break;

        default:                                //如果定时器状态超出预期
             OSSchedUnlock(&err);               //解锁调度器
            *p_err   = OS_ERR_TMR_INVALID_STATE;//错误类型为“定时器状态非法”
             success = DEF_FALSE;               //执行结果暂为 DEF_FALSE
             break;
    }
    return (success);                           //返回执行结果
} 

OSTmrDel ()

  OSTmrDel () 函数用于删除一个软件定时器。OSTmrDel () 函数的信息如下表所示。

  OSTmrDel () 函数的定义位于“os_tmr.c”:

#if OS_CFG_TMR_DEL_EN > 0u             //如果使能(默认是嫩)了 OSTmrDel() 函数
CPU_BOOLEAN  OSTmrDel (OS_TMR  *p_tmr, //定时器控制块指针
                       OS_ERR  *p_err) //返回错误类型
{
    OS_ERR       err;
    CPU_BOOLEAN  success;  //暂存函数执行结果

#ifdef OS_SAFETY_CRITICAL               //如果使能(默认禁用)了安全检测
    if (p_err == (OS_ERR *)0) {         //如果错误类型实参为空
        OS_SAFETY_CRITICAL_EXCEPTION(); //执行安全检测异常函数
        return (DEF_FALSE);             //返回 DEF_FALSE,不继续执行
    }
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u          //如果使能(默认使能)了中断中非法调用检测
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {  //如果该函数是在中断中被调用
       *p_err  = OS_ERR_TMR_ISR;                //错误类型为“在中断函数中定时”
        return (DEF_FALSE);                     //返回 DEF_FALSE,不继续执行
    }
#endif

#if OS_CFG_ARG_CHK_EN > 0u          //如果使能(默认使能)了参数检测
    if (p_tmr == (OS_TMR *)0) {     //如果使能 p_tmr 的实参为空
       *p_err = OS_ERR_TMR_INVALID; //错误类型为“无效的定时器”
        return (DEF_FALSE);         //返回 DEF_FALSE,不继续执行
    }
#endif

#if OS_CFG_OBJ_TYPE_CHK_EN > 0u            //如果使能(默认使能)了对象类型检测
    if (p_tmr->Type != OS_OBJ_TYPE_TMR) {  //如果该定时器的对象类型有误
       *p_err = OS_ERR_OBJ_TYPE;           //错误类型为“对象类型错误”
        return (DEF_FALSE);                //返回 DEF_FALSE,不继续执行
    }
#endif

    OSSchedLock(&err);          //锁住调度器
#if OS_CFG_DBG_EN > 0u          //如果使能(默认使能)了调试代码和变量
    OS_TmrDbgListRemove(p_tmr); //将该定时从定时器双向调试链表移除
#endif
    OSTmrQty--;                 //定时器个数减1

    switch (p_tmr->State) {                       //根据定时器的状态分类处理
        case OS_TMR_STATE_RUNNING:                //如果定时器正在运行
             OS_TmrUnlink(p_tmr);                 //从当前定时器轮列表移除定时器
             OS_TmrClr(p_tmr);                    //复位定时器的指标
             OSSchedUnlock(&err);                 //解锁调度器
            *p_err   = OS_ERR_NONE;               //错误类型为“无错误”
             success = DEF_TRUE;                  //执行结果暂为 DEF_TRUE
             break;

        case OS_TMR_STATE_STOPPED:                //如果定时器已被停止
        case OS_TMR_STATE_COMPLETED:              //如果定时器已完成第一次定时
             OS_TmrClr(p_tmr);                    //复位定时器的指标
             OSSchedUnlock(&err);                 //解锁调度器
            *p_err   = OS_ERR_NONE;               //错误类型为“无错误”
             success = DEF_TRUE;                  //执行结果暂为 DEF_TRUE
             break;

        case OS_TMR_STATE_UNUSED:                 //如果定时器已被删除
             OSSchedUnlock(&err);                 //解锁调度器
            *p_err   = OS_ERR_TMR_INACTIVE;       //错误类型为“定时器未激活”
             success = DEF_FALSE;                 //执行结果暂为 DEF_FALSE
             break;

        default:                                  //如果定时器的状态超出预期
             OSSchedUnlock(&err);                 //解锁调度器
            *p_err   = OS_ERR_TMR_INVALID_STATE;  //错误类型为“定时器无效”
             success = DEF_FALSE;                 //执行结果暂为 DEF_FALSE
             break;
    }
    return (success);                             //返回执行结果
}
#endif

原文地址:https://www.cnblogs.com/tianxxl/p/10366940.html

时间: 2024-10-29 16:55:11

软件定时器的相关文章

毫秒,微妙级别软件定时器

单片机开发中,软件定时器是常用的工具.定时执行特定任务和延时功能,都可以用软件定时器实现. 常见的延时函数的实现做法有: 1. 使用空指令进行延时,通过控制空指令的执行次数,进行延时.优点:不需要占用系统外设.缺点:系统运行指定个空指令的时间不稳定,中途出现的中断处理会严重影响计时的精确性. 2.使用单片机的定时器外设,设定特定的时间产生中断,进行计时.优点:计时准确,不受其他中断影响计时.缺点:浪费单片机外设资源,并且延时处理不能嵌套调用,灵活性不够. 这里要介绍的是利用单片机内部的sysTi

实现自己的软件定时器

为什么要实现软件定时器: 在芯片平台上,地址空间也是相当宝贵的,如果保留了更多的硬件定时器的话,就需要更多的地址空间,那么我们能不能作个折中方案呢?答案是肯定的,我们可以使用一个硬件定时器,来模拟实现一个软件定时器,可以满足更多的定时需求,需要注意的一点就是软件定时器精度可能会有稍微误差,因为会涉及到任务调度.锁中断等,在对定时精度要求不高的场景,可以考虑使用软件定时器.Linux内核中的timer_list精度为10ms,这里我们来实现一套精度为1ms的软件定时器(当然可以实现精度为微秒级的,

高效软件定时器的设计

软件定时器在协议栈等很多场景都有广泛的应用,有时候会有大量的定时器同时处于工作状态,它们的超时时间各异,要高效的保证每个定时器都能够较为准确的超时并执行到其回调函数并不是一件易事.本文分析嵌入式实时操作系统Nucleus的定时器方案,它巧妙的管理了一条按照相对时间来排序的双向链表,避免每次tick中断都要遍历链表检查超时和更新剩余时间,实现了一种相当高效的软件定时器. 结构体TM_TCB来表示动态创建的定时器,其定义如下 typedef struct TM_TCB_STRUCT { /*Nucl

软件定时器-闹钟提醒我们该吃饭吃饭,该睡觉睡觉

闹钟提醒我们该吃饭吃饭,该睡觉睡觉 原文地址:http://blog.csdn.net/u011833609/article/details/28862125 softwaretimer.h #ifndef _SOFTWARETIMER_H_ #define _SOFTWARETIMER_H_ typedef enum{z_false = 0, z_true = !z_false} z_bool; typedef unsigned char z_uchar; typedef unsigned c

μC/OS-II中使用软件定时器

在试着将μC/OS-II移植到ARM7芯片(LPC2138)上的过程中,发现使用OSTmrCreate创建的OSTmr始终都不能执行CallbackFunction,OS版本是v2.85,最后是这么解决的. 在文档<uCOS-II-RefMan.PDF>中找到了关于“OSTmrSignal()”这个函数的一段描述: OSTmrSignal() is called either by a task or an ISR to indicate that it’s time to update th

软件定时器osTimerCreate返回NULL

CMSIS-RTOS是对FreeRtos的封装,函数名比較适合纯软件编程. 如今的版本号是1.0.2. id1 = osTimerCreate(osTimer(Timer_1), osTimerOnce, NULL); 可是这个osTimerCreate总是返回0x00000000. 就是创建软件定时器不成功. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/di

OSAL之时间管理,软件定时器链表管理

读源码写作,尊重原创: 本博文根据蓝牙4.0, 协议族版本是1.3.2 OSAL的时钟实现在OSAL_CockBLE.c与OSAL_Clock.h两个文件中.OSAL支持完整的UTC(世界统一时间),以2000年1月1日00:00:00为时间起点,可以精确到年.月.日.时.分.秒的时间值. 背景知识 // number of seconds since 0 hrs, 0 minutes, 0 seconds, on the 1st of January 2000 UTC存储自2000年1月1日开

emWin 2天速成实例教程004_软件定时器(Timer)和位图片动画

备注:(1)打开工程目录下的"Exe\GUISimulationDebug.exe"即可看到效果.(2)看完教程000-005就基本会用emWin做项目,其他章节可以需要时再参考.  emWin的TIMER是一个软件定时器,它以OS_TimeMS变量的值作为定时基准,而OS_TimeMS则通过一个硬件定时器每1ms中断加1,在emWin内部程序不断查询OS_TimeMS的变化实现软件定时.  在很多应用场合,我们需要用到定时器,比如每隔一定时间查询某一事件有没有被触发,每隔一定时间改变

uC/OS-III-11.0-uC/OS-III软件定时器

1.软件定时器管理 uC/OS-III提供了软件定时器服务(相关代码在OS_TMR.C中).当设置OS_CFG.H中的OS_CFG_TMR_EN为1时软件定时器服务被使能. 2.uC/OS-III 定时器的分辨率决定于时基频率,也就是变量OS_CFG_TMR_TASK_RATE_HZ的值,它是以 Hz为单位的.如果时基任务的频率设置为 10Hz,所有定时器的分辨率为十分之一秒.事实上, 这是用于定时器的推荐值. 定时器用于不精确时间尺度的任务. 3.uC/OS-III提供了一些函数用于管理定时器

ucosiii浅析内核对象-软件定时器

内核对象和各种内核机制的函数接口都在os.h里声明,实现在各自的.c文件,比如os_tmr.c和os_time.c. C语言全局变量一般会默认初始化:局部变量如若不初始化,会分配垃圾数据的:建议使用时都手动初始化. 其实使用内核对象时,就类似与使用任务,只不过在创建对象之前,要先声明一个内核对象. 好了,上面闲聊了几句,今天来说说ucosiii的几个内核对象. 首先说"软件定时器",其实单纯的讲就是定时作用,这里我们要注意的就是,使用它方法和使用任务类似:那么我们就先来分析分析任务的执