利用delphi建立精确计数器_第1页
利用delphi建立精确计数器_第2页
利用delphi建立精确计数器_第3页
利用delphi建立精确计数器_第4页
利用delphi建立精确计数器_第5页
全文预览已结束

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、利用delphi建立精确计数器在delphi中最常用的是timer控件,它的设置和使用都非常方便,理论上它的记时精度可以达到1ms(毫秒)。但是众所周知的,实际上timer在记时间隔小于50ms之下是精度是十分差的。它只适用于对于精度要求不太高的场合。 这里作者要介绍的是两种利用windows api函数实现精确记时的方法。第一中方法是利用高性能频率记数(作者本人的称呼)法。利用这种方法要使用两个api函数queryperformancefrequency和queryperformancecounter。queryperformancefrequency函数获得高性能频率记数器的震荡频率。调用

2、该函数后,函数会将系统频率记数器的震荡频率(每毫秒)保存到一个largeinteger中。不过利用该函数在几台机器上做过试验,结果都是1193180。读者朋友可以在自己的机器上试一下queryperformancecounter函数获得系统频率记数器的震荡次数,结果也保存到一个largenteger中。很显然,如果在计时中首先使用queryperformancefrequency获得高性能频率记数器每毫秒的震荡次数,然后在计时开始时使用queryperformancecounter函数获得当前系统频率记数器的震荡次数。在计时结束时再调用queryperformancecounter函数获得系统

3、频率记数器的震荡次数。将两者相减,再将结果除以频率记数器每毫秒的震荡次数,就可以获得某一事件经过的准确时间。(次数除以频率等于时间)另外的一种精确记时器的功能是利用多媒体记时器函数(这也是作者的定义,因为这个系列的函数是在winmm.dll中定义并且是为媒体播放服务的)。实现多媒体记时器首先要使用timesetevent函数建立计时事件。该函数在delphi中的mmsystem.pas中有定义,定义如下:function timesetevent(udelay, uresolution: uint; lpfunction: tfntimecallback; dwuser: dword; ufl

4、ags: uint): mmresult; stdcall函数定义中参数udelay定义延迟时间,以毫秒为单位,该参数相当于timer控件的interval属性。参数uresolution定义记时精度,如果要求尽可能高的精度,要将该参数设置为0;参数lpfunction定义了timesetevent函数的回调函数。该函数相当于一个定时中断处理函数,每当经过一个udelay长度的时间间隔,该函数就会被调用,编程者可以在该函数中加入相应的处理语句。参数dwuser定义用户自定义的回调值,该值将传递给回调函数。参数uflags定义定时类型,如果要不间断的记时,该值应设置为1。如果函数调用成功,在系统

5、中建立了一个多媒体记时器对象,每当经过一个udelay时间后lpfunction指定的函数都会被调用。同时函数返回一个对象标识,如果不再需要记时器则必须要使用timekillevent函数删除记时器对象。由于windows是一个多任务的操作系统,因此基于api调用的记时器的精度都会受到其它很多因素的干扰。到底这两中记时器的精度如何,我们来使用以下的程序进行验证:设置三种记时器(timer控件、高性能频率记数、多媒体记时器)。将它们的定时间隔设置为10毫秒,让它们不停工作直到达到一个比较长的时间(比如60秒),这样记时器的误差会被累计下来,然后同实际经过的时间相比较,就可以得到它们的精度。下面是

6、具体的检测程序。unit unit1;interfaceuses 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); proce

7、dure 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; protimec

8、allback: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.e

9、nabled :=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.ca

10、ption :='开始倒计时' 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.enable

11、d :=true; button1.enabled :=false; timer1.enabled :=true; erval :=10; protimecallback:=timeproc; htimeid:=timesetevent(10,0,protimecallback,1,1); acttime1:=gettickcount; /获得系统的高性能频率计数器在一毫秒内的震动次数 queryperformancefrequency(lgper); ftemp:=lgper/1000; iten:=trunc(ftemp*10); queryperformancecou

12、nter(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); cessmessages; end; end;

13、end;procedure tform1.timer1timer(sender: tobject);begin edit1.text := floattostr(stimercount); stimercount:=stimercount-0.01;end;procedure tform1.button2click(sender: tobject);begin proendcount; /显示从开始记数到记数实际经过的时间 showmessage('实际经过时间'+inttostr(acttime2)+'毫秒');end;end. 运行程序,点击“开始倒记时”按

14、钮,程序开始60秒倒记时,由于上面的程序只涉及了记时器程序的原理而没有将错误处理加入其中,所以不要等60秒倒记时结束。点击“结束倒记时”按钮可以结束倒记时。这时在弹出对话框中会显示实际经过的时间(单位为毫秒),将三个文本框内的时间乘以1000再加上实际经过的时间,越接近60000,则记时精度越高。 从上面的结果看,由delphi的timer控件建立的记时器的精度十分差,无法在实际中使用,而利用高性能频率记数法和多媒体计数器法的误差都在1%以下。考虑到程序中在文本框中显示时间对程序所造成的影响,这个误差在应用中是完全可以忽略的。另外在运行程序时作者还发现一个问题,如果在倒记时时拖动窗口,文本框中

15、的显示都会停止,而当停止窗口拖放后,多媒体记时器显示会跳过这段时间记时,而其它两种记时器显示倒记时却还是从原来的时间倒数。这说明多媒体记时器是在独立的线程中运行的,不会受到程序的影响。综合上面的介绍和范例,我们可以看到,如果要建立高精度的记时器,使用多媒体记时器是比较好的选择。而高性能频率记数法比较适合计算某个耗时十分短的过程所消耗的时间(例如分析程序中某个被多次调用的程序段执行时间以优化程序),因为毕竟高性能频率记数的理论可以达到微秒级别。timer控件虽然精度比上面两者差很多,但是它使用方便,在要求不高的场合它还是最佳选择。下面为一些常用的日期处理函数:var   Da

16、teTime,MyDate,MyTime : TDateTime;   DateStr,TimeStr:string;begin   DateTime := Now;                     /返回当前日期时间   DateStr:= DateToStr(DateTime);   /转换日期为字符串 ,

17、例如:01/08/96   TimeStr := TimeToStr(DateTime);   /转换时间为字符串,例如:20:50  MyDate:= StrToDate(DateStr); /转换字符串为日期  MyTime:= StrToTime(TimeStr); /转换字符串为时间  DateTime:= MyDate + MyTime; /相加得到datetime  DateTime   := DateTime + (15/60/24);/加15分钟  DateStr:= FormatDateTime('yyyy-mmmm-dd',MyDate);  1996-January-08  DateStr:= FormatDateTime('mmm,d,yy,ddd',MyDate);  Jan,8,96,Mon  DateStr:= FormatDateTime('dddd/dd/mm/yy',MyDate); Monday/08/01/96  TimeStr:= FormatDateTime('t',MyTime);  &

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论