張 超 ,范娟利 ,章傳銀 ,方書山
(1.中國測繪科學研究院,北京 100830; 2.山東科技大學,山東 青島266510;3.中測新圖(北京)遙感技術有限責任公司,北京 100039)
隨著計算機通信技術的發展,越來越多的新技術被用到測繪行業獲取高質量的測量數據,但正確的獲取觀測數據是測量的根本,也是避免誤差的重要措施之一。全球導航定位系統的數據格式遵循NEMA-0183協議,目前關于解析該類的文獻很多,但是這些文獻有的是簡單介紹一下單行數據的解析,有的是基于后處理的數據解析,有的是沒有結合讀取串口或者網口數據流來分析,而基于ASCII的無地址格式數據的解析更是少之又少。
在實際應用中,GPS接收機、羅經方位系統、數字羅盤等儀器輸出的數據都是NEMA-0183格式的數據[1]。另外,一些硬件廠商為了產品需求,方便數據收發而自定義各自的數據通信格式(用戶層面的通訊協議)的數據。
基于上述情況,本文以NEMA-0183格式數據與U型激光傳感器所示的基于ASCII碼的無地址格式數據為基礎,詳細介紹基于串口 NEMA-0183 格式和ASCII無地址實時數據流的解析。
NEMA 0183是美國國家海洋電子協會(NMEA )為海用電子設備制定的標準格式。目前已成了GPS導航設備統一的國際海運事業無線電技術委員會(RTCM)標準協議。NEMA-0183 格式數據串的所有數據都采用 ASCII文本字符表示,數據傳輸以“$”開頭,后面是語句頭。語句頭由五個字母組成,分兩部分,前兩個字母表示“系統ID”,即表示該語句是屬于哪種系統,后面三個字母表示“語句ID”,表示該語句是關于哪方面的數據。語句頭后是數據體,包含不同的數據體字段,語句末尾為校驗碼(可選,由十六進制組成),以回車換行符
NEMA-0183協議是GPS接收機應當遵守的標準協議,也是目前GPS 接收機上使用最廣泛的協議,大多數常見的GPS接收機、GPS數據處理軟件、導航軟件都遵守或者至少兼容這個協議。本文中使用的是 NovAtel 的GPS-OEMV4板接收機。其輸出的數據格式$GPGLL,5106.9802869,N,11402.3037325,W,182147.00,A*1C。其中$GPGLL 為語句頭,5106.9802869表示51°06.9802869分,N表示緯度,11402.3037325表示 114°02.3037325 s,W表示經度,182147.00表示18點21分47.00秒,A表示數據可用,如果是V表示數據不可用,*標示此句馬上結束,1C為校驗和。
導航用的三維數字羅盤也輸出 NEMA-0183格式數據,數字羅盤主要輸出姿態(航向、橫滾、俯仰)數據,本文以型號為XW_EC1730的電子羅盤為例,其串口輸出的 NEMA-0183 數據格式舉例:$C220.6,P4.5,R0.3,X-8.20,Y-10.74,Z-20.33,T15.0*49.其中$:數據包幀頭,C220.6:航向角,值為220.6°,P4.5:俯仰角,值為4.5°,R0.3:橫滾角,值為0.3°,X-8.20:X軸磁場強度,值為-8.20,Y-10.74:Y軸磁場強度,值為-10.74,Z-20.33,Z軸磁場強度,值為-20.33,T15.0:傳感器溫度,值為15.0,*49,校驗和。
基于ASCII無地址格式數據是廠商根據串口通信用戶層協議編制原則:1) 數據包必須有包頭;2) 非定長數據包必須有包尾;3) 一般應對數據進行檢校;4) 要求便于觀察的數據應該在結尾加入換行等符號;5) 要求更新快的數據,應盡量簡短[3]自定義通信協議的典型。其數據格式是$<1>,<2>,<3>…$<1>,<2>,<3>…$<1>,<2>,<3>…,……,該數據格式與NEMA-0183數據格式最大的區別:1) 沒有類似于符號“*”的數據結束標示符;2) “$”符號后的字段數不固定;3)每個字段長度也不固定。例如:A.如果現在只需要測量距離信息和激光反射強度,通過串口寫數據函數,設置好后其數據流為$BM10.841,22348$BM10.842,22355$BM10.840,22991……,說明所測距離為10.841 m、10.842 m和10.840 m,分別對應的激光反射強度為22348B、22355B、22991B.如果僅需要測量距離信息,同樣通過串口寫數據函數,設置好后其數據流為$BM20.882$BM21,235$BM20.013……,其中所測距離分別為20.882 m、21,235 m、20.013 m.
將GPS串口、數字羅盤串口、U型傳感器串口分別與電腦連接,利用串口調試工具查找各自對應串口號。將GPS串口波特率設置為115 200,羅盤串口波特率設置為192 00,U型激光傳感器的波特率設置為115 200.GPS 串口輸出的數據類型為 NEMA-0183 格式的 GPGLL 數據,其包含測站位置數據(測站經緯度、 對應時間、狀態及檢校位)。數字羅盤的數據流包含姿態數據(俯仰角、方位角及翻滾角)。U型傳感器數據流包含測距數據或激光反射強度信息。連接本文設計的程序,設置好各自串口號及波特率,連接成功后通過串口采集兩種格式的ASCII數據,將所需數據解析提取并存儲。
串行口的本質功能是作為CPU和串行設備間的編碼轉換器,當數據從CPU經過串口發送出去時,字節數據轉換為串行位。在接收數據時,串口的位被轉換為字節數據。在Windows環境下,串口是系統資源的一部分,應用程序要使用串口進行通信,必須在使用之前向操作系統提出資源申請(打開串口),通信完成后必須釋放資源(關閉串口)[4-7]。那么按照上節兩種格式的ASCII數據流的規律及區別,對串口數據流的讀取,采用如圖1所示的思路設計串口類。

圖1 串口數據流解析流程圖
本文串口類的設計以多線程串口類CSerialPort為基礎,需要用到的主要函數有:打開關閉串口函數、串口參數設置和初始化函數、串口讀寫函數。
本文中,串口類名為:CSerialCom.定義如下:
class CSerialCom
{
……
public:
HANDLE m_hComm; //串口句柄
BOOL CreateComEvent();//建立串口通訊事件
BOOL OpenPort(int port); //打開串口,即通知其他程序禁用此串口
BOOL ConfigurePort(int baud, int timeout); //串口參數的設置和初始化
ReadFile(m_hComm, unsigned char*data, DWORD len, DWORD &read, NULL);//讀串口數據
WriteFile(m_hComm, unsigned void*data, DWORD len, DWORD &read, NULL); //寫串口數據
BOOL ClosePort(int port);//關閉使用的串口,即釋放串口以供其他程序使用
……
};
根據所需數據的類型,設計該類時只用了簡單的同步I/O數據讀寫方式。其中所用函數為Windows API函數,具體使用說明可查閱相關資料。
由于GPS-OEM板卡輸出的數據格式與羅盤XW_EC1730輸出的數據格式都是NEMA-0183格式數據,是特殊數據格式。U型激光傳感器輸出的數據格式為基于ASCII的無地址格式數據,是以串口通訊標準的最基本形式。所以以U型激光傳感器輸出的基于ASCII無地址格式數據流為例。NEMA-0183數據流的解析只需在此基礎上稍作修改即可。
設計U型激光傳感器的基于ASCCII無地址格式數據解析類,命名為CLaserThread。利用多線程函數的功能,設計虛成員函數為Run函數。Run函數的功能就是從串口中讀取數據、解析并存儲數據。
CLaserThread的定義如下:
class CLaserThread:public CWinThread,public CSerialCom
{
public:
virtual int Run();//接收并解析串口數據
bool StoreData();//數據存儲函數
}
其中CWinThread為系統自帶類,具體功能可查閱相關資料。
由第1節U型激光傳感器的基于ASCII無地址格式數據流的規律,通過串口數據解析的方法為:先讀取緩存中的所有數據,再對數據進行解析。由于該數據只有數據頭標示符“$”,沒有結束符標志,就需要特殊的方法來解析緩存區的數據,指針首先找到“$”字符,然后下移直到再次遇到“$”字符,去掉最后一個“$”字符后就可以提取出第一組數據,按照事先測試的每個逗號前的數據內容,以“,”為標志提取相關數據,而“$”前的最后一個數據可通過用該組數據的總長度減去截止最后一個逗號的字符串長度來獲取,關鍵在提取第二組數據時,指針起始位置需向上移動一位,這樣再按照第一組數據提取的方式進行解析就可以得到第二組數據。如此反復,就可以將讀入緩存區的數據解析完。其實現過程如圖2所示。

