史禮婷,張 騫,皮本杰,高佳雋,李春權(quán)
(1.航天行云科技有限公司,武漢 430040;2.湖北航天科工集團總體設(shè)計所,武漢 430040)
具有自動、章動、進動的三自由度轉(zhuǎn)臺,是飛行器進行動態(tài)性能測試的關(guān)鍵設(shè)備,廣泛應(yīng)用于各類飛行器模擬試驗,特別是研究彈丸或引信在空中的飛行試驗,經(jīng)常需要利用轉(zhuǎn)臺進行地面飛行狀況的模擬。
在轉(zhuǎn)臺的模擬試驗中,需要通過計算機良好的人機界面和強大的數(shù)據(jù)處理功能,對其進行控制。而其他設(shè)備與計算機進行數(shù)據(jù)通信的方法中,串口通信是經(jīng)常使用的方法之一,它具有實現(xiàn)簡單、使用靈活、數(shù)據(jù)傳輸可靠等有點,因而應(yīng)用廣泛[1]。
在具體工程實踐中,遇到兩個較大問題:一是三自由度轉(zhuǎn)臺既要實現(xiàn)實時控制,又要周期返回大量狀態(tài)信息,I/O數(shù)據(jù)量較大,導(dǎo)致程序處理速度降低。二是由于工程設(shè)計需要,轉(zhuǎn)臺程序需要在多個系統(tǒng)中復(fù)用。
為解決上述問題,本文設(shè)計了多線程的處理程序,并將串口和轉(zhuǎn)臺之間的通信協(xié)議進行了DLL封裝,具有以下優(yōu)點:一是提高內(nèi)存利用率。采用多線程技術(shù),大大提高程序I/O處理能力,提高工作效率。二是簡化主程序開發(fā)。將協(xié)議解析和使用分開,簡化主控制程序的開發(fā)工作量。將串口訪問、協(xié)議解析、組幀等進行封裝,主控制程序的調(diào)用相對簡單,不必理解協(xié)議具體內(nèi)容,簡化了主程序的開發(fā)。三是采用模塊化開發(fā)設(shè)計,便于升級和維護。將通信協(xié)議封裝在DLL里,協(xié)議有修改時,動態(tài)鏈接庫可獨立升級調(diào)試,不影響主控制軟件,便于維護。四是提高系統(tǒng)的適應(yīng)性和安全性。DLL可以用不同的編程語言進行開發(fā)和調(diào)用,只要接口確定,內(nèi)部可以獨立設(shè)計,相對安全、適應(yīng)性高。
串口通信的實現(xiàn)通常有三個辦法:一是利用mscomm通信控件;二是采用微軟提供的內(nèi)置的串口操作類System.IO.SerialPort;三是通過API函數(shù)。前兩種方法編程實現(xiàn)起來簡單,但是靈活性有所欠缺;第三種方法雖然編程難度較大,但是高效、自由、靈活,且能避免高速緩存中緩存溢出的缺點,因此,本文采用第三種方法。
圖1 串口通信操作步驟
如圖1所示,本文對串口使用采用以下幾個步驟:
(1)打開轉(zhuǎn)臺串口。由于串口是獨占性資源,因此,在應(yīng)用程序設(shè)計中,需要避免因打開已占用的串口引發(fā)的錯誤。
(2)設(shè)置波特率等串口通信參數(shù)。利用GetCommState函數(shù)獲取串口當(dāng)前配置,根據(jù)需要更改BuildCommDCB結(jié)構(gòu)中的參數(shù),利用SetCommState函數(shù)設(shè)置串口通信參數(shù)。
(3)啟動串口監(jiān)控,即啟動串口相關(guān)線程(具體見2.2節(jié))。
(4)數(shù)據(jù)收發(fā)。向轉(zhuǎn)臺發(fā)送指令進行控制;對串口數(shù)據(jù)接收,將接收到轉(zhuǎn)臺的數(shù)據(jù)解析
(5)關(guān)閉串口。在不需要使用此串口時,需關(guān)閉串口,釋放資源。
現(xiàn)今主流操作系統(tǒng)大多是多進程系統(tǒng),即系統(tǒng)內(nèi)可同時運行多個進程,而每個進程也可以同時執(zhí)行多個線程。每個進程都有一個主線程,同時,可以建立另外的多個線程,進程中的各個線程都是并行執(zhí)行的[1]。對于本系統(tǒng),有大量的I/O測試數(shù)據(jù),要想獲得較高的用戶體驗,創(chuàng)建多線程是最好的選擇。
在轉(zhuǎn)臺模擬試驗中,數(shù)據(jù)接收和發(fā)送是兩個相對獨立的過程,其中接收的部分?jǐn)?shù)據(jù)是按設(shè)置的時間周期定時返回,接收頻率有可能會比較高,發(fā)送控制指令相對來說比較隨機,需要根據(jù)試驗設(shè)計的操作流程來確定。根據(jù)這些特點,可以在程序中將讀線程和寫線程分開,創(chuàng)建兩個專門的線程來分別讀取和發(fā)送串口的數(shù)據(jù),如圖2所示,線程設(shè)計解釋如下:
圖2 通信線程設(shè)計
(1)主線程:用來響應(yīng)用戶的各種操作,處理其他線程的各種響應(yīng)。
(2)讀線程:監(jiān)聽串口,響應(yīng)各種串口消息事件,如標(biāo)準(zhǔn)事件EX_RXCHAR,響應(yīng)接收到字符事件;事件EX_RXFLAG,響應(yīng)接收到事件字符、置入輸入緩存區(qū)事件;事件EV_CTS,響應(yīng)準(zhǔn)許發(fā)送數(shù)據(jù)事件等。
(3)寫線程:向串口寫數(shù)據(jù),采用API函數(shù)WriteFile實現(xiàn),當(dāng)有寫入錯誤需要返回錯誤代碼。
(4)中斷線程:中斷線程的優(yōu)先級最高,用戶或轉(zhuǎn)臺隨時可以中斷讀和寫操作信號,提高程序的安全性和健壯性。
由于同一個進程中的所有的線程共享同一虛擬地址空間,且線程的中斷是匯編語言級的,所以有可能會出現(xiàn)線程沖突、阻塞或錯誤,因此需要采取線程同步措施來避免這些問題[1]。
(1)重疊I/O方式。線程的執(zhí)行采用重疊I/O方式,避免了程序因等待函數(shù)返回而阻塞線程的問題,本文在CreateFile時傳遞OVERLAPPED結(jié)構(gòu)參數(shù),如果進行I/O操作的API函數(shù)返回后并沒有完成需要的操作,則調(diào)用GetOverLappedResult函數(shù),來等待知道I/O操作完成后返回。
(2)臨界區(qū)對象。臨界區(qū)是一段代碼,在任意給定的時刻只能被一個線程使用,如果有兩個以上的線程同時訪問臨界區(qū),只允許一個線程使用,其他線程保持等待或被阻塞。在初始化串口、讀串口、寫串口這些重要操作時,可以利用臨界區(qū),避免重要操作沖突或阻塞。
在實現(xiàn)時利用全局變量來統(tǒng)一控制臨界區(qū)的使用,本文定義了全局變量CRITICAL_SECTION m_csComnuSync,用Enter-CriticalSection函數(shù)進入臨界區(qū),LeaveCriticalSection釋放對臨界區(qū)的使用權(quán)。
(3)事件對象。事件對象時指用戶在程序中使用內(nèi)核對象的有無信號狀態(tài)實現(xiàn)線程間的同步。通過API函數(shù)CreateEvent用于創(chuàng)建事件對象;SetEvent設(shè)置其為有信號狀態(tài);ResetEvent設(shè)置無信號狀態(tài)。
(4)等待函數(shù)。等待函數(shù)是用來暫時掛起線程,待到監(jiān)控對象產(chǎn)生一定信號則繼續(xù)執(zhí)行該線程,避免對CPU的過多占用,提高程序的執(zhí)行效率。利用WaitforSingleObject監(jiān)控單個同步對象,用WaitForMultipleObject同時監(jiān)控多個同步對象。
本文將采用動態(tài)鏈接庫(DLL)對通信協(xié)議進行封裝,主測試程序負責(zé)提供給測試人員操作界面相關(guān)功能,如串口打開、指令發(fā)送、指令解析、日志記錄等操作;DLL內(nèi)實現(xiàn)具體的協(xié)議組幀、協(xié)議解析、串口初始化、線程啟動、串口讀、串口寫、關(guān)閉串口等功能,程序流程設(shè)計如圖3所示。
圖3 程序設(shè)計流程圖
具體設(shè)計如下:
(1)對于協(xié)議的實現(xiàn),本文從協(xié)議發(fā)送和接收兩個方面出發(fā)進行設(shè)計。
(2)設(shè)計了協(xié)議處理類CFrameData和指令參數(shù)結(jié)構(gòu)體strOrderParam,strOrderParam定義如下:
(3)在主程序?qū)χ噶钸M行發(fā)送時,只需設(shè)置外環(huán)、中環(huán)、內(nèi)環(huán)的指令參數(shù),統(tǒng)一調(diào)用協(xié)議處理類里面的SetOrder函數(shù)即可。
(4)協(xié)議的解析,采用解析函數(shù)MatchAnswerString來處理,如果協(xié)議解析成功,函數(shù)將返回CFrameData對象指針。
(5)CFrameData類定義了一系列協(xié)議解析的返回的參數(shù),如利用GetMsg來返回幀解析字符串,GetAngel來獲取外環(huán)、中環(huán)、內(nèi)環(huán)的具體數(shù)值等。
本文的DLL采用MFC規(guī)則的動態(tài)鏈接庫,在DLL中有一些必須導(dǎo)出的函數(shù),可以采用以下關(guān)鍵字將函數(shù)或類進行導(dǎo)出:可以使用導(dǎo)出關(guān)鍵字__declspec(dllexport)來聲明導(dǎo)出;關(guān)鍵字AFX_EXT_CLASS來聲明導(dǎo)出類;關(guān)鍵字extern “C”可以使編寫的函數(shù)供其他編程語言使用。
由程序設(shè)計分析得出,需要導(dǎo)出的接口如下:
(1)串口控制類。包含串口控制對象,以及串口打開、配置串口、數(shù)據(jù)發(fā)送和接收、關(guān)閉串口等串口控制函數(shù),便于主程序調(diào)用控制實現(xiàn)同時操作多個串口。
(2)串口中斷函數(shù)。主程序可采用發(fā)送消息的方式,向DLL發(fā)送中斷消息,從而觸發(fā)DLL中的中斷函數(shù),停止串口收發(fā)數(shù)據(jù)。
(3)協(xié)議發(fā)送控制和接收解析函數(shù)。協(xié)議調(diào)用的接口函數(shù)主要包括以下兩個部分:一是提供統(tǒng)一的指令發(fā)送接口函數(shù),供主程序調(diào)用后,在DLL內(nèi)完成組幀發(fā)送操作;二是提供統(tǒng)一的解析接口函數(shù),將轉(zhuǎn)臺的狀態(tài)數(shù)據(jù)返回,顯示在主程序界面中。
程序采用Microsoft Visual Studio 2010開發(fā)平臺,開發(fā)語言為VC++,主程序開發(fā)語言為同一語言。程序界面如圖4所示。在工程實踐中,用于飛行試驗中對轉(zhuǎn)臺的通信控制試驗,試驗未出現(xiàn)信號中斷或異常,控制效果良好。
圖4 主程序界面
本文將協(xié)議和串口通信封裝在DLL中,并基于DLL實現(xiàn)了上位機與三自由度轉(zhuǎn)臺之間的串口通信。這種處理方法通信速度快、節(jié)省資源、簡化主程序的開發(fā)過程、遵循模塊化程序設(shè)計思想,具有較強的可拓展性和實用性,在轉(zhuǎn)臺試驗中得到了較好的應(yīng)用。