VxWorks通用定时器设计与实现
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
VxWorks通用定时器设计与实现
摘要:在进行网络通信设备开发时,需要使用通用定时器。本文在研究VxWorks系统看门狗函数的基础上,提出了基于看门狗函数的定制定时器的设计方法,可以使定制定时器的最小周期满足网络通信设备开发的需要本文给出了定制定时器实现的思想。
1 概述
VxWorks是WindRiver公司开发的具有工业领导地位的高性能实时操作系统内核,具有先进的网络功能,易于设计高效的嵌入式系统目前已成为嵌入式操作系统的首选,并将其作为通信产品的软件平台。
在进行网络通信设备开发时,需要用到定时器,如以周期为m秒对某个端口进行查询、以周期为n分对某个设备的性能数据进行统计等。而VxWorks只提供了像watchDog(看门狗),而没有提供一个通用的定时器。本文提出的通用定时器设计方法,占用系统资源少,运行效率高,并可根据需要定制满足要求的定时器。
2 通用定时器的基本原理
虽然在Vxworks没有提供像windows中的定时器一样好用的定时器,但可以利用VxWorks的看门狗来实现定时器。对看门狗的操作函数主要有三个:创建看门狗函数WDOG_ID wdCreate(void);启动看门狗函数STATUS wdStart(WDOG_ID wdId,int delay,FUNCPTR pRoutine,int parameter);删除看门狗函数STATUS wdDelete(WDOG_ID wdId)。通过对看门狗启动函数进行研究发现,如果能够在看门狗的响应函数中重新启动看门狗.那么就可以实现以一个固定的周期循环执行的定时器。以下是定时器的基本框架:
void settimer(int interval)
{ int in_interval;
m_interval=sysClkRateGet()*interval;/*将延时秒数转化为ticks数*/
gm wdID =wdCreate();/*创建看门狗*/
if(gm_perfHist_wdID = NULL)
{
printf("Could not create watchdog timer\n");
return ;
}
if(wdStart(gm_wdID,m_interval,(FUNCPTR)
action_func,interval) = ERROR)
/*启动看门狗*/
{
printf ("Error in starting routine associated with timer\n");
wdDelete(gm_wdlD);/*如果启动看门狗不成功,则删除看门狗*/
return;
}
return;
}
void action_func(int interval)
{ int m_interval;
m_interval=sysClkRateGet()*interval;/*将延时秒数转化为ticks数*/
if(wdStart(gm_wdID,m_interval,(FUNCPTR)action_fnnc,interval)= ERROR)
/*启动看门狗*/
{
printf ("Error in starting routine associated with timer\n");
wdDelete(gm_wdID);
return;
}
/*执行用户函数*/
……
}
用户只需调用settimer并给出以秒为单位的定时器周期,就可以建立一个定时器。
3 通用定时器设计
通过调用settimer可实现一个基本的定时器,但在程序中对定时器的要求比较复杂。如有可能在运行过程中,要求加人某个需用轮询的函数,这样就要建立一个较为通用的定时器。
3.1 通用定时器的设计思想
通用定时器应能满足用户的要求.要能动态地将用户需轮询函数加入到定时器的轮询队列中。要实现动态加载用户需轮询函数,可将用户需轮询函数串接成一个链表(链表的每个结点称为一个定时器用户)。在每个定时器周期到期时,遍历定时器用户链表,执行用户函数,这样就可以实现动态加载用户需轮询函数。
如果轮询周期与定时器周期相同,那么加入的用户轮询函数,在第一次执行时,其周期将会小于所要求的轮询周期,在最坏情况下,可能相差近一个周期。要解决这个问题可将定时器的周期设置为较小,且在定时器用户结点中记录用户的轮询周期和距离轮询周期到期所剩余时间,在定时器到期时,用剩余时间减去定时器周期,如果结果小于零,就执行用户函数。用这种方法可以解决第一次执行时的时差较大问题;另一方面,动态加载的用户函数可以以不同的周期进行轮询。
另一个问题是在定时器到期时遍历定时器用户链表并执行相关用户函数时的效率:如果用户函数执行时间较长(如板间通信),由于函数的执行会影响链表下一个结点函数的执行。为解决这个问题可以为每个用户函数启动一个任务。但反复地为用户创建、删除任务,会加重
系统的开销。解决这个问题可以在创建定时器用户时,就为定时器用户的响应函数创建一个任务,并将此任务挂起。当要求的轮询周期到期时,唤醒此任务;为了能够正确地对此任务进行操作,就要在定时器用户结点的数据结构中增加一个关联任务标识。在创建定时器用户时,由用户指明是否为其响应函数创建关联任务。这样,在定时器遍历定时器用户链表时,如果检测到关联任务为无效值时,就直接执行用户函数,而不创建新的任务。
根据通用定时器的设计思想,可以设计出通用定时器结构如附图所示:
系统初始化时,将设置并启动一个默认的周期为1秒的定时器0,此定时可以满足大部分用户的要求;如果此定时器不能满足用户的要求,也可以定制自己的定时器,在不需要使用定制的定时器时,要将其删除,否则由于定时器要占用一定的系统资源,而造成系统资源的浪费。但系统默认定时器0是无法删除的。
用户可以将需要以一定周期运行的函数加入到符合要求的定时器的用户队列中,这样用户的函数就可以以一定周期运行当用户认为已经加入定时器用户队列的函数,不需要再周期性运行时,可以将其从队列中删除。
3.3 通用定时器的数据结构
通用定时器的数据结构分为两部分,即定时器数据结构和定时器用户数据结构。
1.定时器数据结构:描述定时器的信息。包括用于标识此定时器的ID、用于分配定时
器用户ID的有效索引值、定时器的周期、定时器所用的看门狗ID以及定时器用户队列
2.定时器用户数据结构:描述每个加入定时器的用户的信息。主要有定时器用户ID、
用户指定的轮询周期、距离用户指定周期到期剩余时间、用户响应函数及响应函数所带的参数以及参数长度。为了方便不同用户使用,应将响应函数所带参数设置为无符号指针,这样用户就可以设置任何一种数据类型。如果用户参数较多,可以采用结构指针。
3.4 通用定时器的具体实现
通用定时器的实现主要包括下面几类函数:
①定时器核心实现函数:将定时器的实现框架进行扩充,使其能够以较小的周期运行。当一