基于Windows的精確定時技術_第1頁
基于Windows的精確定時技術_第2頁
基于Windows的精確定時技術_第3頁
基于Windows的精確定時技術_第4頁
基于Windows的精確定時技術_第5頁
已閱讀5頁,還剩5頁未讀, 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、基于Windows的精確定時技術(長沙交通學院計算機工程系 李湘江) 在工業生產控制系統中,有許多需要定時完成的操作,如:定時顯示當前時間,定時刷新屏幕上的進度條,上位機定時向下位機發送命令和傳送數據等。特別是在對控制性能要求較高的控制系統和數據采集系統中,就更需要精確定時操作。眾所周知,Windows是基于消息機制的系統,任何事件的執行都是通過發送和接收消息來完成的。這樣就帶來了一些問題,如一旦計算機的CPU被某個進程占用,或系統資源緊張時,發送到消息隊列中的消息就暫時被掛起,得不到實時處理。因此,不能簡單地通過Windows消息引發一個對定時要求嚴格的事件。另外,由于在Windows中已經

2、封裝了計算機底層硬件的訪問,所以,要想通過直接利用訪問硬件來完成精確定時,也比較困難。所以在實際應用時,應針對具體定時精度的要求,采取相適應的定時方法。 VC的時間操作函數 VC 中提供了很多關于時間操作的函數,利用它們控制程序能夠精確地完成定時和計時操作。VC中的WM_TIMER消息映射能進行簡單的時間控制。首先調用函數SetTimer()設置定時間隔,如SetTimer(0,200,NULL)即為設置200ms的時間間隔。然后在應用程序中增加定時響應函數OnTimer(),并在該函數中添加響應的處理語句,用來完成到達定時時間的操作。這種定時方法非常簡單,但其定時功能如同Sleep()函數的

3、延時功能一樣,精度非常低,只可以用來實現諸如位圖的動態顯示等對定時精度要求不高的情況。 在精度要求較高的情況下,如要求誤差不大于1ms時,可以利用GetTickCount()函數。該函數的返回值是DWORD型,表示以ms為單位的計算機啟動后經歷的時間間隔。下列的代碼可以實現50ms的精確定時,其誤差小于1ms。 / 起始值和中止值DWORD dwStart, dwStop ;dwStop = GetTickCount(); while(TRUE) / 上一次的中止值變成新的起始值 dwStart = dwStop ; / 此處添加相應控制語句do dwStop = GetTickCount()

4、 ; while(dwStop 50 dwStart) ; 對于精確度要求更高的定時操作,則應該使用QueryPerformanceFrequency()和QueryPerformanceCounter()函數。這兩個函數是VC提供的僅供Windows 95及其后續版本使用的精確時間函數,并要求計算機從硬件上支持精確定時器。QueryPerformanceFrequency()函數和QueryPerformanceCounter()函數的原型如下: BOOL QueryPerformanceFrequency(LARGE_INTEGER lpFrequency); BOOL QueryPerf

5、ormanceCounter(LARGE_INTEGER lpCount); 數據類型LARGE_INTEGER既可以是一個8字節長的整型數,也可以是兩個4字節長的整型數的聯合結構,其具體用法根據編譯器是否支持64位而定。該類型的定義如下: typedef union _LARGE_INTEGER struct / 4字節整型數 DWORD LowPart ; / 4字節整型數 LONGHighPart ; ; / 8字節整型數 LONGLONG QuadPart ; LARGE_INTEGER ; 在進行定時之前,先調用QueryPerformanceFrequency()函數獲得機器內部定

6、時器的時鐘頻率,然后在需要嚴格定時的事件發生之前和發生之后分別調用QueryPerformanceCounter()函數,利用兩次獲得的計數之差及時鐘頻率,計算出事件經歷的精確時間。下面的程序用來測試函數Sleep(100)的精確持續時間: LARGE_INTEGER litmp; LONGLONG QPart1,QPart2; double dfMinus, dfFreq, dfTim; QueryPerformanceFrequency(litmp); / 獲得計數器的時鐘頻率 dfFreq = (double)litmp.QuadPart; QueryPerformanceCounter

7、(litmp); / 獲得初始值 QPart1 = litmp.QuadPart; Sleep(100); QueryPerformanceCounter(litmp); / 獲得中止值 QPart2 = litmp.QuadPart; dfMinus = (double)(QPart2 QPart1); / 獲得對應的時間值 dfTim = dfMinus / dfFreq; 由于Sleep()函數自身的誤差,上述程序每次執行的結果都會有微小誤差。 使用多媒體定時器 微軟公司在其多媒體Windows中提供了精確定時器的底層API支持。利用多媒體定時器可以很精確地讀出系統的當前時間,并且能在非

8、常精確的時間間隔內完成一個事件、函數或過程的調用。利用多媒體定時器的基本功能,可以通過兩種方法實現精確定時。 1.使用timeGetTime()函數 該函數定時精度為ms級,返回從Windows啟動開始所經過的時間。由于使用該函數是通過查詢的方式進行定時控制的,所以,應該建立定時循環來進行定時事件的控制。 2. 使用timeSetEvent()函數 利用該函數可以實現周期性的函數調用。函數的參數說明如下: uDelay:延遲時間; uResolution:時間精度,在Windows中缺省值為1ms; lpFunction:回調函數,為用戶自定義函數,定時調用; dwUser:用戶參數; uFl

9、ags:標志參數; TIME_ONESHOT:執行一次; TIME_PERIODIC:周期性執行。 具體應用時,可以通過調用timeSetEvent()函數,將需要周期性執行的任務定義在lpFunction回調函數中(如:定時采樣、控制等),從而完成所需處理的事件。需要注意的是:任務處理的時間不能大于周期間隔時間。另外,在定時器使用完畢后,應及時調用timeKillEvent()將之釋放。 下面這段代碼的主要功能是設置兩個時鐘定時器,一個間隔是1ms,一個間隔是2s。每執行一次,把當前系統時鐘值輸入文件“cure.out”中,以比較該定時器的精確度。 /定義1ms和2s時鐘間隔,以ms為單位

10、define ONE_MILLI_SECOND 1 define TWO_SECOND 2000 /定義時鐘分辨率,以ms為單位 define TIMER_ACCURACY 1 /定義時間間隔 UINT wTimerRes_1ms,wTimerRes_2s; /定義分辨率 UINT wAccuracy; /定義定時器句柄 UINT TimerID_1ms,TimerID_2s; /打開輸出文件“cure.out” CCureApp:CCureApp():fout(“cure.out”, ios:out) / 給時間間隔變量賦值 wTimerRes_1ms = ONE_MILLI_SECOND;

11、 wTimerRes_2s = TWO_SECOND; TIMECAPS tc; /利用函數timeGetDevCaps取出系統分辨率的取值范圍,如果無錯則繼續 if(timeGetDevCaps(tc,sizeof(TIMECAPS)=TIMERR_NOERROR) /分辨率的值不能超出系統的取值范圍 wAccuracy=min(max(tc.wPeriodMin, TIMER_ACCURACY),tc.wPeriodMax); /調用timeBeginPeriod函數設置定時器的分辨率 timeBeginPeriod(wAccuracy); /設置定時器 InitializeTimer()

12、; CCureApp: CCureApp() /結束時鐘 fout “結束時鐘”foutms“:1ms:” osBinaryTimeendl; / 加裝1ms定時器 void CCureApp:StartOneMilliSecondTimer() if(TimerID_1ms = timeSetEvent(wTimerRes_1ms, wAccuracy, / 回調函數 (LPTIMECALBACK) OneMil liSecondProc, / 用戶傳送到回調函數的數據 (DWORD)this, / 周期調用,只使用一次,用TIME_ONESHOT/ TIME_PERIODIC) = 0)

13、AfxMessageBox(“不能進行定時!”, MB_OK | MB_ICONASTERISK); else /不等于0表明加裝成功,返回此定時器的句柄 fout “16ms 計 時:” endl; 利用系統定時中斷 在PC機中采用了可編程定時/計數芯片8253,計數器0工作在方式3,用OUT0產生時鐘信號。OUT0作為中斷請求信號接可編程中斷控制器8259A的IR0(系統中IRQ0)。由于fCLK1.19MHz,TCLK840ns,因此8253初值為65536時,大約每840ns6553655ms中斷一次。可以讀取計數器的當前計數值,計數器值每減一,代表時間840ns,另加上計數器是否計滿

14、的判斷,則可計算出時間的精確值。 8253的6種工作方式的設置是在初始化時用輸出指令寫控制字來實現的,其中,方式0為在結束計數時中斷。 調用VC運行庫函數clock(),可以獲得本次程序運行由處理器用去的ms時間,由此可判斷出計數器是否計滿。具體程序代碼如下: / 延時函數 void Ddelay(unsigned long n) unsigned long Told; unsigned long nn,old_Clock, new_Clock, low, high, v_8253; unsigned long old_8253, new_8253, int_Time; / nn單位: 840

15、ns nn =(unsigned long)(float)n1000/840); / 鎖定8253計數值 _outp(0x43,0x00); / 讀取8253計數值 low = _inp(0x40); high = _inp(0x40); v_8253 = low 256 high; old_8253 = v_8253; old_Clock=clock(); Told=old_Clock; int_Time=0; while(int_Time nn) _outp(0x43,0x00); low = _inp(0x40); high = _inp(0x40); v_8253 = low 256

16、high; new_8253 = v_8253; new_Clock=clock(); if(old_8253 new_8253 new_ClockTold 55) int_Time=(old_8253new_8253) (new_Clockold_Clock)/551)65536lu; else int_Time=(old_8253new_8253) (new_Clockold_Clock)/55) 65536lu; Told=new_Clock; Windows98下精度為微秒級的定時 南京航空航天大學 劉學軍- 目前程序員所能看到的一些計時程序精度為ms級,在精度要求較高的場合不適用。現

17、介紹一種方法可以得到精度為大約840ns的定時程序。 - 在PC機中采用了一片可編程定時/計數芯片8253,計數器0工作在方式3,用OUT0產生時鐘信號。OUT0作為中斷請求信號接可編程中斷控制器8259A的IR0(系統中IRQ0)。由于fCLK1.19MHZ,TCLK840ns,因此8253初值為65536時,此定時時間大約每840ns6553655ms中斷一次。可以讀取計數器的當前計數值,計數器值每減一,代表時間840ns,另加上計數器是否計滿的判斷,則可計算出時間的精確值。 - 調用VC+運行庫函數clock(),可以獲得本次程序運行由處理器用去的時間(單位是ms),由此可判斷出計數器是

18、否計滿。 - 根據上述方法編寫的延時程序在實際應用上具有重要意義,現舉二例說明。 - 步進電機是工業過程控制及儀表中的主要控制之一。用PC機控制步進電機原理系統圖如下: - 步進電機控制軟件中必須解決的一個重要問題,就是產生一個如下圖的周期性脈沖序列: - 實現脈沖波的方法可以先輸出低電平,然后利用本文所述定時方法延時一段時間,而后輸出高電平,再延時。這樣可以控制較高工作頻率的步進電機工作。具體程序代碼如下: void Ddelay(unsigned long n) / 延時函數,n單位:usunsigned long Told;unsigned long nn,old_Clock, new_

19、Clock, low, high, v_8253;unsigned long old_8253, new_8253, int_Time; nn =(unsigned long)(float)n*1000/840); / nn單位: 840ns */_outp(0x43,0x00); / 鎖定8253計數值low = _inp(0x40); / 讀取8253計數值high = _inp(0x40);v_8253 = low + 256 * high;old_8253 = v_8253;old_Clock=clock();Told=old_Clock;int_Time=0;while(int_Ti

20、me nn)_outp(0x43,0x00);low = _inp(0x40);high = _inp(0x40);v_8253 = low + 256 * high;new_8253 = v_8253;new_Clock=clock();if(old_8253 new_8253 & new_Clock-Told 55) int_Time=(old_8253-new_8253)+(new_Clock-old_Clock)/55+1)*65536lu; else int_Time=(old_8253-new_8253)+ (new_Clock-old_Clock)/55) * 65536lu;

