天天看點

VC中基于 Windows 的精确定時

在工業生産控制系統中,有許多需要定時完成的操作,如定時顯示目前時間,定時重新整理螢幕上的進度條,上位 機定時向下位機發送指令和傳送資料等。特别是在對控制性能要求較高的實時控制系統和資料采集系統中,就更需要精确定時操作。

  衆所周知,windows 是基于消息機制的系統,任何事件的執行都是通過發送和接收消息來完成的。 這樣就帶來了一些問題,如一旦計算機的cpu被某個程序占用,或系統資源緊張時,發送到消息隊列 中的消息就暫時被挂起,得不到實時處理。是以,不能簡單地通過windows消息引發一個對定時要求 嚴格的事件。另外,由于在windows中已經封裝了計算機底層硬體的通路,是以,要想通過直接利用 通路硬體來完成精确定時,也比較困難。是以在實際應用時,應針對具體定時精度的要求,采取相适

應的定時方法。

  vc中提供了很多關于時間操作的函數,利用它們控制程式能夠精确地完成定時和計時操作。本文詳細介紹了 vc中基于windows的精确定時的七種方式,如下圖所示:

圖一 圖像描述

  方式一:vc中的wm_timer消息映射能進行簡單的時間控制。首先調用函數settimer()設定定時 間隔,如settimer(0,200,null)即為設定200ms的時間間隔。然後在應用程式中增加定時響應函數 ontimer(),并在該函數中添加響應的處理語句,用來完成到達定時時間的操作。這種定時方法非常 簡單,可以實作一定的定時功能,但其定時功能如同sleep()函數的延時功能一樣,精度非常低,最小 計時精度僅為30ms,cpu占用低,且定時器消息在多任務作業系統中的優先級很低,不能得到及時響

應,往往不能滿足實時控制環境下的應用。隻可以用來實作諸如位圖的動态顯示等對定時精度要求不高的情況。如示例工程中的timer1。

  方式二:vc中使用sleep()函數實作延時,它的機關是ms,如延時2秒,用sleep(2000)。精度非常 低,最小計時精度僅為30ms,用sleep函數的不利處在于延時期間不能處理其他的消息,如果時間太 長,就好象當機一樣,cpu占用率非常高,隻能用于要求不高的延時程式中。如示例工程中的timer2。

  方式三:利用coledatetime類和coledatetimespan類結合windows的消息處理過程來實作秒級延時。如示例工程中的timer3和timer3_1。以下是實作2秒的延時代碼:

  方式四:在精度要求較高的情況下,vc中可以利用gettickcount()函數,該函數的傳回值是  dword型,表示以ms為機關的計算機啟動後經曆的時間間隔。精度比wm_timer消息映射高,在較 短的定時中其計時誤差為15ms,在較長的定時中其計時誤差較低,如果定時時間太長,就好象當機一樣,cpu占用率非常高,隻能用于要求不高的延時程式中。如示例工程中的timer4和timer4_1。下列代碼可以實作50ms的精确定時:

為使gettickcount()函數在延時或定時期間能處理其他的消息,可以把代碼改為:

雖然這樣可以降低cpu的占有率,并在延時或定時期間也能處理其他的消息,但降低了延時或定時精度。

  方式五:與gettickcount()函數類似的多媒體定時器函數dword timegettime(void),該函數定時精 度為ms級,傳回從windows啟動開始經過的毫秒數。微軟公司在其多媒體windows中提供了精确定時器的底 層api持,利用多媒體定時器可以很精确地讀出系統的目前時間,并且能在非常精确的時間間隔内完成一 個事件、函數或過程的調用。不同之處在于調用dword timegettime(void) 函數之前必須将 winmm.lib  和 mmsystem.h

添加到工程中,否則在編譯時提示dword timegettime(void)函數未定義。由于使用該 函數是通過查詢的方式進行定時控制的,是以,應該建立定時循環來進行定時事件的控制。如示例工程中的timer5和timer5_1。

  方式六:使用多媒體定時器timesetevent()函數,該函數定時精度為ms級。利用該函數可以實作周期性的函數調用。如示例工程中的timer6和timer6_1。函數的原型如下:

  該函數設定一個定時回調事件,此事件可以是一個一次性事件或周期性事件。事件一旦被激活,便調用指定的回調函數, 成功後傳回事件的辨別符代碼,否則傳回null。函數的參數說明如下:

  具體應用時,可以通過調用timesetevent()函數,将需要周期性執行的任務定義在lptimeproc回調函數 中(如:定時采樣、控制等),進而完成所需處理的事件。需要注意的是,任務處理的時間不能大于周期間隔時間。另外,在定時器使用完畢後, 應及時調用timekillevent()将之釋放。

  方式七:對于精确度要求更高的定時操作,則應該使用queryperformancefrequency()和 queryperformancecounter()函數。這兩個函數是vc提供的僅供windows 95及其後續版本使用的精确時間函數,并要求計算機從硬體上支援精确定時器。如示例工程中的timer7、timer7_1、timer7_2、timer7_3。

queryperformancefrequency()函數和queryperformancecounter()函數的原型如下:

  資料類型arge_integer既可以是一個8位元組長的整型數,也可以是兩個4位元組長的整型數的聯合結構, 其具體用法根據編譯器是否支援64位而定。該類型的定義如下:

  在進行定時之前,先調用queryperformancefrequency()函數獲得機器内部定時器的時鐘頻率, 然後在需要嚴格定時的事件發生之前和發生之後分别調用queryperformancecounter()函數,利用兩次獲得的計數之差及時鐘頻率,計算出事件經 曆的精确時間。下列代碼實作1ms的精确定時:

  其定時誤差不超過1微秒,精度與cpu等機器配置有關。 下面的程式用來測試函數sleep(100)的精确持續時間:

  由于sleep()函數自身的誤差,上述程式每次執行的結果都會有微小誤差。下列代碼實作1微秒的精确定時:

其定時誤差一般不超過0.5微秒,精度與cpu等機器配置有關

繼續閱讀