NMEA 解析程序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NMEA 解析程序相关的知识,希望对你有一定的参考价值。

经常需求使用 GPS 串口 NMEA 解析的功能,写了一段代码来完成引功能。
分享一下,大家一起学习。

头文件:

 1 #ifndef _GPS_MONITER_HH_  
 2 #define _GPS_MONITER_HH_  
 3   
 4 BOOL InitSerailPort(CString csSerialPort,LPVOID pParent = NULL);  
 5 DWORD WINAPI ReadNMEAThread(LPVOID lpParameter);  
 6 void SetSystemTimeFormUTC(CString csDate,CString csUTCTime);  
 7   
 8 void DeinitSerialPort(void);  
 9   
10 #endif  

源文件:

  1 #include "stdafx.h"  
  2 #include "GPSMoniter.h"  
  3   
  4 #define SATTATOLNUMBER  32  
  5   
  6 // 用于在 GPS 监控界面显示 NMEA 信息  
  7 char gcBuff[4096];  
  8   
  9 CString gcsTime;  
 10 CString gcsDate;  
 11 int gdSignalNumber[SATTATOLNUMBER];  
 12 CString csLat;  
 13 CString csLatdir;  
 14 CString csLon;  
 15 CString csLondir;  
 16 CString csAltitude;  
 17 CString csSpeed;  
 18 CString csOrientation;  
 19 int nNumDisplayed;  
 20 int giGSVSatNumber;  
 21   
 22 HANDLE ghCommHandle;  
 23 HANDLE nmeathread_hand;                         // Global handle to the NMEA reading thread  
 24   
 25 CString gcsGPSState;    //定位: A; 导航: V  
 26 CString gcsTimeOp;  
 27 CString gcsLatField;  
 28 CString gcsLonField;  
 29 int giResult;  
 30   
 31 int giSalNumber;  
 32 int giGSVCurrentPackage;  
 33   
 34 int giHourDiff;  
 35   
 36 BOOL InitSerailPort(CString csSerialPort,LPVOID pParent)  
 37 {  
 38     DCB commDCB;  
 39     COMMTIMEOUTS timeouts;  
 40   
 41     ghCommHandle = CreateFile(csSerialPort, GENERIC_READ | GENERIC_WRITE, 0, NULL,   
 42         OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);  
 43     if(INVALID_HANDLE_VALUE == ghCommHandle)  
 44     {  
 45         RETAILMSG(1, (TEXT("Opening GPS %s failed: %d!\r\n"),csSerialPort,(int)GetLastError()));  
 46         return FALSE;  
 47     }  
 48   
 49     commDCB.DCBlength = sizeof (DCB);  
 50     if(!GetCommState(ghCommHandle,&commDCB))  
 51     {  
 52         CloseHandle(ghCommHandle);  
 53         ghCommHandle = INVALID_HANDLE_VALUE;  
 54          RETAILMSG(1,(L"Failed in getting GPS %s DCB settings: %d!\r\n",csSerialPort,(int)GetLastError()));  
 55         return FALSE;  
 56     }  
 57     commDCB.DCBlength = sizeof(DCB);   
 58     commDCB.BaudRate = 9600;             // Current baud  
 59     commDCB.ByteSize = 8;                 // Number of bits/bytes, 4-8  
 60     commDCB.Parity = NOPARITY;            // 0-4=no,odd,even,mark,space   
 61     commDCB.StopBits = ONESTOPBIT;        // 0,1,2 = 1, 1.5, 2  
 62   
 63     // Setting serial port to Centrality speicifcations  
 64     if(!SetCommState(ghCommHandle,&commDCB))  
 65     {  
 66         CloseHandle(ghCommHandle);  
 67         ghCommHandle = INVALID_HANDLE_VALUE;  
 68         RETAILMSG(1,(L"Error in trying to set GPS %s DCB settings: %d!\r\n",csSerialPort,(int)GetLastError()));  
 69         return FALSE;  
 70     }  
 71   
 72     // Get the default timeout settings for port  
 73     if(!GetCommTimeouts(ghCommHandle, &timeouts))  
 74     {  
 75         CloseHandle(ghCommHandle);  
 76         ghCommHandle = INVALID_HANDLE_VALUE;  
 77         RETAILMSG(1,(L"Failed in getting GPS %s timeout settings: %d!\r\n",csSerialPort,(int)GetLastError()));  
 78         return FALSE;  
 79     }  
 80     // RETAILMSG(1,(L"%s DCB set successfully!\r\n",csSerialPort));  
 81   
 82     // Change the timeouts structure settings to Centrality settings  
 83     timeouts.ReadIntervalTimeout = 500;  
 84     timeouts.ReadTotalTimeoutMultiplier = 0;  
 85     timeouts.ReadTotalTimeoutConstant = 0;  
 86   
 87     // Set the time-out parameters for all read and write operations on the port.   
 88     if(!SetCommTimeouts(ghCommHandle,&timeouts))  
 89     {  
 90         CloseHandle(ghCommHandle);  
 91         ghCommHandle = INVALID_HANDLE_VALUE;  
 92         RETAILMSG(1,(L"Error in trying to set GPS %s timeout settings: %d!\r\n",csSerialPort,(int)GetLastError()));  
 93         return FALSE;  
 94     }  
 95   
 96     if(0 != SetCommMask(ghCommHandle,EV_RXCHAR))  
 97     {  
 98         RETAILMSG(1,(L"==Set %s mask OK!\r\n",csSerialPort));  
 99     }  
100     else  
101     {  
102         RETAILMSG(1,(TEXT("==Set %s mask failure:%d!\r\n"),csSerialPort,GetLastError()));  
103     }  
104   
105     nmeathread_hand = CreateThread(NULL,0,ReadNMEAThread,pParent,0,NULL);  
106     //nmeathread_hand = CreateThread(NULL, 0, ReadNMEAThread, this, CREATE_SUSPENDED, NULL);  
107     if(!nmeathread_hand)  
108     {  
109         RETAILMSG(1, (L"Could not create NMEA read thread.\r\n"));  
110         return FALSE;  
111     }  
112     else  
113     {  
114         //SetThreadPriority(nmeathread_hand, THREAD_PRIORITY_BELOW_NORMAL);  
115         //ResumeThread(nmeathread_hand);  
116     }  
117   
118     SYSTEMTIME stUTC;  
119     SYSTEMTIME stLocal;  
120   
121     GetLocalTime(&stLocal);  
122     GetSystemTime(&stUTC);  
123     giHourDiff = stLocal.wHour - stUTC.wHour;  
124   
125     return TRUE;  
126 }  
127   
128 // nmeathread_hand = CreateThread(NULL, 0, ReadNMEAThread, this, 0, NULL);  
129 DWORD WINAPI ReadNMEAThread(LPVOID lpParameter)  
130 {  
131     //DECLARE_USER_MESSAGE(UWM_NEW_NMEA);  
132   
133     int start, endline, onestart, oneend, linelen, degdig, iPos;  
134     ULONG bytesRead;  
135     DWORD EventMask = EV_RXCHAR;  
136     CString field;  
137     TCHAR *stopstring;  
138   
139     static int iCount = 0;  
140   
141     CWnd *mpNmea;  
142     mpNmea = (CWnd*)lpParameter;  
143   
144     // Wait on the event  
145     while(WaitCommEvent(ghCommHandle, &EventMask, NULL))  
146     {  
147         // RETAILMSG(1,(TEXT("---------------------------------------------ReadNMEAThread:%d,Tick: %d\r\n"),iCount++,GetTickCount()));  
148         // Clear the buffer before you start reading  
149         memset(gcBuff, 0, 4096);  
150   
151         // Read from serial port (4b)  
152         if (ReadFile(ghCommHandle, gcBuff, 4096, &bytesRead, NULL))  
153         {  
154             if(bytesRead == 0)  
155                 continue;  
156   
157             CString dacstr(gcBuff); /*Leo:从串口读GPS卫星数据*/  
158   
159             start = 0;  
160             endline = 0;  
161   
162             // Parse/Process the output (4c)  
163             while(1)  
164             {  
165                 int i = 0;  
166                 start = dacstr.Find(L"$G", start);  
167                 if(start < 0)  
168                     break;  
169                 endline = dacstr.Find(L"\r\n", start);  
170                 if(endline < 0)  
171                     break;  
172   
173                 linelen = endline - start;  
174                 //DebugOutput(MSG_DEBUG, "GPSViewer msg: start = %d endline = %d length = %d", start, endline, linelen);      
175   
176                 // Extract one line  
177                 CString oneline;  
178   
179                 oneline = dacstr.Mid(start, linelen);  
180 #if _DEBUG  
181                 // RETAILMSG(1,(TEXT("*******************************GPSViewer msg: Oneline = %s\r\n"),oneline));  
182 #endif  
183   
184                 onestart = 0;  
185                 oneend = 0;  
186                 i = 0;  
187                 //////////////////////////////////////////////////////////////////////////  
188                 //$GPRMC,075017.31,V,2232.6057,N,11356.3074,E,,,190708,,W,N*15  
189                 //$GPRMC,080525.82,A,2232.5196,N,11356.3719,E,,,190708,,W,A*08  
190                 if(oneline.Left(6) == L"$GPRMC")  
191                 {  
192                     while((iPos = oneline.Find(L",")) >= 0)  
193                     {  
194                         field = oneline.Left(iPos);  
195                         i ++;  
196                         oneline = oneline.Mid(iPos + 1);  
197   
198                         if(3 == i)  
199                         {  
200                             gcsGPSState = field;  
201                         }  
202                         else if(10 == i)        // <9>当前UTC日期ddmmyy 格式 - 例如: 030222  
203                         {  
204                             gcsDate = field;  
205                         }  
206                     }  
207                 }  
208                 //////////////////////////////////////////////////////////////////////////  
209                 //$GPGGA,080514.82,2232.5203,N,11356.3719,E,1,6,1.327,239.386,M,,M,,*4D  
210                 else if(oneline.Left(6) == L"$GPGGA")  
211                 {  
212                     while((iPos = oneline.Find(L",")) >= 0)  
213                     {  
214                         static int iOrientation = 0;  
215   
216                         field = oneline.Left(iPos);  
217                         i ++;  
218                         oneline = oneline.Mid(iPos + 1);  
219                         if (i == 2)  
220                         {  
221                             //////////////////////////////////////////////////////////////////////////  
222                             if(iOrientation != giResult)  
223                             {  
224                                 RETAILMSG(1,(L"[GPS]Status of GPS is changed: %d(Old: %d)\r\n",giResult,iOrientation));  
225                                 iOrientation = giResult;  
226                             }  
227                             //////////////////////////////////////////////////////////////////////////  
228                             gcsTimeOp = field;  
229                             // 将格式从: --:--:--.-- 修改为: --:--:-- ,即不显示秒后的数据 ---Leo 2009-03-26  
230                             CString csTmp = gcsTimeOp.Right(5);  
231                             CString csHour = gcsTimeOp.Left(2);  
232                             int iHour = _wtoi(csHour);  
233   
234                             if(iHour + giHourDiff < 24)  
235                             {  
236                                 csHour.Format(L"%d",iHour + giHourDiff);  
237                             }  
238                             else  
239                             {  
240                                 csHour.Format(L"%d",((iHour + giHourDiff) - 24));  
241                             }  
242                             // gcsTime = csHour + L":" + time.Mid(2,2) + L":" + csTmp.Left(2);  
243                             gcsTime = csHour + gcsTimeOp.Mid(2,2) + csTmp.Left(2);  
244                         }  
245                         else if (i == 3)          
246                         {   //Get Latitude from GGA - Value may not be valid.  Check flag to be sure.  
247                             gcsLatField = field;  
248                             degdig = gcsLatField.GetLength() - 2;  
249                             csLat = gcsLatField.Left(2) + CString(" ") + gcsLatField.Right(degdig);  
250                         }  
251                         else if (i == 4)          
252                         {   //Get Latitude Direction (N,S) from GGA - Value may not be valid.  Check flag to be sure.  
253                             csLatdir = field;  
254                         }             
255                         else if (i == 5)  
256                         {   //Get Longitude from GGA - Value may not be valid.  Check flag to be sure.  
257                             gcsLonField = field;  
258                             degdig = gcsLonField.GetLength() - 3;  
259                             csLon = gcsLonField.Left(3) + CString(" ") + gcsLonField.Right(degdig);  
260                         }  
261                         else if (i == 6)  
262                         {   //Get Longitude Direction (E,W) from GGA - Value may not be valid.  Check flag to be sure.  
263                             csLondir = field;  
264                         }  
265                         else if (i == 7)    //<6>GPS状态批示0-未定位 1-无差分定位信息 2-带差分定位信息  
266                         {   //Get Flag from GGA indicating position fix.  Position output from GGA is valid.  
267                             giResult = atoi((const char*)((LPCTSTR)field));  
268                             if(0 == giResult)  
269                             {  
270                                 // RETAILMSG(1,(TEXT("===No orientation\r\n")));  
271                             }  
272                             else if(1 == giResult)  
273                             {  
274                                 // RETAILMSG(1,(TEXT("===Orientation with no difference\r\n")));  
275                             }  
276                             else if(2 == giResult)  
277                             {  
278                                 // RETAILMSG(1,(TEXT("===Orientation with difference\r\n")));  
279                             }  
280                         }  
281                         else if (i == 10)  
282                         {  
283                             csAltitude = field;  
284                         }  
285                     }  
286                 }  
287                 //$GPGSV,3,3,11,29,21,93,36,30,33,40,36,31,49,324,*46  
288                 else if (oneline.Left(6) == L"$GPGSV")  
289                 {  
290                     while((iPos = oneline.Find(L",")) >= 0)  
291                     {  
292                         field = oneline.Left(iPos);  
293                         i ++;  
294                         oneline = oneline.Mid(iPos + 1);  
295   
296                         if(3 == i)  
297                         {  
298                             if(_ttoi(field) > 0)  
299                             {  
300                                 giGSVCurrentPackage = _ttoi(field);  
301                                 if (giGSVCurrentPackage == 1) // new GSV sentence  
302                                 {  
303                                     nNumDisplayed = 0;  
304                                     for(int j = 0;j < SATTATOLNUMBER;j++)  
305                                     {  
306                                         gdSignalNumber[j] = -1;  
307                                     }  
308                                 }  
309                             }  
310                         }  
311                         else if(4 == i)  
312                         {  
313                             if(_tcstod(field, &stopstring) > 0)  
314                             {  
315                                 giGSVSatNumber = (int)_tcstod(field, &stopstring);  
316                             }  
317                         }  
318                         else if(0 == (i - 5) % 4) //卫星的PRV号星号  
319                         {  
320                             if (_ttoi(field) > 0)  
321                             {  
322                                 giSalNumber = _ttoi(field);  
323                             }                 
324                         }  
325                         else if(3 == (i - 5) % 4) // SNR  
326                         {  
327                             if (_ttoi(field) > 0)  
328                             {  
329                                 gdSignalNumber[giSalNumber-1] = _ttoi(field);  
330                                 nNumDisplayed++;  
331                             }  
332                         }  
333                     }  
334                     if ((iPos = oneline.Find(L"*")) >= 0) // last sat  
335                     {  
336                         field = oneline.Left(iPos);  
337                         i ++;  
338                         if(3 == (i - 5) % 4) // SNR  
339                         {  
340                             if (_ttoi(field) > 0)  
341                             {  
342                                 gdSignalNumber[giSalNumber-1] = _ttoi(field);  
343                                 nNumDisplayed++;  
344                             }  
345                         }  
346                     }  
347                 }  
348                 //$GPVTG,<1>,T,<2>,M,<3>,N,<4>,K,<5>*hh   
349                 // <1> 对地航向(单位:度)  
350                 // <2> 磁偏角(单位:度)  
351                 // <3> 对地航速(单位:哩/小时)  
352                 // <4> 地面速率(0000.0~1851.8公里/小时,前面的0也将被传输)  
353                 //如: $GPVTG,359.95,T,,M,15.15,N,28.0,K,A*04   
354                 else if(oneline.Left(6) == L"$GPVTG")  
355                 {  
356                     while((iPos = oneline.Find(L",")) >= 0)  
357                     {  
358                         field = oneline.Left(iPos);  
359                         i ++;  
360                         oneline = oneline.Mid(iPos + 1);  
361                         if(2 == i)  
362                         {  
363                             csOrientation = field;  
364                         }  
365                         else if(8 == i)  
366                         {  
367                             csSpeed = field;  
368                         }  
369                     }  
370                 }  
371                 start = endline + 2;  
372             } // end of buffer processing  
373         }   
374         //Sleep(1000);// end of ReadFile  
375     } // end of WaitCommEvent  
376     {  
377         // RETAILMSG(1,(TEXT("Exit GPS thread:%d"),GetLastError()));  
378     }  
379   
380     return 0;  
381 }// end of ReadNMEAThread  
382   
383   
384 //csDate: 01-01-03  
385 //csUTCTime: 04:07:44.08  
386 void SetSystemTimeFormUTC(CString csDate,CString csUTCTime)  
387 {  
388     SYSTEMTIME st;  
389     int iHour = 0;  
390     int iMinute = 0;  
391     int iSecond = 0;  
392     int iYear = 0;  
393     int iMonth = 0;  
394     int iDay = 0;  
395     CString csSubString;  
396     TCHAR *stopstring;  
397     // RETAILMSG(1,(TEXT("====Set system time from UTC.Date: %s, Time: %s"),csDate,csUTCTime));  
398   
399     GetSystemTime(&st);  
400   
401     csSubString = csDate.Left(2);  
402     iDay = (int)_tcstod(csSubString, &stopstring);  
403   
404     csSubString = csDate.Mid(3,2);  
405     iMonth = (int)_tcstod(csSubString, &stopstring);  
406   
407     csSubString = csDate.Right(2);  
408     iYear = 2000 + (int)_tcstod(csSubString, &stopstring);  
409   
410     st.wYear = iYear;  
411     st.wMonth = iMonth;  
412     st.wDay = iDay;  
413   
414     csSubString = csUTCTime.Left(2);  
415     iHour = (int)_tcstod(csSubString, &stopstring);   
416   
417     csSubString = csUTCTime.Mid(3,2);  
418     iMinute = (int)_tcstod(csSubString, &stopstring);  
419   
420     csSubString = csUTCTime.Mid(6,2);  
421     iSecond = (int)_tcstod(csSubString, &stopstring);  
422   
423     st.wHour = iHour;  
424     st.wMinute = iMinute;  
425     st.wSecond = iSecond;  
426   
427     SetSystemTime(&st);  
428 }  
429   
430 void DeinitSerialPort(void)  
431 {  
432     SetCommMask(ghCommHandle,0);  
433   
434     if(nmeathread_hand)  
435     {  
436         TerminateThread(nmeathread_hand,1);  
437         CloseHandle(nmeathread_hand);  
438     }  
439     if(INVALID_HANDLE_VALUE != ghCommHandle)  
440     {  
441         EscapeCommFunction(ghCommHandle,CLRDTR);  
442         EscapeCommFunction(ghCommHandle,CLRRTS);  
443         //清除驱动程序内部的发送和接收队列  
444         PurgeComm(ghCommHandle,PURGE_TXCLEAR|PURGE_RXCLEAR);  
445   
以上是关于NMEA 解析程序的主要内容,如果未能解决你的问题,请参考以下文章

GPS(NMEA)数据解析

c_cpp NMEA格式解析

NMEA协议解析

高通平台开发系列讲解(GPS篇)NMEA数据包解析

高通平台开发系列讲解(GPS篇)NMEA数据包解析

GPS串口报文NMEA格式,Python解析L76-gps数据流