一、本例程实现功能

通过NEO-6M GPS模块获取当地经纬度、海拔高度、以及获取GPS时间 (UTC)

二、 GPS使用说明

GPS模块默认每秒自动输出一次经纬度、海拔、UTC信息
GPS上电工作后大概需要1~3分钟(时间长短取决于信号好坏)的搜星定位准备工作,此阶段无数据输出
如果希望提高搜星能力或者在室内定位,请将GPS模块的天线换成有源天线
当GPS模块上的LED灯开始每秒闪烁一次时,说明GPS此时有数据正在输出

三、引脚图

四、GPS模块的数据格式

对GPS模块的数据处理本质上还是串口通信程序设计,只是GPS模块的输出遵循固定的格式,通过字符串检索查找即可从模块发送的数据中找出需要的数据,常用的GPS模块大多采用NMEA-0183 协议。NMEA-0183 是美国国家海洋电子协会(National Marine Electronics Association)所指定的标准规格,这一标准制订所有航海电子仪器间的通讯标准,其中包含传输资料的格式以及传输资料的通讯协议。
以下是一组正常的GPS 数据
$GPGGA,082006.000,3852.9276,N,11527.4283,E,1,08,1.0,20.6,M,,,,0000*35
$GPRMC,082006.000,A,3852.9276,N,11527.4283,E,0.00,0.0,261009,,*38
$GPVTG,0.0,T,,M,0.00,N,0.0,K*50
下面分别对每组数据的含义进行分析。

$GPGSA,A,2,01,04,11,17,28,,,,,,,,2.8,2.7,0.9*3C
$GPGSV,3,1,09,01,59,035,53,03,31,127,21,04,30,037,50,06,06,219,33*75
$GPGSV,3,2,09,11,45,032,42,17,24,285,54,19,09,059,35,28,40,334,51*7C
$GPGSV,3,3,09,32,21,084,27*4B
$GPGGA,061102.0,2233.150278,N,11356.386896,E,1,05,2.7,83.5,M,-1.0,M,,*79
$GPVTG,,T,0.0,M,0.0,N,0.0,K,A*0D
$GPRMC,061102.0,A,2233.150278,N,11356.386896,E,0.0,,230715,0.0,E,A*2E

4.1 $GPGGA分析

GPS 固定数据输出语句($GPGGA),这是一帧GPS 定位的主要数据,也是使用最广的数据。为了便于理解,下面举例说明$GPGGA语句各部分的含义。
例:$GPGGA,082006.000,3852.9276,N,11527.4283,E,1,08,1.0,20.6,M,,,,0000*35
其标准格式为:
$GPGGA,(1),(2),(3),(4),(5),(6),(7),(8),(9),M,(10),M,(11),(12)*hh(CR)(LF)
各部分所对应的含义为:
(1) 定位UTC 时间:08 时20 分06 秒
(2) 纬度(格式ddmm.mmmm:即dd 度,mm.mmmm 分);
(3) N/S(北纬或南纬):北纬38 度52.9276 分;
(4) 经度(格式dddmm.mmmm:即ddd 度,mm.mmmm 分);
(5) E/W(东经或西经):东经115 度27.4283 分;
(6) 质量因子(0=没有定位,1=实时GPS,2=差分GPS):1=实时GPS;
(7) 可使用的卫星数(0~8):可使用的卫星数=08;
(8) 水平精度因子(1.0~99.9);水平精度因子=1.0;
(9) 天线高程(海平面,-9999.9~99999.9,单位:m);天线高程=20.6m);
(10) 大地椭球面相对海平面的高度(-999.9~9999.9,单位:m):无;
(11) 差分GPS 数据年龄,实时GPS 时无:无;
(12) 差分基准站号(0000~1023),实时GPS 时无:无;
*总和校验域;hh 总和校验数:35(CR)(LF)回车,换行。

4.2 GPRMC(建议使用最小GPS 数据格式)

$GPRMC,082006.000,A,3852.9276,N,11527.4283,E,0.00,0.0,261009,,*38

$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.(检查位)

4.3 $GPVTG 地面速度信息

例:$GPVTG,0.0,T,,M,0.00,N,0.0,K*50
字段0:$GPVTG,语句ID,表明该语句为Track Made Good and Ground Speed(VTG)地
面速度信息
字段1:运动角度,000 - 359,(前导位数不足则补0)

字段2:T=真北参照系

字段3:运动角度,000 - 359,(前导位数不足则补0)

字段4:M=磁北参照系

字段5:水平运动速度(0.00)(前导位数不足则补0)

