当前位置: 首页 > article >正文

STM32传感器系列:GPS定位模块

简介

我们在做一些项目的时候,可能需要使用到GPS模块,我们可以通过这个模块获得当前的位置以及时间,我这里就教大家如何去使用GPS定位模块,并且把示例代码开源到评论区下面,有需要自取即可,我我这里用到的是GPS NEO-6M模块搭配吸盘天线或者陶瓷天线。

实验所需材料

一块 STM32F103C8T6 小系统板、一个下载器、一个 4针 I2C 通讯的 OLED 液晶、一个GPS 驱动板、一套吸盘天线套装(吸盘天线可以搁置在窗户外无遮挡的地方)或陶瓷天线(陶瓷天线必须户外空旷地实验)、一个面包板、若干杜邦线。

实验步骤

1、通过 STLINK 下载器给小系统板烧录我开源的GPS示例代码。

2、拔掉小系统板上连接的 STLINK 杜邦线,用 4根杜邦线连接系统板和 OLED 液晶屏,用 4 根杜邦线连接系统板和 GPS 模块。

最小系统板和 OLED 液晶屏的接线方式:

VCC5V/3.3V
GNDGND
SCLPB12
SDAPB13

 最小系统板和 GPS 模块的接线方式:

VCC5V
GNDGND
RXPA2
TXPA

3、连接好后,用 USB 数据线给开发板上电 

4、可以看到 OLED 液晶屏幕显示“爱学电子的刻刻帝”以及“模块同步中“。

5、等有信号后,GPS 模块上的 LED 灯会闪烁,获取到数据后,OLED 液晶屏幕上会显示 GPS 的经纬度以及时间会按北京时间走动。

模块介绍 

引脚介绍

其中,PPS引脚同时连接到了模块自带了的状态指示灯:PPS,该引脚连接在UBLOX NEO-6M模组的TIMEPULSE端口,该端口的输出特性可以通过程序设置。PPS指示灯(即PPS引脚),在默认条件下(没经过程序设置),有2个状态:

1, 常亮,表示模块已开始工作,但还未实现定位。

2, 闪烁(100ms灭,900ms亮),表示模块已经定位成功。

指令解析 

NMEA-0183 协议简介:

NMEA 0183是美国国家海洋电子协会(National Marine Electronics Association)为海用电子设备
制定的标准格式。目前业已成了GPS导航设备统一的RTCM标准协议。NMEA-0183协议采用ASCII码来传递GPS定位信息,我们称之为帧。帧格式形如:$aaccc,ddd,ddd,…,ddd*hh(CR)(LF)
1、“$”:帧命令起始位
2、aaccc:地址域,前两位为识别符(aa),后三位为语句名(ccc)
3、ddd…ddd:数据
4、“*”:校验和前缀(也可以作为语句数据结束的标志)
5、hh:校验和(check sum),$与*之间所有字符ASCII码的校验和(各字节做异或运算,得到
校验和后,再转换16进制格式的ASCII字符)
6、(CR)(LF):帧结束,回车和换行符

 

UTC 时间即协调世界时,相当于本初子午线(0 度经线)上的时间,北京时间比 UTC 8 个小时。  

指令讲解 

1,$GPGGA(GPS定位信息,Global Positioning System Fix Data)
$GPGGA语句的基本格式如下(其中M指单位M,hh指校验和,CR和LF代表回车换行,下同):
$GPGGA,(1),(2),(3),(4),(5),(6),(7),(8),(9),M,(10),M,(11),(12)*hh(CR)(LF)
(1)UTC时间,格式为hhmmss.ss;
(2)纬度,格式为ddmm.mmmmm(度分格式);
(3)纬度半球,N或S(北纬或南纬);
(4)经度,格式为dddmm.mmmmm(度分格式);
(5)经度半球,E或W(东经或西经);
(6)GPS状态,0=未定位,1=非差分定位,2=差分定位;
(7)正在使用的用于定位的卫星数量(00~12)
(8)HDOP水平精确度因子(0.5~99.9)
(9)海拔高度(-9999.9到9999.9米)
(10)大地水准面高度(-9999.9到9999.9米)
(11)差分时间(从最近一次接收到差分信号开始的秒数,非差分定位,此项为空)
(12)差分参考基站标号(0000到1023,首位0也将传送,非差分定位,此项为空)
举例如下:
$GPGGA,023543.00,2308.28715,N,11322.09875,E,1,06,1.49,41.6,M,-5.3,M,,*7D
2,$GPGSA(当前卫星信息)
$GPGSA语句的基本格式如下:
$GPGSA,(1),(2),(3),(3),(3),(3),(3),(3),(3),(3),(3),(3),(3),(3),(4),(5),(6)*hh(CR)(LF)
(1) 模式,M = 手动,A = 自动。
(2) 定位类型,1=未定位,2=2D定位,3=3D定位。
(3) 正在用于定位的卫星号(01~32)
(4) PDOP综合位置精度因子(0.5-99.9)
(5) HDOP水平精度因子1(0.5-99.9)
(6) VDOP垂直精度因子(0.5-99.9)
举例如下:
$GPGSA,A,3,26,02,05,29,15,21,,,,,,,2.45,1.49,1.94*0E
注1:精度因子值越小,则准确度越高。
3,$GPGSV(可见卫星数,GPS Satellites in View)
$GPGSV语句的基本格式如下:
$GPGSV, (1),(2),(3),(4),(5),(6),(7),...,(4),(5),(6),(7)*hh(CR)(LF)
(1) GSV语句总数。
(2) 本句GSV的编号。
(3) 可见卫星的总数(00~12,前面的0也将被传输)。
(4) 卫星编号(01~32,前面的0也将被传输)。
(5) 卫星仰角(00~90度,前面的0也将被传输)。
(6) 卫星方位角(000~359度,前面的0也将被传输)
(7) 信噪比(00~99dB,没有跟踪到卫星时为空)。
注:每条GSV语句最多包括四颗卫星的信息,其他卫星的信息将在下一条$GPGSV语句中输出。
举例如下:
$GPGSV,3,1,12,02,39,117,25,04,02,127,,05,40,036,24,08,10,052,*7E
$GPGSV,3,2,12,09,35,133,,10,01,073,,15,72,240,22,18,05,274,*7B
$GPGSV,3,3,12,21,10,316,31,24,16,176,,26,65,035,42,29,46,277,18*7A
4,$GPRMC(推荐定位信息,Recommended Minimum Specific GPS/Transit Data)
$GPRMC语句的基本格式如下:
$GPRMC,(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)*hh(CR)(LF)
(1) UTC时间,hhmmss(时分秒)
(2) 定位状态,A=有效定位,V=无效定位
(3) 纬度ddmm.mmmmm(度分)
(4) 纬度半球N(北半球)或S(南半球)
(5) 经度dddmm.mmmmm(度分)
(6) 经度半球E(东经)或W(西经)
(7) 地面速率(000.0~999.9节)
(8) 地面航向(000.0~359.9度,以真北方为参考基准)
(9) UTC日期,ddmmyy(日月年)
(10)磁偏角(000.0~180.0度,前导位数不足则补0)
(11) 磁偏角方向,E(东)或W(西)
(12) 模式指示(A=自主定位,D=差分,E=估算,N=数据无效)
举例如下:
$GPRMC,023543.00,A,2308.28715,N,11322.09875,E,0.195,,240213,,,A*78
5,$GPVTG(地面速度信息,Track Made Good and Ground Speed)
$GPVTG语句的基本格式如下:
$GPVTG,(1),T,(2),M,(3),N,(4),K,(5)*hh(CR)(LF)
(1) 以真北为参考基准的地面航向(000~359度,前面的0也将被传输)
(2) 以磁北为参考基准的地面航向(000~359度,前面的0也将被传输)
(3) 地面速率(000.0~999.9节,前面的0也将被传输)
(4) 地面速率(0000.0~1851.8公里/小时,前面的0也将被传输)
(5) 模式指示(A=自主定位,D=差分,E=估算,N=数据无效)
举例如下:
$GPVTG,,T,,M,0.195,N,0.361,K,A*2A
6,$GPGLL(定位地理信息,Geographic Position)
$GPGLL语句的基本格式如下:
$GPGLL,(1),(2),(3),(4),(5),(6),(7)*hh(CR)(LF)
(1) 纬度ddmm.mmmmm(度分)
(2) 纬度半球N(北半球)或S(南半球)
(3) 经度dddmm.mmmmm(度分)
(4) 经度半球E(东经)或W(西经)
(5) UTC时间:hhmmss(时分秒)
(6) 定位状态,A=有效定位,V=无效定位
(7) 模式指示(A=自主定位,D=差分,E=估算,N=数据无效)
举例如下:
$GPGLL,2308.28715,N,11322.09875,E,023543.00,A,A*6A
7,$GPZDA(当前时间信息)
$GPZDA语句的基本格式如下:
$GPZDA,(1),(2),(3),(4),(5),(6)*hh(CR)(LF)
(1) UTC时间:hhmmss(时分秒)
(2) 日
(3) 月
(4) 年
(5) 本地区域小时(NEO-6M未用到,为00)
(6) 本地区域分钟(NEO-6M未用到,为00)
举例如下:
$GPZDA,082710.00,16,09,2002,00,00*64
NMEA-0183协议命令帧部分就介绍到这里,接下来我们看看NMEA-0183协议的校验,通过前面
的介绍,我们知道每一帧最后都有一个hh的校验和,该校验和是通过计算$与*之间所有字符
ASCII码的异或运算得到,将得到的结果以ASCII字符表示就是该校验(hh)。
例如语句:$GPZDA,082710.00,16,09,2002,00,00*64,校验和(红色部分参与计算)计算方法为:
0X47xor 0X50xor 0X5Axor 0X44xor 0X41xor 0X2Cxor 0X30xor 0X38xor 0X32xor 0X37xor 
0X31xor 0X30xor 0X2Exor 0X30xor 0X30xor 0X2Cxor 0X31xor 0X36xor 0X2Cxor 0X30xor 
0X39xor 0X2Cxor 0X32xor 0X30xor 0X30xor 0X32xor 0X2Cxor 0X30xor 0X30xor 0X2Cxor 
0X30xor 0X30
得到的结果就是0X64,用ASCII表示就是64。
NMEA-0183协议我们就介绍到这里,了解了该协议,我们就可以编写单片机代码,解析
NMEA-0183数据,从而得到GPS定位的各种信息了。

