文章目录
- 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
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协议如下:
4.STM32程序实现
源码获取方法:
- 源码链接:https://pan.baidu.com/s/1I8CXlKuAWouwOdgN-9z_1w 提取码:AIXK
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.实现效果
获取到的定位数据如下: