参考:
- 【野火】物联网操作系统 LiteOS 开发实战指南
- Huawei LiteOS | 中文网
7. 软件定时器
7.1 基本概念
7.1.1 概念
- 软件定时器,是基于系统
Tick
时钟中断,且由软件来模拟的定时器,当经过设定的Tick时钟计数值后触发用户定义的回调函数(类似硬件的中断服务函数) - 定时精度与系统
Tick
时钟的周期有关 - 定时器的定时周期,是两次触发回调函数的时间间隔
- 软件定时器回调函数的上下文是任务,且回调函数也要快进快出,且回调函数中不能有任何阻塞任务运行的情况
7.1.2 功能支持
- 裁剪:能通过宏关闭软件定时器功能
- 软件定时器创建
- 软件定时器启动
- 软件定时器停止
- 软件定时器删除
- 软件定时器剩余
Tick
数获取
7.1.3 支持模式
-
单次模式
- 当用户创建了定时器并启动定时器后,定时时间到了,只执行一次回调函数就将该定时器删除,不再重新执行
-
周期模式
- 这个定时器会按照设定的定时时间循环执行回调函数,直到用户将定时器删除
7.1.4 定时器管理
- LiteOS通过一个软件定时器任务
osSwTmrTask
来管理软件定时器 - 软件定时器任务的优先级是
0
,也就是最高优先级,是在LiteOS核心初始化的时候自动创建 osSwTmrTask
任务会在其执行期间检查用户启动的时间周期溢出的定时器,并调用其回调函数
7.2 应用场景
- 弥补硬件定时器受限的场景
- 适用于对时间精度要求不高的任务,一些辅助型的任务
- 不足:
- 精度较硬件定时器中断较差,因软件定时器的定时过程中极有可能被其他中断所打断
7.3 运作机制
7.3.1 精度说明
- 操作系统中,软件定时器以系统节拍周期为计时单位
- 系统节拍配置为
LOSCFG_BASE_CORE_TICK_PER_SECOND
,在target_config.h
中定义 - 软件定时器所定时数值必须是这个节拍周期的整数倍
7.3.2 机制
- 软件定时器使用了系统的一个队列和一个任务资源,软件定时器的出发遵循队列规则,先进先出,定时器短的总是比定时时间长的靠近队列头
- 软件定时器以
Tick
为基本定时单位,当用户创建并启动一个软件定时器时,LiteOS会根据当前系统Tick
时间及用户设置的定时时间间隔
确定该定时器的到期Tick
时间,并将该定时器控制结构挂入计时全局链表 - 当Tick中断到来时,在Tick中断处理函数中扫描定时器的计时全局链表,看是否有定时器超时若有,则将超时的定时器记录下来
- 如果软件定时器的定时时间到来,那么在Tick中断处理函数结束后,软件定时器任务
osSwTmrTask
(优先级最高)被唤醒,在该任务中调用之前记录下来的定时器的超时函数
7.3.3 定时器状态
OS_SWTMR_STATUS_UNUSED
(未使用)- 系统在定时器模块初始化的时候将系统中所有定时器资源初始化成该状态
OS_SWTMR_STATUS_CREATED
(创建未启动/停止)- 在未使用状态下,调用
LOS_SwtmrCreate()
函数,或者是定时器启动后调用LOS_SwtmrStop()
函数后,定时器变成该状态
- 在未使用状态下,调用
OS_SWTMR_STATUS_TICKING
(计数)- 在定时器创建后调用
LOS_SwtmrStart()
函数,定时器将变成该状态,表示定时器运行时的状态
- 在定时器创建后调用
7.4 使用注意点
- 软件定时器的回调函数中不要做过多操作,不要使用可能引起任务挂起或者阻塞的接口,如
LOS_TaskDelay()
- 软件定时器使用了系统的一个队列和一个任务资源,软件定时器任务的优先级设定为
0
,且不允许修改 - 系统可配置的软件定时器资源个数是指:整个系统可使用的软件定时器资源总个数,而并非是用户可使用的软件定时器资源个数
- 创建单次软件定时器,该定时器超时执行完回调函数后,系统会自动删除该软件定时器,并回收资源
7.5 开发说明
注意:使用时需要包含头文件:
los_swtmr.h
7.5.1 控制块
typedef struct tagSwTmrCtrl
{
struct tagSwTmrCtrl *pstNext; /* 指向下一个软件定时器的指针 */
UINT8 ucState; /* 软件定时器状态 */
UINT8 ucMode; /* 软件定时器模式 */
#if (LOSCFG_BASE_CORE_SWTMR_ALIGN == YES)/* 如果定义了LOSCFG_BASE_CORE_SWTMR_ALIGN */
UINT8 ucRouses; /* 使用软件定时器唤醒 */
UINT8 ucSensitive; /* 使用软件定时器对齐 */
#endif
UINT16 usTimerID; /* 软件定时器ID */
UINT32 uwCount; /* 软件定时器计数值,用来记录软件定时器到来的剩余时间 */
UINT32 uwInterval; /* 软件定时器的超时时间间隔,或者说定时周期 */
UINT32 uwArg; /* 调用处理软件定时器超时的回调函数时传入的参数 */
SWTMR_PROC_FUNC pfnHandler; /* 处理软件定时器超时的回调函数 */
} SWTMR_CTRL_S;
7.5.2 功能函数
Huawei LiteOS系统中的软件定时器模块为用户提供下面几种功能,下面具体的API详见软件定时器对外接口手册。
功能分类 | 接口名 | 描述 |
---|---|---|
创建、删除定时器 | LOS_SwtmrCreate | 创建定时器 |
LOS_SwtmrDelete | 删除定时器 | |
启动、停止定时器 | LOS_SwtmrStart | 启动定时器 |
LOS_SwtmrStop | 停止定时器 | |
获得软件定时器剩余Tick数 | LOS_SwtmrTimeGet | 获得软件定时器剩余Tick数 |
7.5.3 开发流程
- 配置软件定时器(在
target_config.h
中)- 确认配置项
LOSCFG_BASE_CORE_SWTMR
和LOSCFG_BASE_IPC_QUEUE
为YES
打开状态 - 配置
LOSCFG_BASE_CORE_SWTMR_LIMIT
最大支持的软件定时器数 - 配置
OS_SWTMR_HANDLE_QUEUE_SIZE
软件定时器队列最大长度
- 确认配置项
- 创建定时器,调用
LOS_SwtmrCreate()
- 创建一个指定定时时长,指定超时处理函数,指定触发模式的软件定时器
- 返回函数运行结果,成功或失败
- 启动定时器,调用
LOS_SwtmrStart()
- 获得定时器剩余Tick数,调用
LOS_SwtmrTimeGet()
- 停止定时器,调用
LOS_SwtmrStop()
- 删除定时器,调用
LOS_SwtmrDelete()
7.5.4 功能函数简介
-
定时器创建函数
LOS_SwtmrCreate()
UINT32 LOS_SwtmrCreate( UINT32 uwInterval, /*软件定时器定时时间*/ UINT8 ucMode, /*软件定时器工作模式*/ SWTMR_PROC_FUNC pfnHandler, /*软件定时器回调函数*/ UINT16 *pusSwTmrID, /*软件定时器id*/ UINT32 uwArg, /*软件定时器传入参数*/ #if (LOSCFG_BASE_CORE_SWTMR_ALIGN == YES) /**/ UINT8 ucRouses, /**/ UINT8 ucSensitive /**/ #endif )
软件定时器工作模式:
enum enSwTmrType { LOS_SWTMR_MODE_ONCE, /**< 单次模式 */ LOS_SWTMR_MODE_PERIOD, /**< 周期模式 */ LOS_SWTMR_MODE_NO_SELFDELETE, /**< 单次模式,但不能删除自己 */ LOS_SWTMR_MODE_OPP, /**<在一次性定时器完成定时后,启用定期软件定时器。 暂时不支持此模式。 */ };
-
定时器删除函数
LOS_SwtmrDelete()
- 注意,要删除的软件定时器必须是已经被创建的
UINT32 LOS_SwtmrDelete(UINT16 usSwTmrID) /* 定时器ID */
-
定时器启动函数
LOS_SwtmrStart()
- 软件定时器需要手动启动
UINT32 LOS_SwtmrStart(UINT16 usSwTmrID) /* 定时器ID */
-
在启动的过程中,会将要插入的软件定时器按照其被唤醒的时间进行排序, 距离唤醒时间越短的软件定时器排在前边,距离唤醒时间越长的排在后面。
-
比如软件定时器队列中一开始只有一个周期为200Tick的软件定时器A,那么A定时器在200Tick后就会调用一次回调函数,但是,现在插入一个周期为100Tick的软件定时器B,那么100个Tick之后,软件定时器B的回调函数就要调用一次,而原来在200个Tick后调用回调函数的软件定时器A就会变成在软件定时器B调用之后的100个Tick进行唤醒,然后调用对应的回调函数,如下图所示:
-
定时器停止函数
LOS_SwtmrStop()
- 删除某个软件定时器之前应先把软件定时器停止
UINT32 LOS_SwtmrStop(UINT16 usSwTmrID) /* 定时器ID */