STM32传感器模块编程实践(五) NEO-6M GPS定位模块简介及驱动源码

文章目录

一.概要

NEO-6M GPS模块是由ublox公司生产的一款GPS定位模块,具有高灵敏度、低功耗、小型化高追踪灵敏度,大大扩大了其定位的覆盖面,在普通GPS接收模块不能定位的地方,如狭窄都市天空下、密集的丛林环境,NEO-6M都能高精度定位。模块的高灵敏度、小静态漂移、低功耗及轻巧的体积,适用于车载、手持设备如PDA,车辆监控、手机、摄像机及其他移动定位系统的应用,是GPS产品应用的好选择。

二.NEO-6M GPS模块主要技术指标

1.模块采用U-BLOX NEO-6M模组,体积小巧,性能优异。

2.模块增加放大电路,有利于快速搜星,可以安装GPS外置天线比如陶瓷天线或者胶棒天线。

3.模块可通过串口进行各种参数设置,并可保存在EEPROM,使用方便。

4.模块自带SMA接口,可以连接各种有源天线,适应能力强。

5.模块兼容3.3V/5V电平,方便连接各种单片机系统。

6.模块自带可充电后备电池,可以掉电保持星历数据。

7.跟踪灵敏度 --162dBm ,冷启动灵敏度--148 dBm。(跟踪灵敏度是GPS接收机在捕获到卫星信号之后,能够导航的最低信号强度;冷启动灵敏度是设备从完全没有信号状态到成功捕获到至少一颗卫星信号所需的最低信号强度)

8.冷启动时间29秒。

9.定位精度:2.5m。

10.工作温度范围:--40° C 至 85° C。

11.模块尺寸25mm*35mm。

12.安装孔径3mm。

三.GPS模块参考原理图

NEO-6M GPS模块参考原理图如下,有些模块引出了PPS输出,P1接插件就会有5针,有些没引出PPS输出就只有4针。

四.NEO-6M GPS模块接线说明

模块如图所示:

模块插针信号定义:

NEO-6M GPS模块与单片机只要4根线就能连接

单片机开发板 GPS模块

3.3V-----------------------VCC

GND----------------------GND

PA2-----------------------RX

PA3-----------------------TX

五.NEO-6M GPS模块通讯协议介绍(NMEA-0183)

串口通讯参数:9600波特率,8位数据,1位停止位,无校验,由于9600波特率比较慢,我们一般会改成38400波特率进行通讯。

NEO-6M GPS模块通过串口输出 GPS 定位数据信息,这些信息默认采用NMEA-0183协议,协议简介如下:

NMEA 0183是美国国家海洋电子协会(National Marine Electronics Association)为海用电子设备

制定的标准格式。目前业已成了GPS导航设备统一的RTCM(Radio Technical Commission for

Maritime services)标准协议。

NMEA-0183协议采用ASCII码来传递GPS定位信息,我们称之为帧。

帧格式形如: a a c c c , d d d , d d d , ... , d d d ∗ h h ( C R ) ( L F ) 1 、" aaccc,ddd,ddd,...,ddd*hh(CR)(LF) 1、" 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个小时。

我们以常用的经纬度数据读取为例

$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=数据无效)

举例如下:

收到ASCII报文$GPRMC,023543.00,A,2308.28715,N,11322.09875,E,0.195,240213,A*78

根据解析经纬度就是北纬23度08分17.2秒,东经113度22分5.9秒

协议解析代码:

