文章目录

  • GP-01模组简介
  • 1.硬件准备
  • 1.1 GP-01-Kit
  • 1.2 STM32F103C8T6核心板或者最小开发板
  • 1.3 接线方式
  • 2.软件准备
  • 2.1 MDK(Keil v5)
  • 2.2 串口调试助手(SSCOM)
  • 3.NMEA
  • 4.STM32程序实现
  • 4.1 串口部分代码
  • 4.2 GPS部分代码
  • 4.3 主函数部分
  • 5.实现效果
  • 联系我们


GP-01模组简介

GP-01是一款高性能 BDS/GNSS 多模卫星导航接收机SOC模块,集成了射频前端,数字基带处理器,32 位的 RISC CPU,电源管理和有源天线检测与保护功能。支持多种卫星导航系统,包括中国的北斗卫星导航系统 BDS,美国的 GPS,俄罗斯的GLONASS,可实现多系统联合定位。

本文将以GP-01-Kit开发板为例,介绍如何通过STM32获取到GP-01的定位的经纬度信息。

1.硬件准备

本文驱动涉及到的硬件有GP-01-Kit、STM32F103C8T6最小系统板、USB转TTL、STLink、杜邦线若干。

1.1 GP-01-Kit

android 12 gps调试 安卓gps模块_Data


GP-01开发板使用时需给开发板5V供电。

1.2 STM32F103C8T6核心板或者最小开发板

烧录方式可以选择通过串口烧录或者使用STLink或JLink下载。

1.3 接线方式

GP-01-kit开发板与STM32F103C8T6,以及STM32F103C8T6与USB转TTL之间的接线见下方表格

GP-01-Kit开发板

STM32F103C8T6

TX

PB11

RX

PB10

USB转TTL

STM32F103C8T6

GND

GND

VCC

V5

TX

PA10

RX

PA9

除此之外需要用安卓线给GP-01-Kit连接串口进行供电。

2.软件准备

2.1 MDK(Keil v5)

具体下载方法可参考网上的例子。

2.2 串口调试助手(SSCOM)

用于查看STM32UART驱动GP-01获取到的经纬度输出信息。

3.NMEA

GP-01支持NMEA-0183协议,它在上电一段时间后就会往串口输出数据,这些数据就是所有的GPS接收机和最通用的数据输出格式。NMEA-0183协议定义的语句非常多,但是常用的或者说兼容性最广的语句只有$GPGGA、$GPGSA、$GPGSV、$GPRMC、$GPVTG、$GPGLL等。要获取到经纬度通常需要关注的是$GNRMC的信息。

GPRMC协议如下:

android 12 gps调试 安卓gps模块_android 12 gps调试_02

4.STM32程序实现

源码获取方法:

4.1 串口部分代码

GPS和STM32之间的通信使用串口3,下面是串口3的初始化代码:

//初始化IO 串口3
//pclk1:PCLK1时钟频率(Mhz)
//bound:波特率	  
void usart3_init(u32 bound)
{  
	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	// GPIOB时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //串口3时钟使能
 	USART_DeInit(USART3);  //复位串口3
		 //USART3_TX   PB10
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
  GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB10
    //USART3_RX	  PB11
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOB, &GPIO_InitStructure);  //初始化PB11
	USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	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(USART3, &USART_InitStructure); //初始化串口	3
	USART_Cmd(USART3, ENABLE);                    //使能串口 
	//使能接收中断
  USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断   
	//设置中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	TIM7_Int_Init(1000-1,7200-1);		//10ms中断
	USART3_RX_STA=0;		//清零
	TIM_Cmd(TIM7,DISABLE);			//关闭定时器7
}

串口3使用中断方式接收数据到缓冲区,代码如下:

void USART3_IRQHandler(void)
{
	u8 res;	      
	if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)//接收到数据
	{	 
		res =USART_ReceiveData(USART3);		 
		if((USART3_RX_STA&(1<<15))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据
		{ 
			if(USART3_RX_STA<USART3_MAX_RECV_LEN)	//还可以接收数据
			{
				TIM_SetCounter(TIM7,0);//计数器清空          				//计数器清空
				if(USART3_RX_STA==0) 				//使能定时器7的中断 
				{
					TIM_Cmd(TIM7,ENABLE);//使能定时器7
				}
				USART3_RX_BUF[USART3_RX_STA++]=res;	//记录接收到的值	 
			}else 
			{
				USART3_RX_STA|=1<<15;				//强制标记接收完成
			} 
		}
	}  				 											 
}

4.2 GPS部分代码

gps.h中定义了解析后数据保存的结构体:

__packed typedef struct  
{										    

	u32 latitude;				//纬度 分扩大100000倍,实际要除以100000
	u8 nshemi;					//北纬/南纬,N:北纬;S:南纬				  
	u32 longitude;			    //经度 分扩大100000倍,实际要除以100000
	u8 ewhemi;					//东经/西经,E:东经;W:西经
}nmea_msg;

typedef struct Data
{
	
	float latitude;//纬度
	char N_S;//南北
	float longitude;//经度
	char E_W;//东西

}Data;

解析GPS数据信息:

//从buf里面得到第cx个逗号所在的位置
//返回值:0~0XFE,代表逗号所在位置的偏移.
//       0XFF,代表不存在第cx个逗号							  
u8 NMEA_Comma_Pos(u8 *buf,u8 cx)
{	 		    
	u8 *p=buf;
	while(cx)
	{		 
		if(*buf=='*'||*buf<' '||*buf>'z')return 0XFF;//遇到'*'或者非法字符,则不存在第cx个逗号
		if(*buf==',')cx--;
		buf++;
	}
	return buf-p;	 
}

//m^n函数
//返回值:m^n次方.
u32 NMEA_Pow(u8 m,u8 n)
{
	u32 result=1;	 
	while(n--)result*=m;    
	return result;
}


//str转换为数字,以','或者'*'结束
//buf:数字存储区
//dx:小数点位数,返回给调用函数
//返回值:转换后的数值
int NMEA_Str2num(u8 *buf,u8*dx)
{
	u8 *p=buf;
	u32 ires=0,fres=0;
	u8 ilen=0,flen=0,i;
	u8 mask=0;
	int res;
	while(1) //得到整数和小数的长度
	{
		if(*p=='-'){mask|=0X02;p++;}//是负数
		if(*p==','||(*p=='*'))break;//遇到结束了
		if(*p=='.'){mask|=0X01;p++;}//遇到小数点了
		else if(*p>'9'||(*p<'0'))	//有非法字符
		{	
			ilen=0;
			flen=0;
			break;
		}	
		if(mask&0X01)flen++;
		else ilen++;
		p++;
	}
	if(mask&0X02)buf++;	//去掉负号
	for(i=0;i<ilen;i++)	//得到整数部分数据
	{  
		ires+=NMEA_Pow(10,ilen-1-i)*(buf[i]-'0');
	}
	if(flen>5)flen=5;	//最多取5位小数
	*dx=flen;	 		//小数点位数
	for(i=0;i<flen;i++)	//得到小数部分数据
	{  
		fres+=NMEA_Pow(10,flen-1-i)*(buf[ilen+1+i]-'0');
	} 
	res=ires*NMEA_Pow(10,flen)+fres;
	if(mask&0X02)res=-res;		   
	return res;
}	  						

//分析GNRMC信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GNRMC_Analysis(nmea_msg *gpsx,u8 *buf)
{
	u8 *p1,dx;			 
	u8 posx;     
	u32 temp;	   
	float rs;  
	p1=(u8*)strstr((const char *)buf,"$GNRMC");//"$GNRMC",经常有&和GNRMC分开的情况,故只判断GPRMC.						
	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);		 
	
}

4.3 主函数部分

int main(void)
 {		 
	delay_init();	    	 		//延时函数初始化  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	//设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(9600);	 				//串口初始化为9600
	usart3_init(9600);	 					//串口初始化为9600
	 while(1)
	{
		delay_ms(1);
		if(USART3_RX_STA&0X8000)		//接收到一次数据了
		{		
 			USART3_RX_STA=0;		   //启动下一次接收
			NMEA_GNRMC_Analysis(&gpsx,(u8*)USART3_RX_BUF);
			GPS_Data.longitude=(float)((float)gpsx.longitude/100000);	
	        GPS_Data.latitude=(float)((float)gpsx.latitude/100000); 
			GPS_Data.N_S=((char)gpsx.nshemi);	
			GPS_Data.E_W=((char)gpsx.ewhemi);	
		
			 printf("Longitude: %f%c,  Latitude: %f%c\r\n",GPS_Data.longitude,GPS_Data.E_W,GPS_Data.latitude,GPS_Data.N_S);
 		}
	}
 

	}

5.实现效果

获取到的定位数据如下:

android 12 gps调试 安卓gps模块_Data_03