字段6:N=节,Knots

字段7:水平运动速度(0.00)(前导位数不足则补0)

字段8:K=公里/时,km/h

字段9:校验值

五、源码获取GPS和时间

char *Start,*End;
char latitude_buf[20];
char longitude_buf[20];
float lat,lon;
char time_buf[20];
/****
*******GPS
*****/
void GPS_function(void)
{
	char i;
	memset(latitude_buf,'-',7);
	memset(longitude_buf,'-',7);
	Start = strstr((char *)uart2_buf, "GLL");
	if(Start != NULL)
	{
		Start = strstr(Start, ",") + 1;        //获取纬度数据首地址
		if(*(Start) != ',')                                                //判断是否获取到经纬度数据
		{
			Start++;                                                                                        //纬度数据首地址
			End = strstr(Start, ",");                        //获取纬度数据尾地址
			for(i=0; i<End - Start; i++)
			{
				latitude_buf[i+1] = *(Start + i-1);        //将纬度数据存放在数组中
				if(*(Start + i-1) == '.')
				{
					latitude_buf[i+1] = latitude_buf[i];
					latitude_buf[i] = latitude_buf[i-1];
					latitude_buf[i-1] = '.';
				}
			}
			Start = strstr(Start, ",") + 1;        //获取南纬或北纬数据
			if(*Start=='N' || *Start=='S')
				latitude_buf[0] = *Start;                        //将数据存放在纬度数组

			Start = strstr(Start, ",") + 1;        //获取经度数据首地址
			End = strstr(Start, ",");                                //获取经度数据尾地址
			for(i=0; i<End - Start; i++)
			{
				longitude_buf[i+1] = *(Start + i);        //将经度数据存放在数组中
				if(*(Start + i) == '.')
				{
					longitude_buf[i+1] = longitude_buf[i];
					longitude_buf[i] = longitude_buf[i-1];
					longitude_buf[i-1] = '.';
				}
			}
			Start = strstr(Start, ",") + 1;        //获取东经或西经数据
			if(*Start=='E' || *Start=='W')
			longitude_buf[0] = *Start;                //将数据存放在经度数组中

			latitude_buf[7] = '\0';                        //只让经度和纬度显示十个字符
			longitude_buf[7] = '\0';

			lat = atof((char *)latitude_buf+1);                //字符串转换为浮点型变量
			lon = atof((char *)longitude_buf+1);                //字符串转换为浮点型变量
      
      Start = strstr(Start, ",") + 1;        //获取经度数据首地址
			End = strstr(Start, ",");                                //获取经度数据尾地址
			for(i=0; i<End - Start; i++)
			{
				time_buf[i+1] = *(Start + i);        //将经度数据存放在数组中
			}
			time_buf[0] = 'T';                //将数据存放在经度数组中
			time_buf[7] = '\0';                        //只让经度和纬度显示十个字符
      
      
      hour=(time_buf[1]-'0')*10+(time_buf[2]-'0');
      if(hour+8>=24)
        hour=hour+8-24;
      else
        hour=hour+8;
      minute=(time_buf[3]-'0')*10+(time_buf[4]-'0');
      sec=(time_buf[5]-'0')*10+(time_buf[6]-'0');
		}
	}
}

六、串口配置

1、变量定义

//串口2的数据获取
uint8_t uart2_value;      //串口传的单个数据
//串口的储存数组,串口的接收时间,串口存值的数量
uint8_t uart2_buf[256],uart2_time,uart2_num;
uint8_t uart2_rx_flag;//串口的获取值的标志位

2、串口初始化(可以用STM32cubeMX配置,波特率9600,需要开接收中断)

void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 9600;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

3、串口回调函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        if(huart->Instance == huart2.Instance)//串口2触发中断
	{
    //获取串口2的数据,uart2_value
		HAL_UART_Receive_IT(&huart2, &uart2_value, 1);
    //将数据存储到uart2_buf中
		uart2_buf[uart2_num++] = uart2_value;
		uart2_time = 0;
	}
}

七、坐标系转换(需注意):

由于定位模块设备输出的经纬度定位信息的坐标系为WGS84国际标准,所以在不同地图中需要转换成对应的坐标系。

例如使用百度地图时,需要将WGS84坐标系转换为BD09坐标系;

用国内其他地图时,需要将WGS84坐标系转换为GCJ-02坐标系。

如果不进行这些转换会出现定位偏差多则一两公里的问题。

开发者可以使用 https://tool.lu/coordinate/ 这个网络在线工具做一个简单的验证。

发表回复

后才能评论