uC/OS-III之定时器管理

来源:互联网 发布:java nio 关闭连接 编辑:程序博客网 时间:2024/05/16 04:06

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;        }    }}
原创粉丝点击