μC/OS-Ⅱ源码学习(7)---软件定时器

快速回顾

μC/OS-Ⅱ中的多任务

μC/OS-Ⅱ源码学习(1)---多任务系统的实现

μC/OS-Ⅱ源码学习(2)---多任务系统的实现(下)

μC/OS-Ⅱ源码学习(3)---事件模型

μC/OS-Ⅱ源码学习(4)---信号量

μC/OS-Ⅱ源码学习(5)---消息队列

μC/OS-Ⅱ源码学习(6)---事件标志组

        本文进一步解析μC/OS-Ⅱ中,软件定时器的函数源码。

μC/OSⅡ中的定时器系统

        软件定时器并不属于事件系统,是一类特殊的模型,有自己独特的执行逻辑。更具体来说,除了手动创建、启动和销毁,软件定时器的其它生命周期过程无需用户操作,更不与其它任务相关联,它和定时器任务共同构成了软件定时器系统。

        在定时器系统中,最重要的就是如何检查定时器的到期,对于一个同步系统来说,基本只能使用“轮询”的方式,即定期检查,这种方式存在两个关键问题:

①如何把控轮询间隔,首先轮询间隔必须是固定(否则步长不定,时间精度也就无从谈起),而且间隔不能太长,否则定时器的时间精度就下降了。也不能太短,这样太消耗资源;

②二是当定时器很多时,遍历的时间就会线性增加,如何设计结构提高遍历效率。

        对于问题①,比较好解决,可以选一个稳定且周期性的中断作为轮询出发点(比如STM32里的滴答中断),并根据用户需求进行间隔时长的配置。

        对于问题②,为了提高轮询效率,μC/OSⅡ使用“车轮式”(Wheel)的查询结构,将时间线周期性地均匀缠绕在“车轮”上,好比钟表走时一样,每一根车辐都对应一个时间刻度,进而可以将不同的定时器通过到期时间归属到对应的时刻上,每一时刻只需盘点该时刻下的定时器,可以减少对大量定时器的遍历,提高查询效率。这种算法本质上还是用空间换取时间

相关结构和类型

        和软件定时器相关的变量如下:

//ucos_ii.h
OS_EXT  INT16U        OSTmrFree;                /* 剩余可用的空白定时器 */
OS_EXT  INT16U        OSTmrUsed;                /* 已使用的定时器数量 */
OS_EXT  INT32U        OSTmrTime;                /* 当前时间 */

OS_EXT  OS_EVENT     *OSTmrSem;                 /* 操作定时器的权限 */
OS_EXT  OS_EVENT     *OSTmrSemSignal;           /* 当定时器更新(到期)时,用于提醒定时器任务运行的信号量 */

OS_EXT  OS_TMR        OSTmrTbl[OS_TMR_CFG_MAX];   /* 软件定时器数组 */
OS_EXT  OS_TMR       *OSTmrFreeList;              /* 空白软件定时器链表 */
OS_EXT  OS_STK        OSTmrTaskStk[OS_TASK_TMR_STK_SIZE];    //软件定时器堆栈大小

OS_EXT  OS_TMR_WHEEL  OSTmrWheelTbl[OS_TMR_CFG_WHEEL_SIZE];   //时间车轮数组,每一个成员代表一个时间刻度

        OS_TMR_CFG_MAX表示定时器的最大数量,OS_TMR_CFG_WHEEL_SIZE表示时间车轮的车辐数,也即时间刻度数,下文中的“车辐”和“刻度”表示一个意思。

        两个信号量,OSTmrSem是获取定时器操作权限的信号量,OSTmrSemSignal是滴答中断用来提醒定时器任务执行的信号量。

        这里面比较重要的类型就是定时器OS_TMR时间车轮OS_TMR_WHEEL

OS_TMR

        与任务、事件类似,定时器也是以链表的形式进行遍历检索的(除了存储定时器的原始数组),且是双向链表的形式,方便在链表中进行插入和删除元素。

//ucos_ii.h
typedef  struct  os_tmr {
    INT8U            OSTmrType;             /* 初始化后被设置位OS_TMR_TYPE(其它类型无效) */
    OS_TMR_CALLBACK  OSTmrCallback;         /* 定时器回调函数 */
    void            *OSTmrCallbackArg;      /* 需要传给回调函数的参数 */
    void            *OSTmrNext;             /* 和OSTmrPrev共同构成双向链表指针 */
    void            *OSTmrPrev;
    INT32U           OSTmrMatch;            /* 到期时间,即当OSTmrTime=OSTmrMatch时定时器到期 */
    INT32U           OSTmrDly;              /* 开启定时器前的延时 */
    INT32U           OSTmrPeriod;           /* 定时器周期 */
#if OS_TMR_CFG_NAME_EN > 0u
    INT8U           *OSTmrName;             /* 定时器名称 */
#endif
    INT8U            OSTmrOpt;              /* 选项(如OS_TMR_OPT_xxx) */
    INT8U            OSTmrState;            /* 定时器状态,有四种 */
} OS_TMR;

        里面有两个成员可以进一步解析,一个是选项OSTmrOpt

//ucos_ii.h
#define  OS_TMR_OPT_NONE              0u  /* 无选项 */

#define  OS_TMR_OPT_ONE_SHOT          1u  /* 单次定时器,不会自动重启 */
#define  OS_TMR_OPT_PERIODIC          2u  /* 周期性定时器,到期后自动重启 */

#define  OS_TMR_OPT_CALLBACK          3u  /* OSTmrStop() option to call 'callback' w/
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值