GPS数据格式解析源代码举例

本文转自:http://norke.blog.163.com/blog/static/2765720820116185028104/


GPS数据格式解析源代码举例

 

随着内置GPS的手机越来越多,GPS相关的应用也越来越广泛,GPS已经不仅仅只是得到一个经纬度的信息,可以通过GPS开发出更多的应用,比如位置图片,比如好友位置显示,比如跟踪等等,TimeSyncPPC就是可以使用GPS的时钟来进行时间同步的。
    
    所有这些功能都需要知道GPS的数据格式并能够解析出自己需要的数据出来。下面就以TimeSyncPPC中如何得到GPS的日期和时间为例来说明如何解析GPS数据。
    
    TimeSyncPPC是用于Pocket PC上的时间同步工具,因此得到GPS的时间和日期,使用的GPS的指令是$GPRMC,其指令格式如下:
    
    $GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11> 

      1) 标准定位时间(UTC time)格式:时时分分秒秒.秒秒秒(hhmmss.sss)。 
      2) 定位状态,A = 数据可用,V = 数据不可用。 
      3) 纬度,格式:度度分分.分分分分(ddmm.mmmm)。 
      4) 纬度区分,北半球(N)或南半球(S)。 
      5) 经度,格式:度度分分.分分分分。
      6) 经度区分,东(E)半球或西(W)半球。 
      7) 相对位移速度, 0.0 至 1851.8 knots 
      8) 相对位移方向,000.0 至 359.9度。实际值。 
      9) 日期,格式:日日月月年年(ddmmyy)。 
      10) 磁极变量,000.0 至180.0。 
      11) 度数。 
      12) Checksum.(检查位) 

    从数据格式中可以看出,我们需要得到1和9两个字段的数据即可。
    
    当然,使用GPS首先要打开GPS的串口,代码如下:  
