• <label id="pxtpz"><meter id="pxtpz"></meter></label>
      1. <span id="pxtpz"><optgroup id="pxtpz"></optgroup></span>

        當前位置:雨林木風下載站 > 技術開發教程 > 詳細頁面

        運用delphi創建精確計數器

        運用delphi創建精確計數器

        更新時間:2022-04-28 文章作者:未知 信息來源:網絡 閱讀次數:

        在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);
                    application.processmessages;
            end;
          end;
        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.

               運行程序,點擊“開始倒記時”按鈕,程序開始60秒倒記時,由于上面的程序只涉及了記時器程序的原理而沒有將錯誤處理加入其中,所以不要等60秒倒記時結束。點擊“結束倒記時”按鈕可以結束倒記時。這時在彈出對話框中會顯示實際經過的時間(單位為毫秒),將三個文本框內的時間乘以1000再加上實際經過的時間,越接近60000,則記時精度越高。

        下面是在我的機器上的執行結果。
               從上面的結果看,由delphi的timer控件建立的記時器的精度十分差,無法在實際中使用,而利用高性能頻率記數法和多媒體計數器法的誤差都在1%以下。考慮到程序中在文本框中顯示時間對程序所造成的影響,這個誤差在應用中是完全可以忽略的。
        另外在運行程序時作者還發現一個問題,如果在倒記時時拖動窗口,文本框中的顯示都會停止,而當停止窗口拖放后,多媒體記時器顯示會跳過這段時間記時,而其它兩種記時器顯示倒記時卻還是從原來的時間倒數。這說明多媒體記時器是在獨立的線程中運行的,不會受到程序的影響。

        綜合上面的介紹和范例,我們可以看到,如果要建立高精度的記時器,使用多媒體記時器是比較好的選擇。而高性能頻率記數法比較適合計算某個耗時十分短的過程所消耗的時間(例如分析程序中某個被多次調用的程序段執行時間以優化程序),因為畢竟高性能頻率記數的理論可以達到微秒級別。timer控件雖然精度比上面兩者差很多,但是它使用方便,在要求不高的場合它還是最佳選擇。

        (最后要說的是,以上的結果都是在windows 9x下獲得的,作者在windows 2000下運行該程序時發現,timer控件的精度比在windows 9x下要高出很多,一般誤差在5%以下,這說明windows 2000是一個真正的多任務操作系統。再加上windows nt\2000的穩定性和易用性,在工業控制或實時檢測等領域是一個比較完美的平臺)

        溫馨提示:喜歡本站的話,請收藏一下本站!

        本類教程下載

        系統下載排行

        主站蜘蛛池模板: 亚洲成a人片在线不卡| 狠狠色伊人亚洲综合成人| 亚洲国产成人精品青青草原| 日本高清不卡aⅴ免费网站| 亚洲男人的天堂一区二区| 粉色视频在线观看www免费| 日韩免费毛片视频| 男女猛烈xx00免费视频试看| 亚洲A∨精品一区二区三区| 无码精品人妻一区二区三区免费 | 91福利视频免费| 精品日韩亚洲AV无码一区二区三区 | 国产乱子精品免费视观看片| 亚洲熟妇色自偷自拍另类| 久久受www免费人成_看片中文| 2017亚洲男人天堂一| 日本免费一本天堂在线| 免费VA在线观看无码| 精品国产香蕉伊思人在线在线亚洲一区二区| 国产免费内射又粗又爽密桃视频 | 久久久久久亚洲精品不卡| 中国黄色免费网站| 亚洲色av性色在线观无码| 我要看WWW免费看插插视频| 美女免费视频一区二区三区| 国产自偷亚洲精品页65页| h视频在线观看免费完整版| 亚洲爆乳大丰满无码专区| 久久伊人亚洲AV无码网站| 51精品视频免费国产专区| 亚洲日本一线产区和二线产区对比| 免费人成在线观看网站视频| 免费h视频在线观看| 亚洲日韩看片无码电影| 亚洲美女又黄又爽在线观看| 99久久这里只精品国产免费| 免费国产高清毛不卡片基地| 亚洲黄网站wwwwww| 免费午夜爽爽爽WWW视频十八禁| 嫩草成人永久免费观看| 亚洲精品无码久久久久久|