`
snake_hand
  • 浏览: 624851 次
社区版块
存档分类
最新评论

VC++获得微秒级时间的方法与技巧探讨

 
阅读更多

获得微秒级的时间 收藏


Win 下建议如下方式:

http://www.vckbase.com/document/viewdoc/?id=1301

VC中基于 Windows 的精确定时

中国科学院光电技术研究所 游志宇

  在工业生产控制系统中,有许多需要定时完成的操作,如定时显示当前时间,定时刷新屏幕上的进度条,上位 机定时向下位机发送命令和传送数据等。特别是在对控制性能要求较高的实时控制系统和数据采集系统中,就更需要精确定时操作。
  众所周知,Windows 是基于消息机制的系统,任何事件的执行都是通过发送和接收消息来完成的。 这样就带来了一些问题,如一旦计算机的CPU被某个进程占用,或系统资源紧张时,发送到消息队列 中的消息就暂时被挂起,得不到实时处理。因此,不能简单地通过Windows消息引发一个对定时要求 严格的事件。另外,由于在Windows中已经封装了计算机底层硬件的访问,所以,要想通过直接利用 访问硬件来完成精确定时,也比较困难。所以在实际应用时,应针对具体定时精度的要求,采取相适 应的定时方法。
  VC中提供了很多关于时间操作的函数,利用它们控制程序能够精确地完成定时和计时操作。本文详细介绍了 VC中基于Windows的精确定时的七种方式,如下图所示:


图一 图像描述

  方式一:VC中的WM_TIMER消息映射能进行简单的时间控制。首先调用函数SetTimer()设置定时 间隔,如SetTimer(0,200,NULL)即为设置200ms的时间间隔。然后在应用程序中增加定时响应函数 OnTimer(),并在该函数中添加响应的处理语句,用来完成到达定时时间的操作。这种定时方法非常 简单,可以实现一定的定时功能,但其定时功能如同Sleep()函数的延时功能一样,精度非常低,最小 计时精度仅为30ms,CPU占用低,且定时器消息在多任务操作系统中的优先级很低,不能得到及时响 应,往往不能满足实时控制环境下的应用。只可以用来实现诸如位图的动态显示等对定时精度要求不高的情况。如示例工程中的Timer1。
  方式二:VC中使用sleep()函数实现延时,它的单位是ms,如延时2秒,用sleep(2000)。精度非常 低,最小计时精度仅为30ms,用sleep函数的不利处在于延时期间不能处理其他的消息,如果时间太 长,就好象死机一样,CPU占用率非常高,只能用于要求不高的延时程序中。如示例工程中的Timer2。
  方式三:利用COleDateTime类和COleDateTimeSpan类结合WINDOWS的消息处理过程来实现秒级延时。如示例工程中的Timer3和Timer3_1。以下是实现2秒的延时代码:


COleDateTime start_time = COleDateTime::GetCurrentTime();
COleDateTimeSpan end_time= COleDateTime::GetCurrentTime()-start_time;
while(end_time.GetTotalSeconds()< 2) //实现延时2秒
{
MSG msg;
GetMessage(&msg,NULL,0,0);
TranslateMessage(&msg);
DispatchMessage(&msg);

//以上四行是实现在延时或定时期间能处理其他的消息,
    //虽然这样可以降低CPU的占有率,
//但降低了延时或定时精度,实际应用中可以去掉。
end_time = COleDateTime::GetCurrentTime()-start_time;
} //这样在延时的时候我们也能够处理其他的消息。
  方式四:在精度要求较高的情况下,VC中可以利用GetTickCount()函数,该函数的返回值是 DWORD型,表示以ms为单位的计算机启动后经历的时间间隔。精度比WM_TIMER消息映射高,在较 短的定时中其计时误差为15ms,在较长的定时中其计时误差较低,如果定时时间太长,就好象死机一样,CPU占用率非常高,只能用于要求不高的延时程序中。如示例工程中的Timer4和Timer4_1。下列代码可以实现50ms的精确定时:
DWORD dwStart = GetTickCount();
DWORD dwEnd = dwStart;
do
{
dwEnd = GetTickCount()-dwStart;
}while(dwEnd <50);


为使GetTickCount()函数在延时或定时期间能处理其他的消息,可以把代码改为:

DWORD dwStart = GetTickCount();
DWORD dwEnd = dwStart;
do
{
MSG msg;
GetMessage(&msg,NULL,0,0);
TranslateMessage(&msg);
DispatchMessage(&msg);
dwEnd = GetTickCount()-dwStart;
}while(dwEnd <50);

虽然这样可以降低CPU的占有率,并在延时或定时期间也能处理其他的消息,但降低了延时或定时精度。
  方式五:与GetTickCount()函数类似的多媒体定时器函数DWORD timeGetTime(void),该函数定时精 度为ms级,返回从Windows启动开始经过的毫秒数。微软公司在其多媒体Windows中提供了精确定时器的底 层API持,利用多媒体定时器可以很精确地读出系统的当前时间,并且能在非常精确的时间间隔内完成一 个事件、函数或过程的调用。不同之处在于调用DWORD timeGetTime(void) 函数之前必须将 Winmm.lib 和 Mmsystem.h 添加到工程中,否则在编译时提示DWORD timeGetTime(void)函数未定义。由于使用该 函数是通过查询的方式进行定时控制的,所以,应该建立定时循环来进行定时事件的控制。如示例工程中的Timer5和Timer5_1。
  方式六:使用多媒体定时器timeSetEvent()函数,该函数定时精度为ms级。利用该函数可以实现周期性的函数调用。如示例工程中的Timer6和Timer6_1。函数的原型如下:
MMRESULT timeSetEvent( UINT uDelay,
UINT uResolution,
LPTIMECALLBACK lpTimeProc,
WORD dwUser,
UINT fuEvent )
  该函数设置一个定时回调事件,此事件可以是一个一次性事件或周期性事件。事件一旦被激活,便调用指定的回调函数, 成功后返回事件的标识符代码,否则返回NULL。函数的参数说明如下:
uDelay:以毫秒指定事件的周期。
Uresolution:以毫秒指定延时的精度,数值越小定时器事件分辨率越高。缺省值为1ms。
LpTimeProc:指向一个回调函数。
DwUser:存放用户提供的回调数据。
FuEvent:指定定时器事件类型:
TIME_ONESHOT:uDelay毫秒后只产生一次事件
TIME_PERIODIC :每隔uDelay毫秒周期性地产生事件。
  具体应用时,可以通过调用timeSetEvent()函数,将需要周期性执行的任务定义在LpTimeProc回调函数 中(如:定时采样、控制等),从而完成所需处理的事件。需要注意的是,任务处理的时间不能大于周期间隔时间。另外,在定时器使用完毕后, 应及时调用timeKillEvent()将之释放。

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

函数的原型如下:
BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
BOOL QueryPerformanceCounter(LARGE_INTEGER *lpCount);
  数据类型ARGE_INTEGER既可以是一个8字节长的整型数,也可以是两个4字节长的整型数的联合结构, 其具体用法根据编译器是否支持64位而定。该类型的定义如下:
typedef union _LARGE_INTEGER
{
struct
{
DWORD LowPart ; // 4字节整型数
LONG HighPart; // 4字节整型数
};
LONGLONG QuadPart ; // 8字节整型数

}LARGE_INTEGER ;
  在进行定时之前,先调用QueryPerformanceFrequency()函数获得机器内部定时器的时钟频率, 然后在需要严格定时的事件发生之前和发生之后分别调用QueryPerformanceCounter()函数,利用两次获得的计数之差及时钟频率,计算出事件经 历的精确时间。下列代码实现1ms的精确定时:
LARGE_INTEGER litmp;
LONGLONG QPart1,QPart2;
double dfMinus, dfFreq, dfTim;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart; // 获得计数器的时钟频率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart; // 获得初始值
do
{
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart; //获得中止值
dfMinus = (double)(QPart2-QPart1);
dfTim = dfMinus / dfFreq; // 获得对应的时间值,单位为秒
}while(dfTim<0.001);

  其定时误差不超过1微秒,精度与CPU等机器配置有关。 下面的程序用来测试函数Sleep(100)的精确持续时间:

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


  由于Sleep()函数自身的误差,上述程序每次执行的结果都会有微小误差。下列代码实现1微秒的精确定时:


LARGE_INTEGER litmp;
LONGLONG QPart1,QPart2;
double dfMinus, dfFreq, dfTim;
QueryPerformanceFrequency(&litmp);
dfFreq = (double)litmp.QuadPart; // 获得计数器的时钟频率
QueryPerformanceCounter(&litmp);
QPart1 = litmp.QuadPart; // 获得初始值
do
{
QueryPerformanceCounter(&litmp);
QPart2 = litmp.QuadPart; //获得中止值
dfMinus = (double)(QPart2-QPart1);
dfTim = dfMinus / dfFreq; // 获得对应的时间值,单位为秒
}while(dfTim<0.000001);

其定时误差一般不超过0.5微秒,精度与CPU等机器配置有关。(完)

====================================================


当精度要求比较高的时候,
一般都需要和系统结合起来,
如果用 标准库函数, 精度是没有那么高的。
jixingzhong(瞌睡虫:选择了远方,只顾风雨兼程!)
转贴的这片文章足够了

QueryPerformanceFrequency()函数的原理是获得时钟频率,计算两个频率的差值
从而得出时间来。
而这个数值和前面的几种方法得到数值一样,不能精确计算出代码执行的时间(对于定时足够了)
如果执行的代码还没有执行完成就到达轮训时间片,会放弃cpu,直到下次调用。
do
{
QueryPerformanceCounter(&litmp); //假如执行完这步的时候,当前的时间片已经用完,那么
任务调度管理器就会把CPU分配给队列里的下一个
进程.在下一个进程的时间片用完或者任务完成之前,
这里是无法执行的。

还有一个可能就是执行到这里的时候被其他的任务抢占。
这就要求此处的do...while是个相对于进程的原子操作
在可抢占式的调度算法下,如何实现呢?

一般的操作系统的时间片都是毫秒级的
一旦时间片落入“敌手”
计时的误差就可能会很大了


QPart2 = litmp.QuadPart; //获得中止值
dfMinus = (double)(QPart2-QPart1);
dfTim = dfMinus / dfFreq; // 获得对应的时间值,单位为秒
}while(dfTim<0.000001);

转载声明:本文来自CSDN博客,转载请标明出处http://blog.csdn.net/wanfustudio/archive/2006/10/18/1339921.aspx

分享到:
评论

相关推荐

    vc实现时间延时 延时时间 包括 秒 毫秒 微秒

    在VC++编程环境中,时间延迟是一个常见的需求,用于控制程序执行的节奏或者等待特定操作完成。标题和描述中提到的“vc实现时间延时”主要涉及到两种常见的方法:使用`Sleep`函数和采用消息泵机制。这两种方法在不同...

    delphi取微秒级时间间隔

    以上两种方法都能帮助你在Delphi中获取微秒级时间间隔,但需要注意的是,`QueryPerformanceCounter`和`TStopwatch`依赖于硬件的支持,可能在某些旧的或低性能的系统上表现不佳。因此,在实际应用中,应当考虑到这些...

    C/C++获取(毫秒/微秒/纳秒级)系统时间差方法大全

    在C/C++编程中,获取系统的毫秒、微秒或纳秒级时间差是常见的需求,特别是在性能测试、定时任务或者高精度计时场景中。本文将详细介绍四种常用的方法。 ### 方法一:利用 `SYSTEMTIME` `SYSTEMTIME` 结构体是...

    基于51单片机的精确延时(微秒级)

    标题中的“基于51单片机的精确延时(微秒级)”表明本文讨论的重点是针对51单片机进行精确的微秒级延时编程方法。51单片机是基于Intel 8051架构的微控制器,广泛应用于嵌入式系统和微型计算机控制系统中。由于其在工业...

    Linux下精确到微秒级的时间操作函数

    Linux下对时间进行运算,如果是到秒级的,一般是用time之类的函数实现。文中介绍了Linux下精确到微秒级的时间操作函数。主要是用到了gettimeofday函数,并且介绍了这个函数的结构。

    nrf52832微秒级定时器

    2. **设置预分频器**:根据需要的定时精度选择合适的预分频器值,以确保定时器的计数频率与目标微秒级间隔相匹配。 3. **设定比较值**:根据预分频器和期望的周期计算出定时器的比较寄存器值,这将决定定时器何时...

    C#微秒级计时器

    实现了微秒级计时器,提供一个类,风格和C#自带的定时器差不多,误差应该在1ms以内,这玩意想要真正十分精确还是得用硬件计时器才行.

    Windows平台 微秒级 延时程序_Window平台微秒级延迟_

    如何在Windows平台上实现微秒级延时, time相关函数实现的只是毫秒级的延时,有时无法满足精度要求,下面是一个微秒级延时的测试实例,测试OK。测试程序每间隔100us,计数器加1,计数器每增加10000,打印出当前的...

    Visual+C++实现微秒级精度定时器[借鉴].pdf

    在工产控制系统中,需要实现微秒级精度定时器来完成一些定时操作,如定时显示当前时间、定时刷新屏幕上的进度条、上位机定时向下位机发送命令和传送数据等。然而,Windows 是基于消息机制的系统,任何事件的执行都是...

    VC++获得当前系统时间的几种方案

    这种方法返回的是从某个固定时间点开始的秒数,适用于高性能计算或游戏开发等需要微秒级别时间间隔的应用。 总结起来,VC++获取当前系统时间的方式多样,可以根据实际需求选择适合的方法。标准库`chrono`提供了一种...

    真正的微秒定时器 ,实现毫秒精度的延时

    在IT领域,尤其是在游戏开发、实时系统或者高精度计时应用中,毫秒甚至微秒级别的延时控制是非常重要的。标题“真正的微秒定时器,实现毫秒精度的延时”指的是创建一个能够以微秒级别精度进行计时的定时器,确保程序...

    VC++ 时间控制

    本文将深入探讨VC++中的时间控制技术,主要包括标准库中的时间函数、Windows API时间函数以及自定义计时器的实现。 1. **标准库中的时间函数** C++标准库提供了`&lt;ctime&gt;`头文件,包含了处理时间的基本函数。例如:...

    vc++6.0 获取系统时间

    Windows API提供了`GetTickCount`和`GetSystemTimeAsFileTime`等函数,可以获取系统的毫秒级和精确到微秒的时间。而在MFC中,我们可以借助`CTime`和`CTimeSpan`类来简化这个过程。 1. **获取系统时间**: MFC中的`...

    高精度定时程序(微秒级)源代码 highrestimer

    基于Windows 的高精度实时定时程序,精度可达到微秒级,可以用来发送串口数据等

    VB 微秒级精确计时程序源码

    【工控老马出品,必属精品,亲测校正...资源名:VB 微秒级精确计时程序源码 资源类型:程序源代码 源码说明: 基于VB写的实现微秒级精确计时功能的程序源码 代码完整适合学习借鉴 适合人群:新手及有一定经验的开发人员

    VB 微秒级精确计时

    在VB(Visual Basic)编程环境中,微秒级精确计时是一项关键的技术,它允许开发者获取非常精确的时间间隔,这对于性能测试、实时应用或者任何需要精确时间控制的场合都非常有用。通常,VB内置的Timer控件并不能提供...

    C++计时类,统计时间可以精确到微秒级

    ### C++计时类——实现微秒级别的时间统计 在计算机科学领域,特别是软件开发过程中,对于程序执行效率的分析尤为重要。为了能够准确地测量代码片段的执行时间,开发者经常需要借助于计时工具来进行时间统计。本文...

    VC 微妙级定时的VC++源码工程

    在这个"VC 微妙级定时的VC++源码工程"中,我们可以深入探讨如何在Windows平台上实现这种高精度的定时功能。 在Windows操作系统中,传统的`Sleep()`函数或`QueryPerformanceCounter()` API并不足以实现微妙级的定时...

    毫秒定时器(VC++6.0)

    在这个"毫秒定时器(VC++6.0)"项目中,开发者可能通过创建一个后台线程来不断查询当前时间,并与目标时间进行比较,当达到预设的间隔时,触发相应的回调函数。这种方法可以避免主消息循环的阻塞,从而提高定时器的...

Global site tag (gtag.js) - Google Analytics