越精确越好

解决方案 »

  1.   

    这个问题很早就有人问了,只不过每人解决
    我把上次的方法搬出来参考
    1)timer
    2)gettickcount settickcount
    3)sleep
    4)创建一个超时的event。
      

  2.   


    Win95下高精度定时器的实现  
    国防科技大学机电工程与仪器系  
    张云洲 梁科山  
    ---- 在工业控制软件中,数据采集和实时控制是经常性的工作。目前,工业控制 
    软件已经从DOS和Windows3.x平台,转到了Windows95上。然而,Windows95并不能 
    直接支持中断,这就意味着在DOS和Windows3.x中的定时器中断不能为我们所用。 
    因此,我们必须寻求新的定时方式。  
     
    ---- 在C++ Builder和Delphi等典型的编程语言中,都提供了定时器控件,可以方 
    便地实现定时和事件响应。此外,Windows95还提供了SetTimer和KillTimer函数来 
    设置和删除一个定时器,在事件WM_TIMER响应函数中实现处理。然而,遗憾的是, 
    通过这些方式获得的Win95定时器最小只能精确到55毫秒,对于55毫秒以下的时间 
    精度便无能为力。这对于Win95下测控软件的开发是十分不利的。幸运的是,多媒 
    体定时器可以解决这一难题。  
     
    ---- 以下是一个完整的多媒体定时器设计示例程序,该定时器的精度为1毫秒。该 
    程序的内容十分简单:按下按钮1,启动定时器,在Edit框中显示定时值(计数值 
    ),按下按钮2则将关闭定时器。此程序在Windows95环境下,采用C++Builder3.0 
    编程并编译通过,但设计思想同样适用于其它高级语言。按照本程序中的实现方法 
    ,读者将可以轻松实现自己的高精度定时器。  
     
    ---- 程序清单如下:  
     
    #include < vcl.h > 
    #pragma hdrstop 
     
    #include "mmsystem.h"   //包含多媒体定时器函数的头文件 
    #define MilliSecond  1  //定时间隔1毫秒 
    #define Accuracy     1  //系统允许的分辨率最小值 
     
    #define Min(x,y)  ((x < y) ? x : y) 
    #define Max(x,y)  ((x > y) ? x : y) 
     
    #include "HighTimerU.h" 
    //------------------------------------------------ 
    #pragma package(smart_init) 
    #pragma resource "*.dfm" 
    UINT TimerID;    //定义定时器句柄 
    int count;       //定义一个变量以进行计数 
    int TimerAccuracy; 
    TForm1 *Form1; 
    //------------------------------------------------ 
    __fastcall TForm1::TForm1(TComponent* Owner) 
        : TForm(Owner) 


     
    void PASCAL TimerCallProc(UINT   
    TimerID, UINT msg,DWORD dwUser, 
               DWORD dwa,DWORD dwb)   
    //定义定时器事件的调用函数 

        count++; 
        Form1- >Edit1->Text=count;    
     //在一个编辑框内显示计数值,即定时值 

     
    //--------------------------------------------------- 
    void __fastcall TForm1::Button1Click(TObject *Sender) 

        TIMECAPS timecaps; 
        int TimerResolution; 
     
     //从系统获得关于定时器服务能力的信息, 
    //分辨率不能超出系统许可值(1到16毫秒) 
      if (timeGetDevCaps(&timecaps,sizeof( 
            TIMECAPS))==TIMERR_NOERROR) 
          TimerAccuracy=Min(Max(timecaps.wPeriodMin, 
            Accuracy),timecaps.wPeriodMax); 
     
        timeBeginPeriod(TimerAccuracy);   
    //设置定时器分辨率 
       
        TimerResolution=1;    //设置定时间隔为1毫秒 
     
       //产生间隔1毫秒,周期执行的定时器事件;启动定时器 
        TimerID = timeSetEvent(TimerResolution,TimerAccuracy, 
                            &TimerCallProc,1,TIME_PERIODIC); 

    //------------------------------------------------------- 
    void __fastcall TForm1::Button2Click(TObject *Sender) 

        timeKillEvent(TimerID);        //删除定时器事件 
        timeEndPeriod(TimerAccuracy);  //清除定时器分辨率 

     
    ---- 多媒体定时器对实现高精度定时是很理想的工具,而且其精度是十分可靠的 
    。但是,多媒体定时器也并不是完美的。因为它可靠的精度是建立在对系统资源的 
    消耗之上的。因此,在利用多媒体定时器完成工作的同时,必须注意以下几点:  
     
    ---- 1. 多媒体定时器的设置分辨率不能超出系统许可范围。  
     
    ---- 2. 在使用完定时器以后,一定要及时删除定时器及其分辨率,否则系统会 
    越来越慢。  
     
    ---- 3. 多媒体定时器在启动时,将自动开辟一个独立的线程。在定时器线程结 
    束之前,注意一定不能再次启动该定时器不然迅速造成死机 
      

  3.   

    Windows 95 中 的 定 时 器 的 应 用  
    李 振  
    ---- 在windows95 编 程 中 有 时 要 用 到 定 时 器 的 功 能, 大 家 常 用 的 是 
     通 过SetTimer 函 数 设 置 一 个 定 时 器, 在 事 件WM_TIMER 响 应 函 数 中 处 
     理, 然 后 用KillTimer 函 数 取 消 此 定 时 器。 但 此 种 方 式 的 定 时 器  
    只 能 精 确 到 大 约55 毫 秒, 对 于55 毫 秒 以 下 的 时 间 精 度 便 无 能 为  
    力。  
     
    ---- 笔 者 在 这 里 向 大 家 提 供 一 个 可 以 精 确 到1 毫 秒 的 定 时 器 —  
    — 多 媒 体 定 时 器。 它 主 要 通 过 以 下 函 数 来 实 现:  
     
    ---- timeBeginPeriod — — 建 立 应 用 程 序 使 用 的 定 时 器 分 辨 率;  
     
    ---- timeEndPeriod — — 清 除 前 面 用timeBeginPeriod 函 数 建 立 的 最 小 定 
     时 器 分 辨 率;  
     
    ---- timeSetEvent — — 产 生 一 个 在 指 定 的 时 间 或 时 间 周 期 间 隔 内  
    执 行 的 定 时 器 事 件;  
     
    ---- timeKillEvent — — 删 除 前 面 用timeSetEvent 产 生 的 定 时 器 事 件;  
     
     
    ---- timeGetDevCaps — — 返 回 关 于 定 时 器 服 务 能 力 的 信 息。  
     
    ---- 下 面 就 结 合 一 段 程 序 来 具 体 说 明 它 的 用 法。 这 段 程 序 的 主 
     要 功 能 是: 设 置 两 个 时 钟 定 时 器, 一 个 间 隔 是1 毫 秒, 一 个 间  
    隔 是2 秒, 每 执 行 一 次, 输 出 当 前 系 统 时 钟 值 到 文 件“cure.out”, 
     以 比 较 此 定 时 器 的 精 确 度。( 此 程 序 在 中 文windows95 及Microsoft  
    VC5.0 编 译 通 过。 只 节 取 与 定 时 器 有 关 的 部 分 程 序。)  
     
    #include < stdio.h > 
    //包含所用系统函数的头文件,  
    如果编译有问题,可调整此语句的位置 
    #include < mmsystem.h > 
     
    //定义1毫秒和2秒时钟间隔,以毫秒为单位 
    #define ONE_MILLI_SECOND1 
    #define TWO_SECOND 2000 
    //定义时钟分辨率,以毫秒为单位 
    #define TIMER_ACCURACY1 
     
    UINT wTimerRes_1ms,wTimerRes_2s;  //定义时间间隔 
    UINT wAccuracy;//定义分辨率 
    UINT TimerID_1ms,TimerID_2s;//定义定时器句柄 
     
    CCureApp::CCureApp() 
    ∶  fout("cure.out", ios::out)//打开输出文件“cure.out” 

    // TODO: add construction code here, 
    // Place all significant  
           initialization in InitInstance 
    //给时间间隔变量赋值 
    wTimerRes_1ms = ONE_MILLI_SECOND ; 
    wTimerRes_2s = TWO_SECOND; 
     
    TIMECAPS  tc; 
    //通过函数timeGetDevCaps取出系统 
    的分辨率取值范围(对intel系统, 
    1~16毫秒),//如果无错则继续 
    if(timeGetDevCaps(&tc, sizeof(TIMECAPS))  
    == TIMERR_NOERROR) 

    //分辨率的值不能超出系统的取值范围 
    wAccuracy = min(max(tc.wPeriodMin,  
    TIMER_ACCURACY),tc.wPeriodMax); 
    //调用timeBeginPeriod函数设置定时器 
    的分辨率,类似于for循环的步长 
    timeBeginPeriod(wAccuracy); 
    //设置定时器 
    InitializeTimer(); 


     
    CCureApp::~CCureApp() 

    //结束时钟 
    fout < <  "结束时钟" < <  endl; 
    //删除两个定时器 
    timeKillEvent(TimerID_1ms); 
    timeKillEvent(TimerID_2s); 
    //删除设置的分辨率 
    timeEndPeriod(wAccuracy); 

    注:使用完的定时器及分辨率一定 
    要删除,否则系统会越来越慢。 
     
    void CCureApp::InitializeTimer() 

    StartOneMilliSecondTimer(); 
    StartTwoSecondTimer(); 

     
    //一毫秒定时器的回调函数, 
    类似于中断处理程序 
    voidPASCAL//一定要声明为全局PASCAL函数, 
    否则编译会有问题 
    OneMilliSecondProc(UINT wTimerID, UINT msg, 
    DWORD dwUser, DWORD dw1, DWORD dw2) 

    static int ms = 0;//定义计数器 
    CCureApp *app = (CCureApp *)dwUser; 
    //取得系统时间以毫秒为单位 
    DWORD osBinaryTime = GetTickCount(); 
    //输出计数器值和当前系统时间到文件  
    app- >fout < <  ++ms < <  ": 1ms : " 
     < <  osBinaryTime < <  endl; 

     
    //加装1毫秒定时器 
    void  CCureApp::StartOneMilliSecondTimer() 

    if((TimerID_1ms = timeSetEvent(wTimerRes_1ms, wAccuracy, 
     (LPTIMECALLBACK) OneMilliSecondProc,//回调函数 
     (DWORD)this,//用户自传送到回调函数的数据 
    /*周期调用,只使用一次用TIME_ONESHOT*/ 
    TIME_PERIODIC)) == 0) 

    AfxMessageBox("不能计时", MB_OK | MB_ICONASTERISK); 

    else//不等于0表明加装成功,  
    返回此定时器的句柄 
    fout < <  "16ms计时:" < <  endl; 

     
    以下为2秒定时器的回调函 
    数和加装函数,与1毫秒的类似; 
    void  PASCAL 
    TwoSecondProc(UINT wTimerID, UINT msg, 
      DWORD dwUser, DWORD dw1, DWORD dw2) 

    static int s = 0; 
    CCureApp *app = (CCureApp *)dwUser; 
    DWORD osBinaryTime = GetTickCount();  
    app- >fout < <  "*********************** 
    ***********************" < <  endl; 
    app- >fout < <  ++s < <  ": 2s : " 
     < <  osBinaryTime < <  endl; 

     
    void CCureApp::StartTwoSecondTimer() 

    if((TimerID_2s = timeSetEvent(wTimerRes_2s, wAccuracy, 
     (LPTIMECALLBACK) TwoSecondProc, 
     (DWORD)this, 
      TIME_PERIODIC)) == 0) 

    AfxMessageBox("不能计时", MB_OK | MB_ICONASTERISK); 

    else 
    fout < <  "2s计时:" < <  endl; 

     
      

  4.   

    其实多媒体计时器的原理跟SetTimer()产生计时器的原理是一样的,
    都是产生一个系统全局资源,运行在独立的线程中,定时到后调用回调函数
    区别就是多媒体计时器能够达到1ms的精度,
    而SetTimer()只能达到55毫秒的精度。可以參考一下:
    http://www2.ccw.com.cn/tips/2k01/011203_03.asp
    http://www.gjwtech.com/scomm/sc2vc6highspeedcom.htm
    http://www.5xsoft.com/data/200112/2908075501.htm
    http://sanjianxia.myrice.com/vc/vc96.htm
    http://landcad.sdau.edu.cn/language/vc/vc17.html
    ...
      

  5.   

    GetTickCount();
    Return Values:
    The return value is the number of milliseconds that have elapsed since the system was started