程序设计 

串口初始化程序

这里我们用到了串口2,我们初始化串口2。

void USART_Config_Init(void)
{
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 38400;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(USART2, &USART_InitStructure);
	/* Enable USARTy Receive  interrupts */
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
	USART_ITConfig(USART2,USART_IT_IDLE,ENABLE);//使能空闲中断
	/* Enable the USART2 */
	USART_Cmd(USART2, ENABLE);
	delay_ms(10);//等待10ms
}

串口2接收中断回调函数

void USART2_IRQHandler(void)
{
	uint8_t temp;
	if(USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)
	{	   //防止溢出中断
		USART_ReceiveData(USART2); 
	}   

	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
	{		//USART接收中断
        temp = USART_ReceiveData(USART2);
		if(rx_index > RXBUFF_SIZE)
		{		   //溢出不再接收数据
			return;
		}
		aRxBuffer[rx_index++] = temp;
	}
	if(USART_GetFlagStatus(USART2, USART_FLAG_IDLE) != RESET)
	{		//USART空闲中断
		USART_ReceiveData(USART2);
		RX_len=rx_index;
		memcpy(USART2_RX_BUF,aRxBuffer,RX_len);//把缓冲区的数据,放入需要解析的数组
		rx_index=0;
	}

}

 GPS模块初始化

//配置UBLOX NEO-6的更新速率	    
//measrate:测量时间间隔,单位为ms,最少不能小于200ms(5Hz)
//reftime:参考时间,0=UTC Time;1=GPS Time(一般设置为1)
//返回值:0,发送成功;其他,发送失败.
uint8_t Ublox_Cfg_Rate(uint16_t measrate,uint8_t reftime)
{
	_ublox_cfg_rate *cfg_rate=(_ublox_cfg_rate *)USART2_TX_BUF;
 	if(measrate<200)return 1;	//小于200ms,直接退出
 	cfg_rate->header=0X62B5;	//cfg header
	cfg_rate->id=0X0806;	 	//cfg rate id
	cfg_rate->dlength=6;	 	//数据区长度为6个字节.
	cfg_rate->measrate=measrate;//脉冲间隔,us
	cfg_rate->navrate=1;		//导航速率(周期),固定为1
	cfg_rate->timeref=reftime; 	//参考时间为GPS时间
	Ublox_CheckSum((uint8_t*)(&cfg_rate->id),sizeof(_ublox_cfg_rate)-4,&cfg_rate->cka,&cfg_rate->ckb);
	HAL_UART_Transmit(USART2, (uint8_t *)&USART2_TX_BUF, sizeof(_ublox_cfg_rate));
	return Ublox_Cfg_Ack_Check();
}

解析GPS接收到的信息 

//NMEA 0183 协议解析后数据存放结构体
__packed typedef struct  
{										    
 	uint8_t svnum;					//可见卫星数
	nmea_slmsg slmsg[12];		//最多12颗卫星
	nmea_utc_time utc;			//UTC时间
	uint32_t latitude;				//纬度 分扩大100000倍,实际要除以100000
	uint8_t nshemi;					//北纬/南纬,N:北纬;S:南纬				  
	uint32_t longitude;			    //经度 分扩大100000倍,实际要除以100000
	uint8_t ewhemi;					//东经/西经,E:东经;W:西经
	uint8_t gpssta;					//GPS状态:0,未定位;1,非差分定位;2,差分定位;6,正在估算.				  
 	uint8_t posslnum;				//用于定位的卫星数,0~12.
 	uint8_t possl[12];				//用于定位的卫星编号
	uint8_t fixmode;					//定位类型:1,没有定位;2,2D定位;3,3D定位
	uint16_t pdop;					//位置精度因子 0~500,对应实际值0~50.0
	uint16_t hdop;					//水平精度因子 0~500,对应实际值0~50.0
	uint16_t vdop;					//垂直精度因子 0~500,对应实际值0~50.0 

	int altitude;			 	//海拔高度,放大了10倍,实际除以10.单位:0.1m	 
	uint16_t speed;					//地面速率,放大了1000倍,实际除以10.单位:0.001公里/小时	 
}nmea_msg; 

//提取NMEA-0183信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void GPS_Analysis(nmea_msg *gpsx,uint8_t *buf)
{
	NMEA_GPGSV_Analysis(gpsx,buf);	//GPGSV解析
	NMEA_GPGGA_Analysis(gpsx,buf);	//GPGGA解析 	
	NMEA_GPGSA_Analysis(gpsx,buf);	//GPGSA解析
	NMEA_GPRMC_Analysis(gpsx,buf);	//GPRMC解析
	NMEA_GPVTG_Analysis(gpsx,buf);	//GPVTG解析
}

 显示GPS解析到的数据

//显示GPS定位信息 
void Gps_Msg_Show(void)
{
 	float tp;		   
 	 
	tp=gpsx.longitude;	   
	sprintf((char *)dtbuf,":%.5f %1c",tp/=100000,gpsx.ewhemi);	//得到经度字符串
	OLED_ShowF16x16(2,1,13);//经
	OLED_ShowF16x16(2,3,14);//度
	OLED_ShowString(2,5,(char *)dtbuf);
	tp=gpsx.latitude;	   
	sprintf((char *)dtbuf,":%.5f %1c",tp/=100000,gpsx.nshemi);	//得到纬度字符串
	OLED_ShowF16x16(3,1,15);//纬
	OLED_ShowF16x16(3,3,16);//度
	OLED_ShowString(3,5,(char *)dtbuf); 	 
	 				    
	if(gpsx.fixmode<=3)														//定位状态
	{  
		gpsx.utc.hour = gpsx.utc.hour + 8; //已知的UTC时间,转换成北京时间,差8小时
		if(gpsx.utc.hour>=24)
		{
		gpsx.utc.hour-=24;
		}

		sprintf((char *)dtbuf,":%02d:%02d:%02d",gpsx.utc.hour,gpsx.utc.min,gpsx.utc.sec);	//显示北京时间
		OLED_ShowF16x16(4,1,17);//时
		OLED_ShowF16x16(4,3,18);//间
		OLED_ShowString(4,5,(char *)dtbuf); 	
	}
  
}	 

完整的工程代码 

通过网盘分享的文件:实时显示当前位置GPS信息.zip
链接: https://pan.baidu.com/s/1rIcEV_G6ukU4uVn44VBgMA?pwd=grtu 提取码: grtu


http://www.kler.cn/a/465237.html

相关文章:

  • MetaGPT - 多Agent框架
  • Mac M2基于MySQL 8.4.3搭建(伪)主从集群
  • YIG带通滤波器
  • 《GICv3_Software_Overview_Official_Release_B》学习笔记
  • 遇到复杂的 递归查询sql 需要oracle 转pgsql 可以把数据表结构给ai
  • 服务器迁移中心——“工作组迁移”使用指南
  • 活动预告 |【Part1】Microsoft Azure 在线技术公开课:使用 Azure DevOps 和 GitHub 加速开发
  • spring中使用@Validated,什么是JSR 303数据校验,spring boot中怎么使用数据校验
  • 【行空板K10】MQTT服务器SIoT V2
  • LeetCode - 初级算法 数组(旋转数组)
  • Vue.js组件开发-如何动态设置下拉框数值
  • 使用Python和OpenCV进行视觉图像分割
  • ASP.NET CORE 依赖注入的三种方式,分别是什么,使用场景
  • GitLab集成Runner详细版--及注意事项汇总【最佳实践】
  • vue + iview inputNumber最大最小值限制问题
  • windows remote desktop service 远程桌面RDS授权激活
  • 智能水文:ChatGPT等大语言模型如何提升水资源分析和模型优化的效率
  • 121.【C语言】数据结构之快速排序(未优化的Hoare排序存在的问题)以及时间复杂度的分析
  • mysql删除无用用户
  • 航电系统之行走避障功能篇
  • AI知识库与用户行为分析:优化用户体验的深度洞察
  • JMeter 的 If Controller:开启性能测试的智能大门
  • 《Vue3实战教程》32:Vue3工具链
  • 《从入门到精通:蓝桥杯编程大赛知识点全攻略》(一)-递归实现指数型枚举、递归实现排列型枚举
  • 数据挖掘——概论
  • Mono里运行C#脚本20—mono_assembly_load_corlib