如何在VB中做精确度高的计时器??

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在VB中做精确度高的计时器??相关的知识,希望对你有一定的参考价值。

我想用VB做一个类似于秒表一样的计时器,timer控件的精确度太差了,即使频率调到10 ms,一分钟也会相差十几秒。怎么做高精度的计时器啊?我理想的状态是在频率10 ms的情况下十分钟的误差率在1秒以内,这可以吗??
调用系统时间怎样调用到毫秒级啊?我不会

用ccrptimer控件。我做项目时用过的,精度很高(1ms)。我在参考资料中给你下载地址。
里面有用法。

如果英文看不明白,我翻译的有中文,给我联系发给你。

补充:
1.
在一个窗体或类模块的声明部分放置一条类似与下面的声明:

Private WithEvents Timer1 As ccrpTimer
2.在Form_Load 中初始化ccrpTimer对象。
Set Timer1 = New ccrpTimer
timer1.interval=1000 '设置Timer事件多久发生一次
3.Private Sub Timer1_Timer()
'你想要的各种功能
End Sub

参考资料:http://vb.mvps.org/tools/ccrpTmr/

参考技术A 调用windows的系统时间
懂不?
自己想想

GetSystemTim 用这个api
很简单
不会找我

' 用API函数GetSystemTime或GetLocalTime返回的SYSTEMTIME结构的参数获得系统日期和精确到毫秒的系统时间?
' GetSystemTime返回UTC时间,GetLocalTime返回当地时间。
Private Declare Sub GetSystemTime Lib "kernel32" (lpSystemTime As SYSTEMTIME)
Private Declare Sub GetLocalTime Lib "kernel32" (lpSystemTime As SYSTEMTIME)

Private Type SYSTEMTIME
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type

Private Sub Timer1_Timer()
Dim s As String
Dim s1 As String
Dim sys As SYSTEMTIME
GetLocalTime sys '获得本地机器时间
'GetSystemTime sys '获得机器的开机总时间
s = CStr(sys.wYear) + "," + CStr(sys.wMonth) + "," + CStr(sys.wDay)
Label1.Caption = s
s1 = CStr(sys.wHour) + ":" + CStr(sys.wMinute) + ":" + CStr(sys.wSecond) + ":" + CStr(sys.wMilliseconds)
Label2.Caption = s1
End Sub
参考技术B 不要用被动的累加计时,而用主动的系统时间相减得结果

delphi timer的用法

1、timer.enable:=false;的时候,就会停止,变成true的时候又会重新计时,有没有办法让它继续计时。或者把已经计了多久读取出来,然后扣掉?
2、ttime这种可是读取出来的时间通过timetodouble,得到的单位是什么?好像不是毫秒。

利用Delphi建立精确计数器

在Windows中的很多场合下编程(例如工业控制、游戏)中需要比较精确的记时器,本文讨论的是在Delphi下实现记时器的若干方法以及它们的精度控制问题。

在Delphi中最常用的是Timer控件,它的设置和使用都非常方便,理论上它的记时精度可以达到1ms(毫秒)。但是众所周知的,实际上Timer在记时间隔小于50ms之下是精度是十分差的。它只适用于对于精度要求不太高的场合。

这里作者要介绍的是两种利用Windows API函数实现精确记时的方法。第一中方法是利用高性能频率记数(作者本人的称呼)法。利用这种方法要使用两个API函数QueryPerformanceFrequency和QueryPerformanceCounter。QueryPerformanceFrequency函数获得高性能频率记数器的震荡频率。

调用该函数后,函数会将系统频率记数器的震荡频率(每毫秒)保存到一个LargeInteger中。不过利用该函数在几台机器上做过试验,结果都是1193180。读者朋友可以在自己的机器上试一下

QueryPerformanceCounter函数获得系统频率记数器的震荡次数,结果也保存到一个Largenteger中。

很显然,如果在计时中首先使用QueryPerformanceFrequency获得高性能频率记数器每毫秒的震荡次数,然后在计时开始时使用QueryPerformanceCounter函数获得当前系统频率记数器的震荡次数。在计时结束时再调用QueryPerformanceCounter函数获得系统频率记数器的震荡次数。将两者相减,再将结果除以频率记数器每毫秒的震荡次数,就可以获得某一事件经过的准确时间。(次数除以频率等于时间)

另外的一种精确记时器的功能是利用多媒体记时器函数(这也是作者的定义,因为这个系列的函数是在Winmm.dll中定义并且是为媒体播放服务的)。

实现多媒体记时器首先要使用timeSetEvent函数建立计时事件。该函数在Delphi中的mmsystem.pas中有定义,定义如下:

function timeSetEvent(uDelay, uResolution: UINT;

lpFunction: TFNTimeCallBack; dwUser: DWORD; uFlags: UINT): MMRESULT; stdcall

函数定义中参数uDelay定义延迟时间,以毫秒为单位,该参数相当于Timer控件的Interval属性。参数uResolution定义记时精度,如果要求尽可能高的精度,要将该参数设置为0;参数lpFunction定义了timeSetEvent函数的回调函数。该函数相当于一个定时中断处理函数,每当经过一个uDelay长度的时间间隔,该函数就会被调用,编程者可以在该函数中加入相应的处理语句。参数dwUser定义用户自定义的回调值,该值将传递给回调函数。参数uFlags定义定时类型,如果要不间断的记时,该值应设置为1。