c 复制代码
//分析GPRMC信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GPRMC_Analysis(nmea_msg *gpsx,uint8_t *buf)
{
	uint8_t *p1,dx;			 
	uint8_t posx;     
	uint32_t temp;	   
	float rs;  
	p1=(uint8_t*)strstr((const char *)buf,"GPRMC");//"$GPRMC",经常有&和GPRMC分开的情况,故只判断GPRMC.
	posx=NMEA_Comma_Pos(p1,1);								//得到UTC时间
	if(posx!=0XFF)
	{
		temp=NMEA_Str2num(p1+posx,&dx)/NMEA_Pow(10,dx);	 	//得到UTC时间,去掉ms
		gpsx->utc.hour=temp/10000;
		gpsx->utc.min=(temp/100)%100;
		gpsx->utc.sec=temp%100;	 	 
	}	
	posx=NMEA_Comma_Pos(p1,3);								//得到纬度
	if(posx!=0XFF)
	{
		temp=NMEA_Str2num(p1+posx,&dx);		 	 
		gpsx->latitude=temp/NMEA_Pow(10,dx+2);	//得到°
		rs=temp%NMEA_Pow(10,dx+2);				//得到'		 
		gpsx->latitude=gpsx->latitude*NMEA_Pow(10,5)+(rs*NMEA_Pow(10,5-dx))/60;//转换为° 
	}
	posx=NMEA_Comma_Pos(p1,4);								//南纬还是北纬 
	if(posx!=0XFF)gpsx->nshemi=*(p1+posx);					 
 	posx=NMEA_Comma_Pos(p1,5);								//得到经度
	if(posx!=0XFF)
	{												  
		temp=NMEA_Str2num(p1+posx,&dx);		 	 
		gpsx->longitude=temp/NMEA_Pow(10,dx+2);	//得到°
		rs=temp%NMEA_Pow(10,dx+2);				//得到'		 
		gpsx->longitude=gpsx->longitude*NMEA_Pow(10,5)+(rs*NMEA_Pow(10,5-dx))/60;//转换为° 
	}
	posx=NMEA_Comma_Pos(p1,6);								//东经还是西经
	if(posx!=0XFF)gpsx->ewhemi=*(p1+posx);		 
	posx=NMEA_Comma_Pos(p1,9);								//得到UTC日期
	if(posx!=0XFF)
	{
		temp=NMEA_Str2num(p1+posx,&dx);		 				//得到UTC日期
		gpsx->utc.date=temp/10000;
		gpsx->utc.month=(temp/100)%100;
		gpsx->utc.year=2000+temp%100;	 	 
	} 
}

六.NEO-6M GPS模块操作流程

连接GPS模块‌:使用USB-TTL工具或者单片机与GPS模块连接,确保VCC和GND引脚正确对接,TXD和RXD引脚也需要正确连接。

‌配置GPS模块‌:通过编程设置GPS模块的工作模式,例如每秒自动输出一次经纬度、海拔和UTC时间。

‌读取数据‌:编写程序读取GPS模块输出的NMEA-0183协议数据。程序需要解析这些数据,提取出经纬度、海拔高度和UTC时间等信息‌。

‌数据处理与展示‌:将解析出的数据通过串口调试终端或通过LCD显示屏显示经纬度、海拔和UTC时间等信息‌。

‌注意事项‌:

GPS模块上电后需要1到3分钟进行搜星定位,具体时间取决于信号强度和环境‌,比如雨雪天气或者天上云层较厚的情况时间下会长一些。

GPS天线需要放在室外露天无遮挡环境,在信号较弱的环境中,可能需要更换有源天线以提高定位速度和准确性‌。

确保编程时正确使用NMEA 0183协议的帧格式,正确解析数据‌。

七.STM32单片机与NEO-6M GPS模块通讯实验

1.硬件准备

STLINK接STM32F103C8T6开发板,STLINK接电脑USB口。

GPS模块与单片机开发板接线:

开发板3.3V         <->模块VCC
开发板PA2脚        <->模块RX
开发板PA3脚        <->模块TX
开发板GND          <->模块GND 

2.软件工程

打开STM32CubeMX软件,新建工程

Part Number处输入STM32F103C8,再双击就创建新的工程

配置下载口引脚

配置外部晶振引脚

配置系统主频

配置串口2,38400波特率,8位数据,1位停止位,无校验

串口2中断使能

配置工程文件名,保存路径,KEIL5工程输出方式

生成工程

用Keil5打开工程

添加代码


3.软件主要代码

串口数据接收相关代码

c 复制代码
//串口接收缓存区 	
uint8_t USART2_RX_BUF[USART_MAX_RECV_LEN]; 				    //接收缓冲,最大USART_MAX_RECV_LEN个字节.
volatile uint8_t UartRxData;
uint8_t UartTxbuf[1000]={1,2,3,4,5,6,7,8,9,10};
uint8_t UartRxbuf[1024],UartIntRxbuf[1024];
uint16_t UartRxIndex=0,UartRxFlag,UartRxLen=0,UartRxTimer,UartRxOKFlag,UartIntRxLen;

//串口清除
uint8_t UartRecv_Clear(void)
{
	UartRxOKFlag=0;
	UartRxLen=0;
	UartIntRxLen=0;
	UartRxIndex=0;
	return 1;
}

//接收标志函数,返回0说明没收据接收,返回1说明有数据收到
uint8_t Uart_RecvFlag(void)
{
		if(UartRxOKFlag==0x55)
		{
			UartRxOKFlag=0;
			UartRxLen=UartIntRxLen;
			memcpy(USART2_RX_BUF,UartIntRxbuf,UartIntRxLen);//把缓冲区的数据,放入需要解析的数组
			UartIntRxLen=0;
			return 1;
		}
		return 0;
}
//串口2在1字节接收完成回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	
	if(huart==&huart2)//判断是否串口2
	{
		UartRxFlag=0x55;//接收标志置位
		UartIntRxbuf[UartRxIndex]=UartRxData;//数据写入缓冲区
		UartRxIndex++;//记载数目加1
		if(UartRxIndex>=1024)//缓冲区是1024字节,如果存满,归零
		{
			UartRxIndex=0;
		}
		HAL_UART_Receive_IT(&huart2,(unsigned char*)&UartRxData,1);//继续接收下一字节
 }

}

