各种定时方法.doc

上传人:hw****26 文档编号:4043910 上传时间:2019-09-15 格式:DOC 页数:8 大小:52.50KB
下载 相关 举报
各种定时方法.doc_第1页
第1页 / 共8页
各种定时方法.doc_第2页
第2页 / 共8页
各种定时方法.doc_第3页
第3页 / 共8页
各种定时方法.doc_第4页
第4页 / 共8页
各种定时方法.doc_第5页
第5页 / 共8页
点击查看更多>>
资源描述

1、关于用 VC 编写的 windows 下精确定时器的资料(转)在工业生产控制系统中,有许多需要定时完成的操作,如定时显示当前时间,定时刷新屏幕上的进度条,上位 机定时向下位机发送命令和传送数据等。特别是在对控制性能要求较高的实时控制系统和数据采集系统中,就更需要精确定时操作。众所周知,Windows 是基于消息机制的系统,任何事件的执行都是通过发送和接收消息来完成的。 这样就带来了一些问题,如一旦计算机的 CPU 被某个进程占用,或系统资源紧张时,发送到消息队列 中的消息就暂时被挂起,得不到实时处理。因此,不能简单地通过 Windows 消息引发一个对定时要求 严格的事件。另外,由于在 Win

2、dows 中已经封装了计算机底层硬件的访问,所以,要想通过直接利用 访问硬件来完成精确定时,也比较困难。所以在实际应用时,应针对具体定时精度的要求,采取相适 应的定时方法。VC 中提供了很多关于时间操作的函数,利用它们控制程序能够精确地完成定时和计时操作。本文详细介绍了 VC 中基于 Windows 的精确定时的七种方式,如下图所示: 图一 图像描述方式一:VC 中的 WM_TIMER 消息映射能进行简单的时间控制。首先调用函数SetTimer()设置定时 间隔,如 SetTimer(0,200,NULL)即为设置 200ms 的时间间隔。然后在应用程序中增加定时响应函数 OnTimer(),

3、并在该函数中添加响应的处理语句,用来完成到达定时时间的操作。这种定时方法非常 简单,可以实现一定的定时功能,但其定时功能如同 Sleep()函数的延时功能一样,精度非常低,最小 计时精度仅为 30ms,CPU 占用低,且定时器消息在多任务操作系统中的优先级很低,不能得到及时响 应,往往不能满足实时控制环境下的应用。只可以用来实现诸如位图的动态显示等对定时精度要求不高的情况。如示例工程中的 Timer1。方式二:VC 中使用 sleep()函数实现延时,它的单位是 ms,如延时 2 秒,用sleep(2000)。精度非常 低,最小计时精度仅为 30ms,用 sleep 函数的不利处在于延时期间不

4、能处理其他的消息,如果时间太 长,就好象死机一样,CPU 占用率非常高,只能用于要求不高的延时程序中。如示例工程中的 Timer2。方式三:利用 COleDateTime 类和 COleDateTimeSpan 类结合 WINDOWS 的消息处理过程来实现秒级延时。如示例工程中的 Timer3 和 Timer3_1。以下是实现 2 秒的延时代码:COleDateTime start_time = COleDateTime:GetCurrentTime();COleDateTimeSpan end_time= COleDateTime:GetCurrentTime()-start_time;wh

