uC/OS-III之定时器管理

1.所谓定时器本质上是递减计数器,当计数器减到零时可以出发某种动作的执行。这种动作可以通过回调函数(callback funtion,简称回调)来实现。需要注意的是,一定要避免在回调函数中使用阻塞调用。
注:定时器在一些协议栈的实现中很有用,也可以用来定期轮训IO设备。

2.定时器任务的频率通过宏定义OS_CFG_TMR_TASK_RATE_HZ来实现,单位是Hz。
该宏定义位于文件os_cfg_app.h中。
注:定时器任务频率的常用推荐值是10Hz。

3.定时器是一个内核对象,其数据类型为OS_TMR。它的定义位于文件os.h中。

typedef  struct  os_tmr              OS_TMR;        // 643行

struct  os_tmr {                                    // 1001行 - 1018行
    OS_OBJ_TYPE          Type;                      // 类型,这里说明一下,内核对象结构体的定义都是以Type作为第一个成员变量,这样uC/OS-III就可以判断结构体是那种内核对象。
    CPU_CHAR            *NamePtr;                   // 定时器的名字
    OS_TMR_CALLBACK_PTR  CallbackPtr;               // 回调函数指针
    void                *CallbackPtrArg;            // 回调函数的参数
    OS_TMR              *NextPtr;                   // 这两个指针构成双向链表,连接定时器
    OS_TMR              *PrevPtr;
    OS_TICK              Match;                     // 当计数器的值到达该值时,定时时间到
    OS_TICK              Remain;                    // 存储距离定时器定时时间到的剩余时间
    OS_TICK              Dly;                       // 开始之前的初始值
    OS_TICK              Period;                    // 定时周期
    OS_OPT               Opt;                       // 选项
    OS_STATE             State;                     // 定时器的状态
#if OS_CFG_DBG_EN > 0u                              // 允许调试
    OS_TMR              *DbgPrevPtr;
    OS_TMR              *DbgNextPtr;
#endif
};

4.定时器的状态有4种:未使用、停止、运行、完成。
(1)“未使用”状态代表定时器未被创建或者已经删除
(2)定时器已创建但未调用OSTmrStart()函数之前或调用OSTmrStop()函数之后,定时器处于“停止”状态
(3)调用OSTmrStart()之后,定时器处于“运行”状态
(4)“完成”状态是指单次定时器过期后所处的状态

5.定时器列表包含一个表(OSCfg_TmrWheel[],在os_cfg_app.c中声明)和一个计数器(OSTmrTickCtr,在os.h中声明)。

6.OSCfg_TmrWheel[]表称为定时器轮。定时器轮中的每个条目的数据类型是OS_TMR_SPOKE(该结构体定义在os.h中),它的大小由宏定义OS_CFG_TMR_WHEEL_SIZE(定义在os_cfg_app.h中)设定。
建议不要将OS_CFG_TMR_WHEEL_SIZE设为定时器任务率的偶数倍,最好使用素数。

7.OS_TMR_SPOKE结构体的定义位于os.h中

typedef  struct  os_tmr_spoke        OS_TMR_SPOKE;          // 644行

struct  os_tmr_spoke {                                      // 1022行 - 1026行
    OS_TMR              *FirstPtr;                          // 在双向链表中指向第一个定时器
    OS_OBJ_QTY           NbrEntries;                        // 链接到这个条目的定时器的数量
    OS_OBJ_QTY           NbrEntriesMax;                     // 用来跟踪表中最大定时器数目
};

8.定时任务OS_TmrTask()的定位位于os_tmr.c中,1041行 - 1101行

void  OS_TmrTask (void *p_arg)
{
    CPU_BOOLEAN          done;
    OS_ERR               err;
    OS_TMR_CALLBACK_PTR  p_fnct;
    OS_TMR_SPOKE        *p_spoke;
    OS_TMR              *p_tmr;
    OS_TMR              *p_tmr_next;
    OS_TMR_SPOKE_IX      spoke;
    CPU_TS               ts;
    CPU_TS               ts_start;
    CPU_TS               ts_end;

    p_arg = p_arg;                                               // 参数
    while (DEF_ON) {
        (void)OSTaskSemPend((OS_TICK )0,    // 等待信号量。若用直接发布模式,该信号量来自OSTimeTick();若用延迟发布模式,该信号量来自OS_IntQTask()
                            (OS_OPT  )OS_OPT_PEND_BLOCKING,
                            (CPU_TS *)&ts,
                            (OS_ERR *)&err);
        OSSchedLock(&err);                                       // 锁定调度器
        ts_start = OS_TS_GET();                                  // 记录定时任务的开始执行时间
        OSTmrTickCtr++;                                          // 计数器加1
        spoke    = (OS_TMR_SPOKE_IX)(OSTmrTickCtr % OSCfg_TmrWheelSize);  // 获取定时器轮的条目位置
        p_spoke  = &OSCfg_TmrWheel[spoke];                       // 根据条目位置获取条目
        p_tmr    = p_spoke->FirstPtr;                            // 获取该条目下的第一个定时器
        done     = DEF_FALSE;
        while (done == DEF_FALSE) {
            if (p_tmr != (OS_TMR *)0) {
                p_tmr_next = (OS_TMR *)p_tmr->NextPtr;           // 获取下一个定时器
                if (OSTmrTickCtr == p_tmr->Match) {              // 定时时间到
                    OS_TmrUnlink(p_tmr);                         // 从当前条目中删除定时器
                    if (p_tmr->Opt == OS_OPT_TMR_PERIODIC) {     // 周期执行
                        OS_TmrLink(p_tmr, OS_OPT_LINK_PERIODIC); // 在定时器轮中重新分配一个位置给定时器
                    } else {                                     // 单次执行
                        p_tmr->State = OS_TMR_STATE_COMPLETED;   // 定时器的状态改为“完成”
                    }
                    p_fnct = p_tmr->CallbackPtr;                 // 执行回调函数
                    if (p_fnct != (OS_TMR_CALLBACK_PTR)0) {
                        (*p_fnct)((void *)p_tmr,
                                  p_tmr->CallbackPtrArg);
                    }
                    p_tmr = p_tmr_next;                          // 定时器指针向后移
                } else {                                         // 定时时间未到
                    done  = DEF_TRUE;
                }
            } else {
                done = DEF_TRUE;
            }
        }
        ts_end = OS_TS_GET() - ts_start;                         // 测量定时任务的执行时间
        OSSchedUnlock(&err);                                     // 解锁定时器
        if (ts_end > OSTmrTaskTimeMax) {                         // 记录定时任务执行的最长时间
            OSTmrTaskTimeMax = ts_end;
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值