//1ms调用一次,用来判断是否收完一帧
void UART_RecvDealwith(void)
{
	if(UartRxFlag==0x55)
	{
		if(UartIntRxLen<UartRxIndex)//UartIntRxLen小于UartRxIndex,说明有收到新的数据,把接收长度增加
		{
		UartIntRxLen=UartRxIndex;
		}else
		{
			UartRxTimer++;
			if(UartRxTimer>=50)//50ms,等待,没收到新数据,说明已经收完一帧
			{
				UartRxTimer=0;
				UartRxFlag=0;
				UartRxOKFlag=0x55;
				UartRxIndex=0;
			}
		}
	}
}
  

main函数代码

c 复制代码
int main(void)
{
  /* USER CODE BEGIN 1 */
	uint8_t key=0XFF;

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();//8M外部晶振,72M系统主频

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();//GPIO时钟初始化
  MX_USART2_UART_Init();//初始化串口2,38400波特率,8位数据,无校验,1位停止,  PA2->USART2_TX,PA3->USART2_RX
  /* USER CODE BEGIN 2 */
	HAL_UART_Receive_IT(&huart2, (uint8_t *)&UartRxData, 1);//接收中断使能
	OLED_Init();//OLED初始化  
	OLED_Clear();//清屏
  /* USER CODE END 2 */
	if(Ublox_Cfg_Rate(1000,1)!=0)	//设置定位信息更新速度为1000ms,顺便判断GPS模块是否在位. 
	{
  
		while((Ublox_Cfg_Rate(1000,1)!=0)&& key)	//持续判断,直到可以检查到NEO-6M,且数据保存成功,如果时初次上电使用,先用9600波特率再重新配置
		{
			huart2.Init.BaudRate = 9600;//初始化串口2波特率为9600(EEPROM没有保存数据的时候,波特率为9600.)
			if (HAL_UART_Init(&huart2) != HAL_OK)//重新初始化串口
			{
			Error_Handler();
			}
	  	Ublox_Cfg_Prt(38400);			//重新设置模块的波特率为38400
			Ublox_Cfg_Tp(1000000,100000,1);	//设置PPS为1秒钟输出1次,脉冲宽度为100ms	    
			key=Ublox_Cfg_Cfg_Save();		//保存配置  
		}	  					 
		HAL_Delay(500);//等待500ms
	
	}
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		OLED_Clear();//清屏
		OLED_ShowCHinese(18,0,0);//光
		OLED_ShowCHinese(36,0,1);//子
		OLED_ShowCHinese(54,0,2);//物
		OLED_ShowCHinese(72,0,3);//联
		OLED_ShowCHinese(90,0,4);//网
		GpsDataRead();//读取经纬度,时间信息,并在液晶上显示
		HAL_Delay(800);//等待800ms
  }
  /* USER CODE END 3 */
}

GPS数据解析相关

c 复制代码
void GpsDataRead(void)
{
		uint16_t i,rxlen;
		if(Uart_RecvFlag())
		{
			if(UartRxLen)
			{
			rxlen=UartRxLen;
			for(i=0;i<rxlen;i++)USART2_TX_BUF[i]=USART2_RX_BUF[i];	   
			USART2_TX_BUF[i]=0;			//自动添加结束符
			GPS_Analysis(&gpsx,(uint8_t*)USART2_TX_BUF);//分析字符串,数据存入GPS结构体
			Gps_Msg_Show();				//显示经纬度,时间信息	
			UartRecv_Clear();//串口数据清0
			}
		}
}