HANDLE OpenCom(CString strCom, DWORD BaudRate, BYTE ByteSize, BYTE StopBits, BYTE Parity, int FlowControl)
{
    HANDLE  hCommPort;

    CString strTemp;

    if((hCommPort = CreateFile(strCom, GENERIC_READ | GENERIC_WRITE, 0,
                        NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
    {
        return NULL;
    }
    
    DCB          commDCB;
    CString      strWinText;

    GetCommState(hCommPort, &commDCB);

    commDCB.BaudRate    = BaudRate;
    commDCB.ByteSize    = ByteSize;
    commDCB.StopBits    = StopBits;
    commDCB.fParity        = (NOPARITY == Parity) ? FALSE : TRUE;
    commDCB.Parity        = Parity;

    commDCB.fDsrSensitivity = FALSE;
    commDCB.fDtrControl     = DTR_CONTROL_ENABLE;

    if(FlowControl == 1)    // Hardware
    {
        // Enable RTS/CTS Flow Control
        commDCB.fRtsControl = RTS_CONTROL_HANDSHAKE;
        commDCB.fOutxCtsFlow = 1;
        commDCB.fOutX = 0;
        commDCB.fInX = 0;
    }
    else if(FlowControl == 0)    // Software
    {
        // Enable XON/XOFF Flow Control
        commDCB.fRtsControl = RTS_CONTROL_ENABLE;
        commDCB.fOutxCtsFlow = 0;
        commDCB.fOutX = 1;
        commDCB.fInX  = 1;  
    }
    else
    {
        commDCB.fRtsControl = RTS_CONTROL_ENABLE;
        commDCB.fOutxCtsFlow = 0;
        commDCB.fOutX = 0;
        commDCB.fInX  = 0;
    }

    SetCommState(hCommPort, &commDCB);

    return hCommPort;
}    

    串口打开后需要得到一行GPS数据,GPS数据是以结束,代码如下:
// 返回值为-1:超时,其他值为数据长度
int GetGPSLineData(HANDLE hCommPort, char *ReadBuf, int Length)
{
    // 读一行GPS数据
    DWORD nBytes;
    int i = 0;
    DWORD TimeOut = 0;
    while(i < Length)
    {
        if(g_isQuit)
            return i;

        TimeOut ++;
        if(TimeOut >= 100)
            return -1;

        ReadFile(hCommPort, (LPVOID)&ReadBuf[i], 1, &nBytes, NULL);
        if(nBytes == 0)
        {
            Sleep(1);
            continue;
        }

        TimeOut = 0;

        if(ReadBuf[i] == 0x0d)
        {
            ReadBuf[i] = 0;
            break;
        }
        if(ReadBuf[i] == 0x0a)
        {
            continue;
        }

        i ++;
    }

    return i;
}    

    下面是解析一行GPS数据,将数据结果存储在一个数组中,代码如下:
// 解析一行GPS数据
int AnalyzeGPSData(char *GPSData, int Length, char Command[][100])
{
    int i = 0;
    int j = 0, k = 0;
    while(i < Length)
    {
        if(GPSData[i] == ',')
        {
            Command[j][k] = 0;
            j ++;
            k = 0;
            i ++;
            continue;
        }
        Command[j][k] = GPSData[i];
        k ++;
        i ++;
    }

    return j;
}
解析之后的GPS数据包含命令和参数,下面就是判断是否是我们需要的命令,如果是得到第一个和第九个参数即可。不过要注意,GPS时间是世界标准时间,因此要转换成本地时间,代码如下:
DWORD WINAPI GetGPSTime(LPVOID lpParameter)
{
    char ReadBuf[1000];
    DWORD TimeOut = 0;
    
    char Command[40][100];

    HANDLE hCommPort = OpenCom(g_strComPort, g_BaudRate);
    if(hCommPort == NULL)
    {
        MessageBox(NULL, _T("Can not open COM port!"), NULL, MB_OK | MB_TOPMOST);
        goto GPSExit;
    }

    while(1)
    {    
        if(g_isQuit)
            break;

        // 读一行GPS数据
        int Length = GetGPSLineData(hCommPort, ReadBuf, 999);
        if(Length == -1)
        {
            TimeOut ++;
            if(TimeOut < 100)
                continue;
        }

        if(TimeOut >= 100)
        {
            MessageBox(NULL, _T("Read GPS data timeout!"), NULL, MB_OK | MB_TOPMOST);
            goto GPSExit;
        }
        TimeOut = 0;

        AnalyzeGPSData(ReadBuf, Length, Command);
        
        if(strcmp(Command[0], "$GPRMC") == 0)
        {
            SYSTEMTIME st, LocalSt;

            st.wHour = (Command[1][0] - '0') * 10 + (Command[1][1] - '0');
            st.wMinute = (Command[1][2] - '0') * 10 + (Command[1][3] - '0');
            st.wSecond = (Command[1][4] - '0') * 10 + (Command[1][5] - '0');
            st.wMilliseconds = (Command[1][7] - '0') * 100 + (Command[1][8] - '0') * 10 +  (Command[1][9] - '0');

            st.wDay = (Command[9][0] - '0') * 10 + (Command[9][1] - '0');
            st.wMonth = (Command[9][2] - '0') * 10 + (Command[9][3] - '0');
            st.wYear = (Command[9][4] - '0') * 10 + (Command[9][5] - '0') + 2000;

            FILETIME FileTime, LocalFileTime;
            SystemTimeToFileTime(&st, &FileTime);
            FileTimeToLocalFileTime(&FileTime, &LocalFileTime);
            FileTimeToSystemTime(&LocalFileTime, &LocalSt);

            g_GPSDateCtrl->SetTime(LocalSt);
            g_GPSTimeCtrl->SetTime(LocalSt);
            if(strcmp(Command[2], "A") == 0)
            {

                BOOL ret = SetSystemTime(&st);
                MessageBox(NULL, _T("SyncTime Success!"), _T(""), MB_OK | MB_TOPMOST);

                strGPSButton = _T("Get GPS Time");
                g_ThisDlg->SetDlgItemText(IDC_GETGPSTIME, strGPSButton);
                g_ThisDlg->GetDlgItem(IDC_SETGPSTIME)->EnableWindow(0);

                break;
            }
            else
            {
                TimeOut ++;
            }
        }
        
    }

GPSExit:

    if(hCommPort != NULL)
        CloseHandle(hCommPort);

    g_GetGPSTimeThread = NULL;

    strGPSButton = _T("Get GPS Time");
    g_ThisDlg->SetDlgItemText(IDC_GETGPSTIME, strGPSButton);
    g_ThisDlg->GetDlgItem(IDC_SETGPSTIME)->EnableWindow(0);
    
    return TRUE;
}    

    如果需要解析其他指令,可以参考函数DWORD WINAPI GetGPSTime(LPVOID lpParameter)的实现方法,其实还是比较简单的。
    
    这些代码已经在TimeSyncPPC中测试过,可以直接使用,开发环境为VS2005,Windows Mobile 6.1 for PPC。如有疑问请在下方留言

猜你喜欢

转载自blog.csdn.net/qq_38335172/article/details/77620489