5、ile(end_time.GetTotalSeconds() 2) /实现延时 2 秒 MSG msg;GetMessage(TranslateMessage( DispatchMessage(/以上四行是实现在延时或定时期间能处理其他的消息,/虽然这样可以降低 CPU 的占有率,/但降低了延时或定时精度,实际应用中可以去掉。end_time = COleDateTime:GetCurrentTime()-start_time;/这样在延时的时候我们也能够处理其他的消息。 方式四:在精度要求较高的情况下,VC 中可以利用 GetTickCount()函数,该函数的返回值是 DWORD 型,表示

6、以 ms 为单位的计算机启动后经历的时间间隔。精度比 WM_TIMER 消息映射高,在较 短的定时中其计时误差为 15ms,在较长的定时中其计时误差较低,如果定时时间太长,就好象死机一样,CPU 占用率非常高,只能用于要求不高的延时程序中。如示例工程中的 Timer4 和 Timer4_1。下列代码可以实现50ms 的精确定时:DWORD dwStart = GetTickCount();DWORD dwEnd = dwStart;dodwEnd = GetTickCount()-dwStart;while(dwEnd 50);为使 GetTickCount()函数在延时或定时期间能处理其他的

7、消息,可以把代码改为:DWORD dwStart = GetTickCount();DWORD dwEnd = dwStart;doMSG msg;GetMessage(TranslateMessage( DispatchMessage(dwEnd = GetTickCount()-dwStart;while(dwEnd 50);虽然这样可以降低 CPU 的占有率,并在延时或定时期间也能处理其他的消息,但降低了延时或定时精度。方式五:与 GetTickCount()函数类似的多媒体定时器函数 DWORDtimeGetTime(void),该函数定时精 度为 ms 级,返回从 Windows 启

8、动开始经过的毫秒数。微软公司在其多媒体 Windows 中提供了精确定时器的底 层 API 持,利用多媒体定时器可以很精确地读出系统的当前时间,并且能在非常精确的时间间隔内完成一 个事件、函数或过程的调用。不同之处在于调用 DWORD timeGetTime(void) 函数之前必须将 Winmm.lib 和 Mmsystem.h 添加到工程中,否则在编译时提示DWORD timeGetTime(void)函数未定义。由于使用该 函数是通过查询的方式进行定时控制的,所以,应该建立定时循环来进行定时事件的控制。如示例工程中的Timer5 和 Timer5_1。方式六:使用多媒体定时器 timeS

9、etEvent()函数,该函数定时精度为 ms级。利用该函数可以实现周期性的函数调用。如示例工程中的 Timer6 和 Timer6_1。函数的原型如下:MMRESULT timeSetEvent( UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, WORD dwUser, UINT fuEvent )该函数设置一个定时回调事件,此事件可以是一个一次性事件或周期性事件。事件一旦被激活,便调用指定的回调函数, 成功后返回事件的标识符代码,否则返回 NULL。函数的参数说明如下:uDelay:以毫秒指定事件的周期。Uresoluti

10、on:以毫秒指定延时的精度,数值越小定时器事件分辨率越高。缺省值为 1ms。LpTimeProc:指向一个回调函数。DwUser:存放用户提供的回调数据。FuEvent:指定定时器事件类型:TIME_ONESHOT:uDelay 毫秒后只产生一次事件TIME_PERIODIC :每隔 uDelay 毫秒周期性地产生事件。 具体应用时,可以通过调用 timeSetEvent()函数,将需要周期性执行的任务定义在 LpTimeProc 回调函数 中(如:定时采样、控制等),从而完成所需处理的事件。需要注意的是,任务处理的时间不能大于周期间隔时间。另外,在定时器使用完毕后, 应及时调用 timeKi

11、llEvent()将之释放。方式七:对于精确度要求更高的定时操作,则应该使用QueryPerformanceFrequency()和 QueryPerformanceCounter()函数。这两个函数是 VC 提供的仅供 Windows 95 及其后续版本使用的精确时间函数,并要求计算机从硬件上支持精确定时器。如示例工程中的 Timer7、Timer7_1、Timer7_2、Timer7_3。QueryPerformanceFrequency()函数和 QueryPerformanceCounter()函数的原型如下:BOOL QueryPerformanceFrequency(LARGE_I

12、NTEGER lpFrequency);BOOL QueryPerformanceCounter(LARGE_INTEGER lpCount);数据类型 ARGE_INTEGER 既可以是一个 8 字节长的整型数,也可以是两个 4字节长的整型数的联合结构, 其具体用法根据编译器是否支持 64 位而定。该类型的定义如下:typedef union _LARGE_INTEGERstructDWORD LowPart ;/ 4 字节整型数LONG HighPart;/ 4 字节整型数;LONGLONG QuadPart ;/ 8 字节整型数LARGE_INTEGER ;在进行定时之前,先调用 Que

13、ryPerformanceFrequency()函数获得机器内部定时器的时钟频率, 然后在需要严格定时的事件发生之前和发生之后分别调用QueryPerformanceCounter()函数,利用两次获得的计数之差及时钟频率,计算出事件经 历的精确时间。下列代码实现 1ms 的精确定时:LARGE_INTEGER litmp; LONGLONG QPart1,QPart2;double dfMinus, dfFreq, dfTim; QueryPerformanceFrequency(dfFreq = (double)litmp.QuadPart;/ 获得计数器的时钟频率QueryPerform

14、anceCounter(QPart1 = litmp.QuadPart;/ 获得初始值doQueryPerformanceCounter(QPart2 = litmp.QuadPart;/获得中止值dfMinus = (double)(QPart2-QPart1);dfTim = dfMinus / dfFreq;/ 获得对应的时间值,单位为秒while(dfTim0.001);其定时误差不超过 1 微秒,精度与 CPU 等机器配置有关。 下面的程序用来测试函数 Sleep(100)的精确持续时间:LARGE_INTEGER litmp; LONGLONG QPart1,QPart2;doub

15、le dfMinus, dfFreq, dfTim; QueryPerformanceFrequency(dfFreq = (double)litmp.QuadPart;/ 获得计数器的时钟频率QueryPerformanceCounter(QPart1 = litmp.QuadPart;/ 获得初始值Sleep(100);QueryPerformanceCounter(QPart2 = litmp.QuadPart;/获得中止值dfMinus = (double)(QPart2-QPart1);dfTim = dfMinus / dfFreq;/ 获得对应的时间值,单位为秒 由于 Sleep

16、()函数自身的误差,上述程序每次执行的结果都会有微小误差。下列代码实现 1 微秒的精确定时:LARGE_INTEGER litmp; LONGLONG QPart1,QPart2;double dfMinus, dfFreq, dfTim; QueryPerformanceFrequency(dfFreq = (double)litmp.QuadPart;/ 获得计数器的时钟频率QueryPerformanceCounter(QPart1 = litmp.QuadPart;/ 获得初始值doQueryPerformanceCounter(QPart2 = litmp.QuadPart;/获得中

17、止值dfMinus = (double)(QPart2-QPart1);dfTim = dfMinus / dfFreq;/ 获得对应的时间值,单位为秒while(dfTim0.000001);其定时误差一般不超过 0.5 微秒,精度与 CPU 等机器配置有关。(完)任何 Visual C+的程序员都会利用 Windows 的 WM_TIMER 消息映射来进行简单的时间控制:1、调用函数 SetTimer()设置定时间隔,如 SetTimer(0,200,NULL)即为设置 200 毫秒的时间间隔;2、在应用程序中增加定时响应函数 OnTimer(),并在该函数中添加响应的处理语句,用来完成定

18、时时间到时的操作。这种定时方法是非常简单的,但其定时功能如同 Sleep()函数的延时功能一样,精度非常低,只可以用来实现诸如位图的动态显示等对定时精度要求不高的情况,但在精度要求较高的条件下,这种方法应避免采用。 - 在要求误差不大于 1 毫秒的情况下,可以采用 GetTickCount()函数(如果读者仍然使用 Windows3.1,可以使用 GetCurrentTime()函数),该函数的返回值是 DWORD 型,表示以毫秒为单位的计算机启动后经历的时间间隔。使用下面的编程语句,可以实现 50 毫秒的精确定时,其误差小于 1 毫秒。以下语句已经使用在大连理工大学海岸和近海工程国家重点实验

19、室为广东省水利水电科学研究所研制开发的液压伺服多向不规则造波机系统的控制程序中。 DWORD dwStart, dwStop ; / 起始值和中止值 dwStop = GetTickCount(); while(TRUE) dwStart = dwStop ; / 上一次的中止值变成新的起始值 / 此处添加相应控制语句 do dwStop = GetTickCount() ; while(dwStop - 50 dwStart) ; - 对于一般的实时控制,使用 GetTickCount()函数就可以满足精度要求。但作者在为大连基康公司编写快速计数程序时,发现使用 GetTickCount()

20、函数对计数结果产生很大影响。为了进一步提高计时精度,作者使用了 QueryPerformanceFrequency()函数和 QueryPerformanceCounter()函数。这两个函数是Visual C+提供的仅供 Windows 95 及其后续版本使用的高精度时间函数,并要求计算机从硬件上支持高精度计时器。QueryPerformanceFrequency()函数和 QueryPerformanceCounter()函数的原型为: BOOL QueryPerformanceFrequency (LARGE_INTEGER *lpFrequency) ; BOOL QueryPerfo

21、rmanceCounter (LARGE_INTEGER *lpCount) ; - 数据类型 LARGE_INTEGER 既可以是一个作为 8 字节长的整型数,也可以作为两个 4 字节长的整型数的联合结构,其具体用法根据编译器是否支持 64 位而定。该类型的定义如下: typedef union _LARGE_INTEGER struct DWORD LowPart ; / 4 字节整型数 LONG HighPart ; / 4 字节整型数 ; LONGLONG QuadPart ; / 8 字节整型数 LARGE_INTEGER ; - 在进行计时之前,应该先调用 QueryPerform

22、anceFrequency()函数获得机器内部计时器的时钟频率。作者在主频为 266、300、333 的三种 Pentium机器上使用该函数,得到的时钟频率都是 1193180Hz。接着,作者在需要严格计时的事件发生之前和发生之后分别调用 QueryPerformanceCounter()函数,利用两次获得的计数之差和时钟频率,就可以计算出事件经历的精确时间。下面的程序是用来测试函数 Sleep(100)的精确持续时间。 LARGE_INTEGER litmp ; LONGLONG QPart1,QPart2 ; double dfMinus, dfFreq, dfTim ; QueryPer

23、formanceFrequency( / 获得计数器的时钟频率 dfFreq = (double)litmp.QuadPart ; QueryPerformanceCounter( / 获得初始值 QPart1 = litmp.QuadPart ; Sleep(100) ; QueryPerformanceCounter( / 获得中止值 QPart2 = litmp.QuadPart ; dfMinus = (double)(QPart2 - QPart1) ; dfTim = dfMinus / dfFreq ; / 获得对应的时间值 - 执行上面程序,得到的结果为 dfTim=0.097143767076216(秒),细心的读者会发现,每次执行的结果都不一样,存在一定的差别,这是由于 Sleep()自身的误差所致。 - 本文介绍了三种定时或计时的实现方法,读者可以根据自己的实际情况进行选择,以达到程序的定时和计时功能。以上程序均使用 Visual C+5.0和 6.0 在 Windows98 下调试通过。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 实用文档资料库 > 策划方案

Copyright © 2018-2021 Wenke99.com All rights reserved

工信部备案号浙ICP备20026746号-2  

公安局备案号:浙公网安备33038302330469号

本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。