//提取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解析
}
//分析GPRMC信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GPRMC_Analysis(nmea_msg *gpsx,uint8_t *buf)
{
	uint8_t *p1,dx;			 
	uint8_t posx;     
	uint32_t temp;	   
	float rs;  
	p1=(uint8_t*)strstr((const char *)buf,"GPRMC");//"$GPRMC",经常有&和GPRMC分开的情况,故只判断GPRMC.
	posx=NMEA_Comma_Pos(p1,1);								//得到UTC时间
	if(posx!=0XFF)
	{
		temp=NMEA_Str2num(p1+posx,&dx)/NMEA_Pow(10,dx);	 	//得到UTC时间,去掉ms
		gpsx->utc.hour=temp/10000;
		gpsx->utc.min=(temp/100)%100;
		gpsx->utc.sec=temp%100;	 	 
	}	
	posx=NMEA_Comma_Pos(p1,3);								//得到纬度
	if(posx!=0XFF)
	{
		temp=NMEA_Str2num(p1+posx,&dx);		 	 
		gpsx->latitude=temp/NMEA_Pow(10,dx+2);	//得到°
		rs=temp%NMEA_Pow(10,dx+2);				//得到'		 
		gpsx->latitude=gpsx->latitude*NMEA_Pow(10,5)+(rs*NMEA_Pow(10,5-dx))/60;//转换为° 
	}
	posx=NMEA_Comma_Pos(p1,4);								//南纬还是北纬 
	if(posx!=0XFF)gpsx->nshemi=*(p1+posx);					 
 	posx=NMEA_Comma_Pos(p1,5);								//得到经度
	if(posx!=0XFF)
	{												  
		temp=NMEA_Str2num(p1+posx,&dx);		 	 
		gpsx->longitude=temp/NMEA_Pow(10,dx+2);	//得到°
		rs=temp%NMEA_Pow(10,dx+2);				//得到'		 
		gpsx->longitude=gpsx->longitude*NMEA_Pow(10,5)+(rs*NMEA_Pow(10,5-dx))/60;//转换为° 
	}
	posx=NMEA_Comma_Pos(p1,6);								//东经还是西经
	if(posx!=0XFF)gpsx->ewhemi=*(p1+posx);		 
	posx=NMEA_Comma_Pos(p1,9);								//得到UTC日期
	if(posx!=0XFF)
	{
		temp=NMEA_Str2num(p1+posx,&dx);		 				//得到UTC日期
		gpsx->utc.date=temp/10000;
		gpsx->utc.month=(temp/100)%100;
		gpsx->utc.year=2000+temp%100;	 	 
	} 
}
//显示GPS定位信息 
void Gps_Msg_Show(void)
{
 	float tp;		   
 	 
	tp=gpsx.longitude;	   
	sprintf((char *)dtbuf,":%.5f %1c",tp/=100000,gpsx.ewhemi);	//得到经度字符串
	OLED_ShowCHinese(0,2,5);//经
	OLED_ShowCHinese(16,2,7);//度
	OLED_ShowString(32,2,dtbuf);
	tp=gpsx.latitude;	   
	sprintf((char *)dtbuf,":%.5f %1c",tp/=100000,gpsx.nshemi);	//得到纬度字符串
	OLED_ShowCHinese(0,4,6);//纬
	OLED_ShowCHinese(16,4,7);//度
	OLED_ShowString(32,4,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_ShowCHinese(0,6,8);//时
		OLED_ShowCHinese(16,6,9);//间
		OLED_ShowString(32,6,dtbuf); 	
	}
  
}	 

4.实验效果

显示经度,纬度以及时间,时间会走秒。

八.视频演示效果及操作说明

bilibili视频链接地址

九.小结

GPS模块,也称为全球定位系统模块,是一种用于定位、导航和追踪的电子设备。它可以通过接收来自地球上的多个GPS卫星信号来确定用户的具体位置。这类模块广泛应用于个人定位、汽车导航、轨迹追踪等领域,学好了GPS模块,能应用到更多的嵌入式开发中。

相关推荐
善 .3 小时前
单片机的内存是指RAM还是ROM
单片机·嵌入式硬件
超级码农ProMax3 小时前
STM32——“SPI Flash”
stm32·单片机·嵌入式硬件
Asa3194 小时前
stm32点灯Hal库
stm32·单片机·嵌入式硬件
撞上电子4 小时前
蓝桥杯物联网开发板硬件组成
物联网·职场和发展·蓝桥杯
end_SJ5 小时前
初学stm32 --- 外部中断
stm32·单片机·嵌入式硬件
lsalp5 小时前
OpenAI于2024年12月21日在GitHub上正式发布了实时嵌入式SDK。支持ESP32-S3
物联网·github·esp32-s3
gantengsheng6 小时前
基于51单片机和OLED12864的小游戏《贪吃蛇》
单片机·嵌入式硬件·游戏·51单片机
嵌入式小强工作室7 小时前
stm32 查找进硬件错误方法
stm32·单片机·嵌入式硬件
准橙考典7 小时前
如何考驾照?
物联网·安全·华为·自动驾驶·汽车
委员8 小时前
基于NodeMCU的物联网窗帘控制系统设计
单片机·mcu·物联网·智能家居·iot