21、Told=new_Clock;若步進電機工作頻率為400HZ,則發送num個脈沖的程序段如下:send_pio=0x00; / 初始化待發送的數據_outp(0x360,0x8a); / 初始化8255for(i=0;i num;i+) send_pio & = 0xfd; /d0位為脈沖輸出位 _outp(0x366,send_pio); / 輸出低電平 Ddelay(1250); / 延時半個周期 send_pio | = 0x01; _outp(0x366,send_pio); / 輸出高電平 Ddelay(1250); / 延時半個周期另利用該方法可以求出某段程序代碼精確的執行時間。程

22、序段如下:unsigned t1,t2,t3,T1,T2,T;_outp(0x43,0x00); / 鎖定8253計數值t1=_inp(0x40)+256*_inp(0x40); / 讀取8253計數值T1=clock(); / 待計時的程序段_outp(0x43,0x00);t2=_inp(0x40)+256*_inp(0x40);T2=clock();if(t155) t3=t1-t2+(T2-T1+1)*65536; else t3=t1-t2+(T2-T1)*65536; T=840*t3; / T即為程序的執行時間基于Windows95的高速數據采集摘要:Windows95的出現給軟

23、件業帶來了革命性的變化,也對工控軟件的設計提出了挑戰。Windows95的新特性使其實時性大大降低,WIN95環境下的數據采集速度難以提高。本文提出了一種利用雙緩沖和多線程提高采集速度的方法,并在對MTS材料疲勞實驗系統的改造中加以運用,取得了非常好的效果。關鍵詞:雙緩沖,多線程,中斷,實時數據采集High Speed Data Acquisition Under Windows95Abstract:A method to realize high speed data acquisition under Windows95 is introduced.Double buffer and mu

24、ltithread are used to increase acquisition speed.An application using this method is given.Key words:double buffer,multithread,interrupt,real-time data acquisition在工業控制領域,實時數據采集是一個最基本且最重要的環節。如何提高采集速度一直是工控技術人員所關心的問題。作為一個實時操作系統,MS-DOS曾給工控軟件提供了一個非常好的平臺。在DOS環境下,利用Turbo C或其他語言,可以很方便地開發出具有極高速度的實時數據采集軟件。然而

25、,要在DOS下設計出一個圖文并茂、操作方便的用戶界面,卻是一件費時費力的工作。Windows95的出現,給計算機用戶展現了一個煥然一新的畫面。多窗口,多任務,以鼠標為主的操作方式,這在原先的DOS環境下是無法想象的。同時,也涌現出大量Windows95環境下的軟件開發工具,如:Visual C+,Visual Basic,Borland C+,Borland Delphi等。利用這些新的開發工具,可以很方便地設計出符合Windows95標準的用戶界面。Turbo C已不再能滿足人們的需要。然而,作為代價,WIN95的實時性卻大大下降。WIN95的多任務機制使得一個程序不能獨占全部的資源,也使得

26、實時數據采集難以實現。因此,許多工控技術人員至今仍在DOS環境下編寫數據采集軟件。然而,習慣了Windows界面后,很少有用戶愿意回到DOS下去面對那枯燥無味的屏幕,許多工控軟件用戶在協議中直接提出了要在WIN95下運行的要求。因此如何在WIN95下設計出高速數據采集程序已成為工控技術人員關心的焦點。1定時中斷存在的問題一個基本的數據采集系統通常包括A/D和D/A兩個部分。在許多場合下,A/D和D/A操作都要精確定時。通常的辦法是利用計時器中斷,先設定定時間隔,然后對計時器中斷進行掛鉤,在中斷程序中進行所需的操作。在數據量較大時,發送和采集的數據都只能以文件的格式存儲在硬盤上。中斷程序的任務是

27、: 從文件中取出數據;必要時對數據進行轉換;通過D/A卡發送數據;從A/D卡讀取數據;必要的數據轉換;將數據存入文件;其他的數據處理工作。在DOS下設計程序時,我們就是這樣做的。在Windows環境下,通過編寫設備驅動程序(.VXD),仍然可以實現對定時中斷的掛鉤。然而,如果將同樣的代碼放在中斷程序中,就會出現問題。中斷程序過長,當定時間隔很小,即采樣頻率較高時,會造成死機。由于Windows95的多任務機制,在中斷程序中進行文件處理,會造成系統的崩潰。在DOS下之所以這樣設計程序,就是因為DOS是單任務操作系統。而Windows95是一個多任務操作系統,當同時有多個任務存在時,在中斷程序中對

28、文件進行操作可能會造成系統函數的重入,導致系統的崩潰。實驗證明,這種崩潰是必然的,而且是致命的,只有通過Reset鍵才能恢復。那么,如何解決這些問題呢?2解決的辦法Windows為我們提供了解決的辦法:采用Windows提供的定時器代替硬件定時中斷。使用這種方法非常安全和簡單,可以在定時函數內進行任何操作,決不會造成死機現象。然而,Windows定時器的實時性非常差,既不能保證定時精度,也不能保證中斷次數,而且,定時間隔也不能太短(55 ms)。顯然,即使對于精度要求很低的數據采集系統,利用Windows定時器作為解決辦法也不能令人滿意。利用Windows提供的多媒體定時器。顧名思義,這種定時

29、器原本是為多媒體服務而設計的,例如MIDI,然而,也可以將其另作它用。因為多媒體定時器的精度非常高,與硬件中斷相當,而且也比較安全,不容易造成死機現象。唯一的缺點是中斷頻率太低,最高只能達到1 kHz,即每毫秒中斷一次。因此無法用于有較高速度要求的系統,當然,對于較低速度的數據采集系統。多媒體定時器仍是一種極好的選擇。 利用Windows95 的多線程,并與硬件中斷相結合,實現高速數據采集。這正是下面要介紹的方法,利用這種方法,可以實現Windows95下的高速數據采集,并從容地對數據進行處理和保存。3多線程和雙緩沖為了保證數據采集的精度和速度,仍然采用了硬件中斷的辦法,利用硬件定時器(如AD

30、卡上的定時器)產生中斷,并編寫VXD為其設置相應的中斷處理程序。為了提高中斷速度以及避免函數重入,去掉了中斷過程中一切與系統調用有關的部分,將中斷程序縮至最短。這樣,中斷程序所做的就是讀取AD卡上的數據,將其送到一個公用的緩沖區,并維護一個緩沖區指針,而把數據處理和文件存盤的工作留給處理線程去完成。公用緩沖區由兩個大小相同、且連續的子緩沖區組成,稱為雙緩沖,用于暫存AD轉換的數據。每次定時中斷到達時,中斷程序從AD卡上讀一個數據放入緩沖區,并將緩沖區指針加1,當兩個子緩沖區全部填滿后,將緩沖區指針歸0,后讀入的數據沖掉原來的數據。開始中斷采集的同時,由主程序啟動一個線程,稱為處理線程。處理線程

31、在后臺與主程序并行工作,用它監視雙緩沖指針。當發現雙緩沖指針從子緩沖區1進入子緩沖區2時,說明中斷程序已將子緩沖區1填滿,這時,處理線程對子緩沖區1中的數據進行處理并存盤。同理,當發現雙緩沖指針從子緩沖區2回到子緩沖區1時,對子緩沖區2中的數據進行處理和存盤。只要緩沖區足夠大,即使在采集頻率非常高的情況下,中斷程序填滿一個子緩沖區的時間也會比較長,而處理線程進行一次處理和存盤的時間相對比較短。因此,中斷程序和處理線程可以并行地訪問緩沖區而不會發生交疊,即中斷程序訪問的子緩沖區與處理線程訪問的子緩沖區總是不同的。這樣,就可以在不丟失任何一個數據的情況下實現長時間連續高速采集。該方法實現的框圖如圖1。圖1利用雙緩沖和多線程提高數據采集速度這實際相當于在PC機的內存中開辟了一片FIFO隊列。與硬件FIFO相比,這種方法大大降低了成本,而且,由于將其放在內存中,可以輕易地得到非常大的FIFO隊列,

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論