首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

VC++ 實作 GPS 定位資料擷取:串口通訊與 NMEA 0183 解析

     編輯:關於VC++

前言

衛星導航技術已廣泛應用於民用與軍事領域。本文以美國 GPS 系統為例,詳細說明如何在 Windows 平台上透過 RS-232 序列埠接收 GPS 接收機輸出的 NMEA 0183 格式資料,並解析出經緯度、速度、時間等關鍵定位參數。

序列埠通訊初始化 (Win32 API)

// 以非同步方式開啟 COM1
m_hCom = CreateFile(_T("COM1"), GENERIC_READ|GENERIC_WRITE, 0, NULL,
    OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
SetCommMask(m_hCom, EV_RXCHAR);                    // 設定接收字元事件
SetupComm(m_hCom, READBUFLEN, WRITEBUFLEN);        // 設定緩衝區大小
PurgeComm(m_hCom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);

// 設定逾時參數
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
SetCommTimeouts(m_hCom, &CommTimeOuts);

// 設定 DCB 參數:4800 bps, 8 data, odd parity, 1 stop bit
GetCommState(m_hCom, &dcb);
dcb.BaudRate = CBR_4800; dcb.ByteSize = 8; dcb.Parity = ODDPARITY; dcb.StopBits = ONESTOPBIT;
SetCommState(m_hCom, &dcb);

事件觸發式資料接收迴圈

while (true)
{
    WaitCommEvent(m_hCom, &dwEvtMask, NULL);
    if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR)
    {
        if (ComStat.cbInQue > 0)
            ReadFile(m_hCom, m_readbuf, ComStat.cbInQue, &nLength, &olRead);
    }
}

NMEA 0183 $GPRMC 句型解析

GPS 接收機持續輸出多種句型,$GPRMC 包含最常用的導航資訊:

$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>*hh
<1> UTC 時間 hhmmss
<2> 狀態 A=有效 V=無效
<3> 緯度 ddmm.mmmm
<4> N/S 半球
<5> 經度 dddmm.mmmm
<6> E/W 半球
<7> 地面速度 0.0~999.9 節
<8> 方位角 000.0~359.9 度
<9> 日期 ddmmyy
<10> 磁變角 000.0~180.0 度
<11> 磁變方向 E/W

解析邏輯:逗號計數法

for (int i=0; i<bufLen; ++i)
{
    if (Data[i] == '$') SectionID = 0;           // 偵測句首
    else if (Data[i] == 10) { /* LF 句尾 */ }
    else if (Data[i] == ',') SectionID++;        // 逗號計數
    else
    {
        switch (SectionID)
        {
            case 1: m_sTime += Data[i]; break;          // UTC 時間
            case 2: if (Data[i]=='A') valid=true; break; // 定位有效性
            case 3: m_sPositionY += Data[i]; break;      // 緯度
            case 5: m_sPositionX += Data[i]; break;      // 經度
            case 9: m_sDate += Data[i]; break;           // 日期
        }
    }
}

字串轉數值與座標換算

// 時間轉北京時間 (UTC+8)
str.Format(_T("%c%c"), buf[0], buf[1]);
hour = (atoi(str) + 8) % 24;

// 緯度 ddmm.mmmm -> 度分格式
str.Format(_T("%c%c"), buf[0], buf[1]); deg = atoi(str);
str.Format(_T("%c%c%c%c%c%c%c"), buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8]);
lat = deg * 60 + atof(str); // 單位:分

// 經度 dddmm.mmmm (可能 2 或 3 位數度)
if (len==10) { str.Format(_T("%c%c%c"), buf[0],buf[1],buf[2]); deg=atoi(str); ... }
else         { str.Format(_T("%c%c"), buf[0],buf[1]); deg=atoi(str); ... }

結語

本文結合完整程式碼示範了從序列埠開啟、參數設定、非同步接收、NMEA 句型解析到座標數值轉換的完整流程。開發者可據此整合至 GIS、RS 等上層應用。測試環境:Windows 98 + Visual C++ 6.0。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved