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 解析程序的主要内容,如果未能解决你的问题,请参考以下文章