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

        當(dāng)前位置:雨林木風(fēng)下載站 > 技術(shù)開(kāi)發(fā)教程 > 詳細(xì)頁(yè)面

        VB高精度計(jì)時(shí)器編程的討論

        VB高精度計(jì)時(shí)器編程的討論

        更新時(shí)間:2022-05-14 文章作者:未知 信息來(lái)源:網(wǎng)絡(luò) 閱讀次數(shù):

             VB記時(shí)器編程的討論 在很多場(chǎng)合下編程(例如工業(yè)控制、游戲)中需要比較精確的記時(shí)器,本文討論的是在VB下實(shí)現(xiàn)記時(shí)器的若干方法以及它們的精度控制問(wèn)題。 在VB中最常用的是Timer控件,它的設(shè)置和使用都非常方便,理論上它的記時(shí)精度可以達(dá)到1ms(毫秒)。但是眾所周知的,實(shí)際上Timer在記時(shí)間隔小于50ms之下是精度是十分差的。它只適用于對(duì)于精度要求不太高的場(chǎng)合。 這里作者要介紹的是兩中利用Windows API函數(shù)實(shí)現(xiàn)精確記時(shí)的方法。第一中方法是利用高性能頻率記數(shù)(作者本人的稱呼)法。利用這種方法要使用兩個(gè)API函數(shù)QueryPerformanceFrequency和QueryPerformanceCounter。QueryPerformanceFrequency函數(shù)獲得高性能頻率記數(shù)器的震蕩頻率,該函數(shù)的定義如下:  

        Private Declare Function QueryPerformanceFrequency Lib "kernel32" _
                      (lpFrequency As LARGE_INTEGER) As Long
        函數(shù)中的數(shù)據(jù)結(jié)構(gòu)LARGE_INTEGER定義如下:
        Type LARGE_INTEGER
            lowpart As Long
            highpart As Long
        End Type

        調(diào)用該函數(shù)后,函數(shù)會(huì)將系統(tǒng)頻率記數(shù)器的震蕩頻率保存到lpPerformanceCount中,其中低位保存到lowpart中,高位保存到highpart中。但是現(xiàn)在的Windows沒(méi)有使用到hightpart(系統(tǒng)頻率記數(shù)器的震蕩頻率與計(jì)算機(jī)的主頻無(wú)關(guān),我在幾臺(tái)機(jī)上做過(guò)驗(yàn)證,都是lowpart為1193180,highpart為0)。
        QueryPerformanceCounter函數(shù)獲得系統(tǒng)頻率記數(shù)器的震蕩次數(shù),函數(shù)的定義如下

        Private Declare Function QueryPerformanceCounter Lib "kernel32" _
                (lpPerformanceCount As LARGE_INTEGER) As Long

        獲得記時(shí)器震蕩次數(shù)保存在lpPerformanceCount中。
        顯然,如果首先獲得利用QueryPerformanceFrequency函數(shù)獲得頻率記數(shù)器的震蕩頻率,然后在執(zhí)行某個(gè)程序段之前調(diào)用QueryPerformanceCounter函數(shù)獲得頻率記數(shù)器的震蕩次數(shù),在程序段結(jié)束再調(diào)用QueryPerformanceCounter函數(shù)獲得頻率記數(shù)器的震蕩次數(shù),將兩次獲得的震蕩次數(shù)相減后再除以震蕩頻率就獲得的了兩次間隔之間的時(shí)間(以秒為單位)。如果在程序中建立一個(gè)循環(huán),在循環(huán)中不停的調(diào)用QueryPerformanceCounter獲得頻率記數(shù)器的震蕩次數(shù)并同先前的頻率記數(shù)器的震蕩次數(shù)相減,將結(jié)果除以頻率記數(shù)器的震蕩頻率,如果達(dá)到一定的時(shí)間就執(zhí)行某個(gè)任務(wù),這樣就實(shí)現(xiàn)了一個(gè)比較精確的記時(shí)器的功能。

        另外的一種精確記時(shí)器的功能是利用多媒體記時(shí)器函數(shù)(這也是作者的定義,因?yàn)檫@個(gè)系列的函數(shù)是在Winmm.dll中定義并且是為媒體播放服務(wù)的)。
        實(shí)現(xiàn)多媒體記時(shí)器首先要定義timeSetEvent函數(shù),該函數(shù)的定義如下:

        Public Declare Function timeSetEvent Lib "winmm.dll" (ByVal uDelay As Long, ByVal _
                uResolution As Long, ByVal lpFunction As Long, ByVal dwUser As Long, _
                ByVal uFlags As Long) As Long

        函數(shù)定義中參數(shù)uDelay定義延遲時(shí)間,以毫秒為單位,該參數(shù)相當(dāng)于Timer控件的Interval屬性。參數(shù)uResolution定義記時(shí)精度,如果要求盡可能高的精度,要將該參數(shù)設(shè)置為0;參數(shù)lpFunction定義了timeSetEvent函數(shù)的回調(diào)函數(shù)的地址。參數(shù)dwUser定義用戶自定義的回調(diào)值,該值將傳遞給回調(diào)函數(shù)。參數(shù)uFlags定義定時(shí)類型,如果定義為Time_OneShot,則只會(huì)在當(dāng)達(dá)到uDelay定義的時(shí)間后調(diào)用回調(diào)函數(shù)一次,如果定義為TIME_PERIODIC,則在每次達(dá)到定時(shí)時(shí)間后調(diào)用回調(diào)函數(shù)。
        如果函數(shù)調(diào)用成功,在系統(tǒng)中建立了一個(gè)多媒體記時(shí)器對(duì)象,每當(dāng)經(jīng)過(guò)一個(gè)uDelay時(shí)間后lpFunction指定的函數(shù)都會(huì)被調(diào)用。同時(shí)函數(shù)返回一個(gè)對(duì)象標(biāo)識(shí),如果不再需要記時(shí)器則必須要使用timeKillEvent函數(shù)刪除記時(shí)器對(duì)象。
        由于Windows是一個(gè)多任務(wù)的操作系統(tǒng),因此基于API調(diào)用的記時(shí)器的精度都會(huì)受到其它很多因素的干擾。到底這兩中記時(shí)器的精度如何,我們來(lái)使用以下的程序進(jìn)行驗(yàn)證:
        設(shè)置三種記時(shí)器(Timer控件、高性能頻率記數(shù)、多媒體記時(shí)器)。將它們的定時(shí)間隔設(shè)置為10毫秒,讓它們不停工作直到達(dá)到一個(gè)比較長(zhǎng)的時(shí)間(比如60秒),這樣記時(shí)器的誤差會(huì)被累計(jì)下來(lái),然后同實(shí)際經(jīng)過(guò)的時(shí)間相比較,就可以得到它們的精度。
        下面是具體的檢測(cè)程序。
        首先建立一個(gè)工程文件,在Form1中加入一個(gè)Timer控件,兩個(gè)CommandButton控件和三個(gè)TextBox控件,然后在Form1的代碼窗口中加入以下代碼


        Option Explicit

        Private Sub Command1_Click()
            Dim lagTick1 As LARGE_INTEGER
            Dim lagTick2 As LARGE_INTEGER
            Dim lTen As Long
             
            Command2.Enabled = True
            Command1.Enabled = False
            iCountStart = 60
            lmmCount = 60
            TimerCount = 60
            actTime1 = GetTickCount
            lTimeID = timeSetEvent(10, 0, AddressOf TimeProc, 1, 1)
            Timer1.Enabled = True
             
            lTen = 10 * lMSFreq
            Call QueryPerformanceCounter(lagTick1)
            lagTick2 = lagTick1
            While iCountStart > 0
                Call QueryPerformanceCounter(lagTick2)
                '如果時(shí)鐘震動(dòng)次數(shù)超過(guò)10毫秒的次數(shù)則刷新Text1的顯示
                If lagTick2.lowpart - lagTick1.lowpart > lTen Then
                    lagTick1 = lagTick2
                    iCountStart = iCountStart - 0.01
                    Text1.Text = Format$(iCountStart, "00.00")
                End If
                DoEvents
            Wend
        End Sub

        Private Sub Command2_Click()
            EndCount
        End Sub

        Private Sub Form_Load()
            Dim lim As LARGE_INTEGER
             
            Text1.Text = "60.00"
            Text2.Text = "60.00"
            Text3.Text = "60.00"
            Command1.Caption = "開(kāi)始倒記時(shí)"
            Command2.Caption = "停止記時(shí)"
            Command2.Enabled = False
             
            '獲得系統(tǒng)板上時(shí)鐘頻率
            QueryPerformanceFrequency lim
             
            '將頻率除以1000就的出時(shí)鐘1毫秒震動(dòng)的次數(shù)
            lMSFreq = (lim.highpart * 2 ^ 16) \ 1000 + lim.lowpart \ 1000
            Timer1.Interval = 10
            Timer1.Enabled = False
        End Sub

        Private Sub Timer1_Timer()
            TimerCount = TimerCount - 0.01
            Text3.Text = Format$(TimerCount, "00.00")
            If TimerCount <= 0 Then
        Timer1.Enabled = False
        End If
        End Sub
        在Project中加入一個(gè)Module,然后在其中加入以下代碼:
        Option Explicit

        Type LARGE_INTEGER
        lowpart As Long
        highpart As Long
        End Type

        Public Declare Function QueryPerformanceCounter Lib "kernel32" _
        (lpPerformanceCount As LARGE_INTEGER) As Long
        Public Declare Function QueryPerformanceFrequency Lib "kernel32" _
        (lpFrequency As LARGE_INTEGER) As Long
        Public Declare Function timeSetEvent Lib "winmm.dll" (ByVal uDelay As Long, ByVal _
        uResolution As Long, ByVal lpFunction As Long, ByVal dwUser As Long, _
        ByVal uFlags As Long) As Long
        Public Declare Function timeKillEvent Lib "winmm.dll" (ByVal uID As Long) As Long
        Public Declare Function GetTickCount Lib "kernel32" () As Long

        Public lMSFreq As Long
        Public TimerCount As Single
        Public lmmCount As Single
        Public lTimeID As Long
        Public actTime1 As Long
        Public actTime2 As Long
        Public iCountStart As Single

        Dim iCount As Single

        'timeSetEvent的回調(diào)函數(shù)
        Sub TimeProc(ByVal uID As Long, ByVal uMsg As Long, ByVal dwUser As Long, _
        ByVal dw1 As Long, ByVal dw2 As Long)

        Form1.Text2.Text = Format$(lmmCount, "00.00")
        lmmCount = lmmCount - 0.01
        If lmmCount <= 0 Then
        iCountStart = 60
        lmmCount = 60
        TimerCount = 60
        EndCount
        End If
        End Sub
        Sub EndCount()
        iCount = iCountStart
        iCountStart = 0
        timeKillEvent lTimeID
        actTime2 = GetTickCount - actTime1
        With Form1
        .Command1.Enabled = True
        .Command2.Enabled = False
        .Timer1.Enabled = False

        .Text1 = "計(jì)數(shù)器記時(shí)" + Format$((60 - iCount), "00.00") + " " _
        + "實(shí)際經(jīng)過(guò)時(shí)間" + Format$((actTime2 / 1000), "00.00")
        .Text2 = "計(jì)數(shù)器記時(shí)" + Format$((60 - lmmCount), "00.00") + " " _
        + "實(shí)際經(jīng)過(guò)時(shí)間" + Format$((actTime2 / 1000), "00.00")
        .Text3 = "計(jì)數(shù)器記時(shí)" + Format$((60 - TimerCount), "00.00") + " " _
        + "實(shí)際經(jīng)過(guò)時(shí)間" + Format$((actTime2 / 1000), "00.00")
        End With
        End Sub


        運(yùn)行程序,點(diǎn)擊“開(kāi)始倒記時(shí)”按鈕開(kāi)始倒記時(shí),可以看到兩種API記時(shí)器工作基本正常,文本框中的倒記時(shí)顯示流暢,而Timer控件的時(shí)間顯示相比之下卻不堪重負(fù),十分緩慢。按“停止記時(shí)”按鈕就可以停止倒記時(shí),由圖1可以看到,兩種API記時(shí)器的累計(jì)誤差在2‰以下,考慮到系統(tǒng)原因和處理記時(shí)顯示的時(shí)間,這個(gè)誤差基本是可以接受的,而且經(jīng)過(guò)作者的多次檢測(cè),誤差都在3‰以下。而Timer控件的誤差簡(jiǎn)直是無(wú)法接受的。

        在運(yùn)行程序時(shí)作者還發(fā)現(xiàn)一個(gè)問(wèn)題,如果在倒記時(shí)時(shí)拖動(dòng)窗口,文本框中的顯示都會(huì)停止,而當(dāng)停止窗口拖放后,多媒體記時(shí)器顯示會(huì)跳過(guò)這段時(shí)間記時(shí),而其它兩種記時(shí)器顯示倒記時(shí)卻還是從原來(lái)的時(shí)間倒數(shù)。這說(shuō)明多媒體記時(shí)器是在獨(dú)立的線程中運(yùn)行的,不會(huì)受到程序的影響。

        綜合上面的介紹和范例,我們可以看到,如果要建立高精度的記時(shí)器,使用多媒體記時(shí)器是比較好的選擇。而高性能頻率記數(shù)法比較適合計(jì)算某個(gè)耗時(shí)十分短的過(guò)程所消耗的時(shí)間(例如分析程序中某個(gè)被多次調(diào)用的程序段執(zhí)行時(shí)間以優(yōu)化程序),因?yàn)楫吘垢咝阅茴l率記數(shù)的理論可以達(dá)到微秒級(jí)別。Timer控件雖然精度比上面兩者差很多,但是它使用方便,在要求不高的場(chǎng)合它還是最佳選擇。
        以上程序在Windows 98中文版,VB6下運(yùn)行通過(guò)。

        溫馨提示:喜歡本站的話,請(qǐng)收藏一下本站!

        本類教程下載

        系統(tǒng)下載排行

        主站蜘蛛池模板: 成年在线观看免费人视频草莓| 亚洲a一级免费视频| 日韩精品视频免费在线观看| 亚洲中字慕日产2020| 亚洲免费福利在线视频| 91亚洲自偷在线观看国产馆| 亚洲成人免费网站| 久久久婷婷五月亚洲97号色| 国产成人精品久久免费动漫 | 最近2019年免费中文字幕高清| 亚洲AV成人一区二区三区AV| 久久99热精品免费观看牛牛| 精品亚洲国产成AV人片传媒| 18禁止看的免费污网站| 国产成人精品亚洲2020| 免费高清小黄站在线观看| 免费看黄网站在线看| 亚洲精品高清国产一线久久| 久久不见久久见免费视频7 | 日韩精品免费电影| 特级aa**毛片免费观看| 亚洲日产无码中文字幕| 99国产精品免费视频观看| 久久精品国产99国产精品亚洲| 免费无码黄动漫在线观看| 人人爽人人爽人人片av免费| 国产亚洲婷婷香蕉久久精品| 免费在线观看h片| 美美女高清毛片视频黄的一免费| 国产精品V亚洲精品V日韩精品| 91免费福利精品国产| 亚洲风情亚Aⅴ在线发布| 亚洲精品无码成人片久久| 久久久久免费看黄A片APP| 九九全国免费视频| 亚洲视频一区二区在线观看| 免费人成网站在线高清| 99re在线免费视频| 鲁啊鲁在线视频免费播放| 亚洲福利在线视频| 可以免费观看一级毛片黄a |