概念
很多系统都提供软件定时器,通过软件定时器可以异步的延时或周期性执行某一函数,使用延时函数也实现同样的功能,但延时函数是同步方式,等待时需要阻塞当前线程,如果要实现多个周期性动作需要创建多个线程。
无论是驱动还是应用程序,经常会用到周期查询任务,最简单高效的的实现方法就是创建一个周期性的软件定时器,在其回调函数中执行响应操作。
接口
SylixOS同样提供软件定时器,可以单次或循环模式执行,且提供普通和高速两种定时器类型。普通软件定时器在线程上下文中判定时间和执行回调,高速软件定时器则是在系统心跳中断中判定时间和执行回调。
/*********************************************************************************************************
TIMER 创建选项
*********************************************************************************************************/
#define LW_OPTION_ITIMER 0x00000001 /* 普通 */
#define LW_OPTION_HTIMER 0x00000000 /* 高速 */
/*********************************************************************************************************
TIMER 设置选项
*********************************************************************************************************/
#define LW_OPTION_AUTO_RESTART 0x00000001 /* 定时器自动重载 */
#define LW_OPTION_MANUAL_RESTART 0x00000000 /* 定时器手动重载 */
LW_API VOID API_TimerHTicks(VOID);/* 高速定时器周期服务函数,需要在心跳中断中调用 */
LW_API ULONG API_TimerHGetFrequency(VOID); /* 获得高速定时器频率 */
/* 建立一个定时器 */
LW_API LW_OBJECT_HANDLE API_TimerCreate(CPCHAR pcName,//定时器名字
ULONG ulOption,//定时器类型
LW_OBJECT_ID *pulId); // 返回对象句柄
LW_API ULONG API_TimerDelete(LW_OBJECT_HANDLE *pulId); /* 删除一个定时器 */
/* 启动一个定时器 */
LW_API ULONG API_TimerStart(LW_OBJECT_HANDLE ulId,//对象句柄
ULONG ulCounter,//定时时间,以节拍为单位
ULONG ulOption,//选项,单次还是周期性
PTIMER_CALLBACK_ROUTINE cbTimerRoutine,//回调函数
PVOID pvArg);//回调函数参数
/* 启动一个定时器 */
LW_API ULONG API_TimerStartEx(LW_OBJECT_HANDLE ulId,//对象句柄
ULONG ulInitCounter,//计数初始值
ULONG ulCounter,//重复计数初始值
ULONG ulOption,//操作选项
PTIMER_CALLBACK_ROUTINE cbTimerRoutine,//回调函数
PVOID pvArg);//回调函数参数
LW_API ULONG API_TimerCancel(LW_OBJECT_HANDLE ulId); /* 停止一个定时器 */
LW_API ULONG API_TimerReset(LW_OBJECT_HANDLE ulId); /* 复位一个定时器 */
/* 获得一个定时器状态 */
LW_API ULONG API_TimerStatus(LW_OBJECT_HANDLE ulId,//对象句柄
BOOL *pbTimerRunning,//定时器是否在运行
ULONG *pulOption,//定时器选项
ULONG *pulCounter,//定时器当前计数值
ULONG *pulInterval);//间隔时间, 为 0 表示单次运行
/* 获得一个定时器状态扩展接口 */
LW_API ULONG API_TimerStatusEx(LW_OBJECT_HANDLE ulId,//对象句柄
BOOL *pbTimerRunning,//定时器是否在运行
ULONG *pulOption,//定时器选项
ULONG *pulCounter,//定时器当前计数值
ULONG *pulInterval,//间隔时间, 为 0 表示单次运行
clockid_t *pclockid);//POSIX 时间类型
LW_API ULONG API_TimerGetName(LW_OBJECT_HANDLE ulId,
PCHAR pcName); /* 获得定时器名字 */
用法举例
/*********************************************************************************************************
**
** 中国软件开源组织
**
** 嵌入式实时操作系统
**
** SylixOS(TM) LW : long wing
**
** Copyright All Rights Reserved
**
**--------------文件信息--------------------------------------------------------------------------------
**
** 文 件 名: timerExample.c
**
** 创 建 人: Hou.JinYu (侯进宇)
**
** 文件创建日期: 2017 年 12 月 20 日
**
** 描 述: 软件定时器例程
*********************************************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioccom.h>
#include <pthread.h>
/*********************************************************************************************************
** 函数名称: timerCb
** 功能描述: 软件定时器回调函数
** 输 入: pvArg 回调参数
** 输 出: 无
*********************************************************************************************************/
VOID timerCb (PVOID pvArg)
{
int *pcount = pvArg;
(*pcount)++;
/*
* 中断中不能调用printf函数
*/
if (!API_InterContext()) {
printf("timer callback, count = %d\n", *pcount);
}
}
/*********************************************************************************************************
** 函数名称: main
** 功能描述: 程序入口
** 输 入: argc 参数个数
** argv 参数列表
** 输 出: ERROR_CODE
*********************************************************************************************************/
int main (int argc, char **argv)
{
LW_OBJECT_HANDLE hTimer;
volatile int count = 0;
int err;
int i;
ULONG ulOption = LW_OPTION_ITIMER;
ULONG ulCounter = API_TimeGetFrequency();
printf("timer example start\n");
/*
* 根据命令参数判断是否为高速定时器,否则默认为普通定时器
*/
if (argc == 2) {
if (strcmp(argv[1], "h") == 0) {
ulOption = LW_OPTION_HTIMER;
ulCounter = API_TimerHGetFrequency();
}
}
/*
* 创建软件定时器,指定为普通模式
*/
hTimer = API_TimerCreate("timer", ulOption, LW_NULL);
if (hTimer == 0) {
printf("create timer failed\n");
return (PX_ERROR);
} else {
printf("create timer success\n");
}
/*
* 启动定时器,周期为1秒,循环模式,回调函数中对计数加加处理
*/
err = API_TimerStart(hTimer,
ulCounter,
LW_OPTION_AUTO_RESTART,
(PTIMER_CALLBACK_ROUTINE)timerCb,
(PVOID)&count);
if (err) {
printf("start timer failed, err = %d\n", err);
API_TimerDelete(&hTimer);
return (PX_ERROR);
} else {
printf("start timer success\n");
}
/*
* 每半秒复位一次软件定时器,这样10次(5秒)内软件定时器应该得不到运行
*/
printf("reset timer 10 times\n");
for (i = 0; i < 10; i++) {
API_TimeSleep(API_TimeGetFrequency() / 2);
API_TimerReset(hTimer);
printf("reset timer. i = %d\n", i);
}
/*
* 不再复位软件定时器,轮询count等于5时停止软件定时器
*/
printf("wait count++ to 5\n");
while (1) {
if (count > 5) {
err = API_TimerCancel(hTimer);
if (err) {
printf("stop timer failed, err = %d\n", err);
API_TimerDelete(&hTimer);
return (PX_ERROR);
} else {
printf("stop timer success\n");
break;
}
}
}
/*
* 软件定时器已停止,等待5秒,期间不应该有回调运行
*/
printf("wait 5s\n");
for (i = 0; i < 10; i++) {
API_TimeSleep(API_TimeGetFrequency() / 2);
printf("wait timer. i = %d, count = %d\n", i, count);
}
/*
*
*/
API_TimerDelete(&hTimer);
printf("timer example finish\n");
return (0);
}
/*********************************************************************************************************
END
*********************************************************************************************************/