如何在WinXP下获得准确的1ms计时器滴答

时间:2010-07-29 09:32:49

标签: c++ windows winapi timer real-time

我尝试每隔1 ms调用一次函数。问题是,我喜欢用windows做这个。所以我尝试了多媒体时间API。

Multimediatimer API

来源

idTimer = timeSetEvent( 
     1, 
     0,
     TimerProc, 
     0, 
     TIME_PERIODIC|TIME_CALLBACK_FUNCTION ); 

我的结果是大部分时间1毫秒都没问题,但有时我会得到双倍期。看到1.95ms左右的小凹凸 multimediatimerHistogram http://www.freeimagehosting.net/uploads/8b78f2fa6d.png

我的第一个想法是,也许我的方法运行时间过长。但我已经测量过了,情况并非如此。

排队计时器API

我的下一次尝试是使用带有

的queud计时器API
hTimerQueue = CreateTimerQueue();
if(hTimerQueue == NULL)
{
printf("Error creating queue: 0x%x\n", GetLastError());
}

BOOL res = CreateTimerQueueTimer(
&hTimer, 
hTimerQueue, 
TimerProc, 
NULL, 
0, 
1,  // 1ms
    WT_EXECUTEDEFAULT);

但结果也不如预期。现在我大部分时间都是2毫秒的周期时间。 queuedTimer http://www.freeimagehosting.net/uploads/2a46259a15.png

测量

为了测量时间,我使用了QueryPerformanceCounter和QueryPerformanceFrequency方法。

问题

所以现在我的问题是,是否有人在Windows下遇到过类似的问题,甚至可能找到解决方案?

感谢。

3 个答案:

答案 0 :(得分:5)

如果没有实时操作系统, 希望您的功能名为 1毫秒。

在不是实时操作系统的Windows上(对于Linux来说,它类似),一个以微秒精度重复读取当前时间并在直方图中存储连续差异的程序有一个非空的bin> 10女士!这意味着有时您将有2毫秒,但您也可以在通话之间获得更多。

答案 1 :(得分:1)

NtQueryTimerResolution()的调用将返回 ActualResolution 的值。在您的情况下,实际分辨率几乎肯定是0.9765625毫秒。这正是您在第一个图中显示的内容。 大约1.95 ms的第二次出现更精确Sleep(1) = 1.9531 ms = 2 x 0.9765625 ms

我猜中断周期接近1ms(0.9765625)。

现在麻烦开始了:当所需的延迟到期时,定时器发出信号。

假设 ActualResolution 设置为0.9765625,系统的中断心跳将以0.9765625 ms周期或1024 Hz运行,并且调用Sleep时所需的延迟为1女士。有两种情况需要考虑:

  1. 打电话<在下一个中断之前1ms(ΔT)。下一个中断不会确认所需的时间段已过期。只有以下中断才会导致调用返回。产生的睡眠延迟将为ΔT+ 0.9765625 ms。
  2. 在下一个中断之前调用> = 1ms(ΔT)。下一个中断将强制呼叫返回。产生的睡眠延迟将为ΔT。
  3. 因此,结果很大程度上取决于调用的时间,因此您可能会观察到0.98ms事件以及1.95ms事件。

    编辑:使用CreateTimerQueueTimer会将观察到的延迟推至1.95,因为计时器滴答(中断周期)为0.9765625 ms。在中断的第一次出现时,所请求的1ms的持续时间尚未完全到期,因此TimerProc仅在第二次中断(2×0.9765625ms = 1.953125ms> 1ms)之后被触发。因此,queueTimer图显示峰值为1.953125 ms。

    注意:此行为很大程度上取决于底层硬件。

    可在Windows Timestamp Project

    找到更多详情

答案 2 :(得分:0)

您可以尝试在程序启动时运行timeBeginPeriod(1)并在退出前timeEndPeriod(1)运行。这个可能可以提高计时器的精确度。