如果函数调用成功,在系统中建立了一个多媒体记时器对象,每当经过一个uDelay时间后lpFunction指定的函数都会被调用。同时函数返回一个对象标识,如果不再需要记时器则必须要使用timeKillEvent函数删除记时器对象。

由于Windows是一个多任务的操作系统,因此基于API调用的记时器的精度都会受到其它很多因素的干扰。到底这两中记时器的精度如何,我们来使用以下的程序进行验证:

设置三种记时器(Timer控件、高性能频率记数、多媒体记时器)。将它们的定时间隔设置为10毫秒,让它们不停工作直到达到一个比较长的时间(比如60秒),这样记时器的误差会被累计下来,然后同实际经过的时间相比较,就可以得到它们的精度。

下面是具体的检测程序。

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

StdCtrls, ExtCtrls,mmSystem;

type

TForm1 = class(TForm)

Edit1: TEdit;

Edit2: TEdit;

Edit3: TEdit;

Button1: TButton;

Button2: TButton;

Timer1: TTimer;

procedure FormCreate(Sender: TObject);

procedure Button1Click(Sender: TObject);

procedure Timer1Timer(Sender: TObject);

procedure Button2Click(Sender: TObject);

private

Private declarations

public

Public declarations

end;

var

Form1: TForm1;

actTime1,actTime2:Cardinal;

smmCount,sTimerCount,sPCount:Single;

hTimeID:Integer;

iTen:Integer;

proTimeCallBack:TFNTimeCallBack;

procedure TimeProc(uTimerID, uMessage: UINT;

dwUser, dw1, dw2: DWORD) stdcall;

procedure proEndCount;

implementation

$R *.DFM

//timeSetEvent的回调函数

procedure proEndCount;

begin

actTime2:=GetTickCount-actTime1;

Form1.Button2.Enabled :=False;

Form1.Button1.Enabled :=TRue;

Form1.Timer1.Enabled :=False;

smmCount:=60;

sTimerCount:=60;

spCount:=-1;

timeKillEvent(hTimeID);

end;

procedure TimeProc(uTimerID, uMessage: UINT;

dwUser, dw1, dw2: DWORD) stdcall;

begin

Form1.Edit2.Text:=FloatToStr(smmCount);

smmCount:=smmCount-0.01;

end;

procedure TForm1.FormCreate(Sender: TObject);

begin

Button1.Caption :='开始倒计时';

Button2.Caption :='结束倒计时';

Button2.Enabled :=False;

Button1.Enabled :=True;

Timer1.Enabled :=False;

smmCount:=60;

sTimerCount:=60;

sPCount:=60;

end;

procedure TForm1.Button1Click(Sender: TObject);

var

lgTick1,lgTick2,lgPer:TLargeInteger;

fTemp:Single;

begin

Button2.Enabled :=True;

Button1.Enabled :=False;

Timer1.Enabled :=True;

Timer1.Interval :=10;

proTimeCallback:=TimeProc;

hTimeID:=timeSetEvent(10,0,proTimeCallback,1,1);

actTime1:=GetTickCount;

//获得系统的高性能频率计数器在一毫秒内的震动次数

QueryPerformanceFrequency(lgPer);

fTemp:=lgPer/1000;

iTen:=Trunc(fTemp*10);

QueryPerformanceCounter(lgTick1);

lgTick2:=lgTick1;

sPCount:=60;

while sPCount>0 do begin

QueryPerformanceCounter(lgTick2);

//如果时钟震动次数超过10毫秒的次数则刷新Edit3的显示

If lgTick2 - lgTick1 > iTen Then begin

lgTick1 := lgTick2;

sPCount := sPCount - 0.01;

Edit3.Text := FloatToStr(sPCount);
参考技术A GetTickCount返回的值是当前时间的毫秒数的,你可以在true的时候获取一次为N1,false的时候获取一次N2,那么N1-N2就是时差N3。下次在运行的话,就可以用你的10分钟转换为毫秒数后减去N3.
就是得到一直运行了多少毫秒,进而转换了追问

麻烦问下把这个函数加在哪?是timer1.enable:=true; i:=getTickCount; 然后再false的时候再getTickCount,然后相减么?

本回答被提问者和网友采纳
参考技术B 就是个定时器。Enabled就是开关,为False时这个东西就不工作了,里面的代码就不会被执行了。
它有个Interval属性,这个的单位是毫秒。当Enabled为True时,每隔Interval毫秒,就执行一次里面的代码。

比如,Interval设为1000,则每隔1000毫秒,里面的代码就被执行一次。追问

这我知道。
但我要的是暂停之后继续计时,比如
如果计时十分钟,到五分钟的时候暂停了,不要再从10分钟开始计,倒计时五分钟就可以了,用timer怎么做?

以上是关于如何在VB中做精确度高的计时器??的主要内容,如果未能解决你的问题,请参考以下文章

如何对自己的VB某段代码测试运行时间

在C语言中如何实现精确计时

如何在 iPhone 上精确播放声音?

如何只在 viewDidAppear 中做一些事情?

C++中如何精确计时

VB.net 如何设定准确的1秒时间?