目前GPS(全球定位系统)定位应用市场日趋成熟,正在进入应用的高速发展时期。看到论坛里不断有人提问关于GPS的问题。现将个人对GPS的了解写出来跟大家一块探讨。
1、 GPS应用简介
近年来GPS系统,已经在大地测绘、海上渔用、车辆定位监控、建筑、农业等各个领域得到广泛应用。从九十年代我国引进GPS定位技术开始,经过十多年的市场培育,GPS定位应用进入了发展的最好时机,未来十年基于GPS的应用将会改变我们的生活和工作方式。
目前市场上的大部分GPS接受模块都是通过RS232串口与MCU进行数据传输的。这些数据包括经度、纬度、海拔高度、时间、卫星使用情况等基本信息。开发人员再依据这些基本数据,进行数据处理来完成整套的定位系统软件。
2、 数据格式
在进行数据接受编程之前,先介绍一下该模块的数据格式。它支持NMEA-0183输出格式。信息如下:
GGA位置测定系统定位资料(Global Positioning System Fix Data)
GSV 导航卫星资料(GNSS Satellites in View)
RMC导航卫星特定精简资料(Recommended Minimum Specific GNSS Data)
VTG 方向及速度等相关资料(Course Over Ground and Ground Speed)
由于文章篇幅问题,笔者在这里只以接收GGA数据为例,格式如下:
$GPGGA,hhmmss,dddmm.mmmm,a,dddmm.mmmm,a,x,xx,x.x,x.x,M,,M,x.x,xxxx*CS
例:$GPGGA,033744,2446.5241,N,12100.1536,E,1,10,0.8,133.4,M,,,,*1F
说明见表:
区域 | 名称 | 例 | 单位 | 说明 |
1 | 信息ID | $GPGGA |
| GGA协议开始 |
2 | UTC时间 | 033744 |
| hhmmss |
3 | 纬度 | 2446.5241 |
| dddmm.mmmm |
4 | 南/北半球指示 | N |
| N=north ; S=south |
5 | 经度 | 12100.1536 |
| dddmm.mmmm |
6 | 东/西半球指示 | E |
| E=east ; W=west |
7 | 定位指示 | 1 |
| 0 =未定位 1=定位SPS模式 2=定位DGPS, SPS模式 |
8 | 应位卫星数 | 10 |
| 00-12 |
9 | HDOP | 0.8 | 米 |
|
10 | 海拔高度 | 133.4 | 米 |
|
11 | 海拔高度单位 | M | 米 |
|
12 | WGS84水准面划分 |
|
|
|
13 | WGS-84水准面划分单位 |
|
|
|
14 | 累计GPS数据微分 |
|
|
|
15 | 参考工作站ID |
|
|
|
16 | 校验位 | *1F |
|
|
上面例子中,我们可读出位置信息:北纬24度46.5241分,西经121度00.1536分
格林威治时间:3点37分44秒
3 部分程序代码(c++)
- //初始化串口
- //入口:strComm(串口名)
- //返回:TRUE(成功);FALSE(失败)
- BOOL CGPSDlg::InitComm(CString strComm)
- {
- int i;
- DCB dcb;
- COMMTIMEOUTS TimeOuts;
- for (i=0; i<3; i++) //串口最多初始化3次
- {
- m_hComm = CreateFile(strComm, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
- if (m_hComm != INVALID_HANDLE_VALUE)
- break;
- }
- if (i == 3) //串口初始化失败
- {
- AfxMessageBox("串口初始化失败...");
- return FALSE;
- }
- SetupComm(m_hComm, MAXLENGTH, MAXLENGTH); //设置发送接收缓冲区大小
- TimeOuts.ReadIntervalTimeout = 0; //设定5个超时参数
- TimeOuts.ReadTotalTimeoutMultiplier = 0;
- TimeOuts.ReadTotalTimeoutConstant = 500;
- TimeOuts.WriteTotalTimeoutMultiplier = 0;
- TimeOuts.WriteTotalTimeoutConstant = 500;
- SetCommTimeouts(m_hComm, &TimeOuts); //设置超时参数
- GetCommState(m_hComm, &dcb); //获得通信状态
- dcb.fAbortOnError = FALSE; //有错误不停止
- dcb.BaudRate = CBR_4800; //波特率4800
- dcb.ByteSize = 8; //8位
- dcb.Parity = NOPARITY; //奇校验
- dcb.StopBits = ONESTOPBIT; //1位停止位
- SetCommState(m_hComm, &dcb); //设置通信状态
- PurgeComm(m_hComm, PURGE_TXCLEAR|PURGE_RXCLEAR); //清空发送和接收缓冲区
- return TRUE;
- }
- //获得GPS参数
- //注意:从GPS接收到的字符串已经在m_strRecv中,由于是定时接收,所以在这个字符串的头和尾都可能存在
- // 不完整的NMEA输出字符串,在处理时要特别注意
- //返回:TRUE(格式正确);FALSE(格式错误)
- BOOL CGPSDlg::GetGPSParam()
- {
- int i,j;
- CString str,strNEMA;
- //先判断是否接收到数据
- if (m_strRecv.IsEmpty())
- return FALSE;
- //若字符串不是以'$'开头的,必须删掉这部分不完整的
- if (m_strRecv[0] != '$')
- {
- i = m_strRecv.Find('/n', 0);
- if (i == -1)
- return FALSE; //尾部未接收完整,必须等接收完后才能删除
- m_strRecv.Delete(0, i+1); //尾部已接收完整(尾部为/r/n结束),删除不完整的部分
- }
- //截取完整的NMEA-0183输出语句(m_strRecv中可能有多条语句,每条间以/r/n分隔)
- for (;;)
- {
- i = m_strRecv.Find('/n', 0);
- if (i == -1)
- break; //所有的完整输出语句都已经处理完毕,退出循环
- //截取完整的NMEA-0183输出语句
- strNEMA = m_strRecv.Left(i+1);
- m_strRecv.Delete(0, i+1);
- //下面对各种输出语句进行分别处理
- if (strNEMA.Find("$GPRMC",0) == 0)
- {
- //该输出语句中的各项以','分隔
- for (i=j=0; strNEMA[i]!='/r'; i++) //j为逗号的计数器
- {
- if (strNEMA[i] == ',')
- {
- j++;
- str = "";
- for (i++; strNEMA[i]!=','&&strNEMA[i]!='/r'; i++)
- str += strNEMA[i]; //str为某项的值
- i--;
- //对各项数据分别处理
- switch (j)
- {
- case 1: //时间(UTC)
- m_strTime = str.Left(6);
- m_strTime.Insert(2, ':');
- m_strTime.Insert(5, ':');
- break;
- case 2: //状态(A-数据有效;V-数据无效,还未定位)
- if (str == "A")
- m_strStatus = "有效数据";
- else if(str == "V")
- m_strStatus = "正在定位...";
- else
- m_strStatus = "非法数据格式";
- break;
- case 3: //纬度(ddmm.mmmm)
- str.Insert(2, "度");
- str += "分";
- m_strLatitude = str;
- break;
- case 4: //纬度指示(N-北纬;S-南纬)
- if (str == "N")
- m_strLatitude.Insert(0, "北纬");
- else
- m_strLatitude.Insert(0, "南纬");
- break;
- case 5: //经度(dddmm.mmmm)
- str.Insert(3, "度");
- str += "分";
- m_strLongitude = str;
- break;
- case 6: //经度指示(E-东经;W-西经)
- if (str == "E")
- m_strLongitude.Insert(0, "东经");
- else
- m_strLongitude.Insert(0, "西经");
- break;
- case 7: //速度(单位:节)
- m_strSpeed = str;
- break;
- case 8: //航向(单位:度)
- m_strCourse = str;
- break;
- case 9: //日期(UTC)
- m_strDate = "";
- m_strDate += "20";
- m_strDate += str[4];
- m_strDate += str[5];
- m_strDate += "-";
- m_strDate += str[2];
- m_strDate += str[3];
- m_strDate += "-";
- m_strDate += str[0];
- m_strDate += str[1];
- break;
- default:
- break;
- }
- }
- }
- }
- else if (strNEMA.Find("$GPGGA",0) == 0)
- {
- }
- else if (strNEMA.Find("$GPGSA",0) == 0)
- {
- }
- else if (strNEMA.Find("$GPGSV",0) == 0)
- {
- }
- else if (strNEMA.Find("$GPGLL",0) == 0)
- {
- }
- else if (strNEMA.Find("$GPVTG",0) == 0)
- {
- }
- else
- return FALSE; //格式错误
- }
- return TRUE;
- }