圖2 基于ASCII無格式數據流解析過程
按照上述方法設計Run函數,如下:
int ClaserThread::Run()
{
unsigned char szBuffer[2048];//設置數據緩沖區大小
DWORD nReadLen = 0;//緩沖區中被讀取的字節數
int nLeftLen = 0; //未解析剩余的字節數
DWORD nOffset = 0; //每次解析完的字節數
DWORD nIndexEnd = 0; //結束符索引值
//讀取羅盤串口數據
ReadData(szBuffer + nLeftLen, sizeof(szBuffer) -nLeftLen -1, nReadLen); nLeftLen += nReadLen;
nOffset = 0;
while(nLeftLen>0){
while(nLeftLen>0){
if(szBuffer[nOffset] == '$')break;//找到數據包的幀頭
nOffset += 1;nLeftLen -= 1;}
while(int(nIndexEnd -nOffset) <= nLeftLen && nIndexEnd < (sizeof szBuffer))
{
switch(szBuffer[nIndexEnd])
{case '$':isFind=1;//是否找到數據包幀頭標志$
break;
default:isFind=0;break;}
if (isFind){break; } else{nIndexEnd+=1; continue; }}
//如果數據包不完整情況就舍棄
if(int(nIndexEnd -nOffset) > nLeftLen|| szBuffer[nIndexEnd] == 0)
{
memmove(szBuffer, szBuffer + nOffset, nLeftLen);break;}
nLeftLen -= (nIndexEnd -nOffset + 1);
…………
while(nOffset < nIndexEnd)
{
for(int i=2;lastData;i++){
if(*(szBuffer+i)==44){
L=atof((const char*)(szBuffer+2+nOffset));//距離值
S=atof((const char*)(szBuffer+i+nOffset));//激光強度大小
lastData=false;//判斷是否到數據包結尾
StoreData();//將提取的測量數據存儲起來
}}
if (szBuffer[nIndexEnd]==_T('$')) //查找下一個字段的開始標示符$
{nLeftLen-=nIndexEnd+1;
nOffset=nIndexEnd;}}}
::PostThreadMessage(m_nThreadID, WM_QUIT, 0, 0);
return CWinThread::Run();
}
由于篇幅限制,Run函數中部分內容省去,僅留關鍵部分。
對于NEMA-0183格式數據流的解析,以數字電子羅盤數據為例。其解析方法為:先讀取緩存中的所有數據,然后再對數據進行解析。針對NEMA-0183格式數據每句都是以“$”開頭,以“*”符號標示結尾,他們之間的數據就是我們所需要的姿態數據。將這之間按“P”“C”“R”的標志將三個姿態數據提取出來。解析完該句后,指針繼續下移,分別找到“$”字符和“*”字符。又解析出下組數據,如此反復直到解析完該緩存區中的所有數據。等下一時刻緩存區存儲數據后再次進行解析,重復以上步驟就可實時獲取所需數據。其實現過程如圖3所示。

圖3 NEMA-0183格式數據流解析過程
NEMA-0183數據流解析的實現過程可在基于ASCII無地址格式數據流解析過程基礎上將代碼稍作調整即可。
由于實時數據流速率和大小的不確定性,作者基于vs2008sp1平臺上編寫了能夠同時接收多個串口數據的多線程程序,利用上述數據解析方法,通過自制控制板卡(串口轉USB接口控制),將連接好天線的NovAtel-OEM4板卡、數字羅盤和U型激光傳感器與PC連接,分別實現了NovAtel-OEM4板卡的GPS數據解析(需將存儲文件通過相應轉換軟件分離出觀測文件、導航文件及氣象文件中的相關數據),數字羅盤數據解析和U型激光傳感器的基于ASCII碼的無地址數據解析。為方便查看和使用所獲數據,電子羅盤數據和基于ASCII碼的無地址數據按照所需的設計格式進行存儲。如表1所示。

表1 解析結果示例
由于篇幅限制,對GPS數據的解析[8-9]不作列出。
通過對基于ASCII無地址格式與NEMA-0183格式實時數據流解析方法介紹與程序編寫,實現了相關數據的提取,驗證了上述解析方法的適用性。如果按照串口通信中用戶層協議一般編制原則,其他類似數據格式的ASCII數據,就可以以NEMA-0183格式數據和基于ASCII碼無地址格式數據為基礎,按照需求目的,在原有代碼基礎上,稍作改動,就可獲取所需測量信息。
[1] 袁德寶,崔希民,郎 博,等.基于VC++的GPS-0EM板卡串行通信關鍵算法的設計與實現[J].測繪科學,2008,33(6):170-172.
[2] 龔建偉.Visual C++/Turbo C串口通信編程實踐[M].北京:電子工業出版社,2007.
[3] 汪 穎,孫華軍.基于VC++串口通信的設計與實現[J].現代電子技術,2011,34(14):19-20.
[4] 唐新國.計算機串口數據采集與數據存儲的設計與應用[J].西華師范大學學報·自然科學版,2004,25(2):213-218.
[5] 高振松,過靜珺,李冰皓,等.Windows CE下實現掌上機和GPS-OEM板的通信[J].測繪通報,2001(5):35-36.
[6] 汪 兵.Windows CE 嵌入式高級編程及其實例詳解[M].北京:水利水電出版社,2008.
[7] 申曉寧,趙毅強,張 進,等.多線程串口類在實時數據采集系統中的應用[J].Computer Era,2010(1):28-30.
[8] 王曉東.基于VC++的GPS數據采集系統的設計與實現[J].湖北汽車工業學院學報,2006,20(2):46-49.
[9] 李洪濤,許國昌,薛鴻印,等.GPS應用程序設計[M].北京:科學出版社,1999.