移植北斗GPS驱动到STM32HAL库
既然是移植,那么自然就有源代码。源代码是我买的模块商家提供的。有很多,不过都不适用于我的F103,而且HAL库也是N个版本之前的。那么我们先来分析分析商家提供的源代码吧。
1.GPS.c文件
头文件部分没什么可说的,一定要改,而且include “stm32f1xx_hal.h”一定要放在第一个
#include "gps.h"
#include "led.h"
#include "delay.h"
#include "usart.h"
#include "stdio.h"
#include "stdarg.h"
#include "string.h"
#include "math.h"
接下来这部分基本都是将接收的串口数据转换成对应的GPS信息,不需要改动,可以直接拿来用。
const u32 BAUD_id[9]={4800,9600,19200,38400,57600,115200,230400,460800,921600};//模块支持波特率数组
//从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;
}
//分析GPGSV信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GPGSV_Analysis(nmea_msg *gpsx,u8 *buf)
{
u8 *p,*p1,dx;
u8 len,i,j,slx=0;
u8 posx;
p=buf;
p1=(u8*)strstr((const char *)p,"$GPGSV");
len=p1[7]-'0'; //得到GPGSV的条数
posx=NMEA_Comma_Pos(p1,3); //得到可见卫星总数
if(posx!=0XFF)gpsx->svnum=NMEA_Str2num(p1+posx,&dx);
for(i=0;i<len;i++)
{
p1=(u8*)strstr((const char *)p,"$GPGSV");
for(j=0;j<4;j++)
{
posx=NMEA_Comma_Pos(p1,4+j*4);
if(posx!=0XFF)gpsx->slmsg[slx].num=NMEA_Str2num(p1+posx,&dx); //得到卫星编号
else break;
posx=NMEA_Comma_Pos(p1,5+j*4);
if(posx!=0XFF)gpsx->slmsg[slx].eledeg=NMEA_Str2num(p1+posx,&dx);//得到卫星仰角
else break;
posx=NMEA_Comma_Pos(p1,6+j*4);
if(posx!=0XFF)gpsx->slmsg[slx].azideg=NMEA_Str2num(p1+posx,&dx);//得到卫星方位角
else break;
posx=NMEA_Comma_Pos(p1,7+j*4);
if(posx!=0XFF)gpsx->slmsg[slx].sn=NMEA_Str2num(p1+posx,&dx); //得到卫星信噪比
else break;
slx++;
}
p=p1+1;//切换到下一个GPGSV信息
}
}
//分析BDGSV信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_BDGSV_Analysis(nmea_msg *gpsx,u8 *buf)
{
u8 *p,*p1,dx;
u8 len,i,j,slx=0;
u8 posx;
p=buf;
p1=(u8*)strstr((const char *)p,"$BDGSV");
len=p1[7]-'0'; //得到BDGSV的条数
posx=NMEA_Comma_Pos(p1,3); //得到可见北斗卫星总数
if(posx!=0XFF)gpsx->beidou_svnum=NMEA_Str2num(p1+posx,&dx);
for(i=0;i<len;i++)
{
p1=(u8*)strstr((const char *)p,"$BDGSV");
for(j=0;j<4;j++)
{
posx=NMEA_Comma_Pos(p1,4+j*4);
if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_num=NMEA_Str2num(p1+posx,&dx); //得到卫星编号
else break;
posx=NMEA_Comma_Pos(p1,5+j*4);
if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_eledeg=NMEA_Str2num(p1+posx,&dx);//得到卫星仰角
else break;
posx=NMEA_Comma_Pos(p1,6+j*4);
if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_azideg=NMEA_Str2num(p1+posx,&dx);//得到卫星方位角
else break;
posx=NMEA_Comma_Pos(p1,7+j*4);
if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_sn=NMEA_Str2num(p1+posx,&dx); //得到卫星信噪比
else break;
slx++;
}
p=p1+1;//切换到下一个BDGSV信息
}
}
//分析GNGGA信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GNGGA_Analysis(nmea_msg *gpsx,u8 *buf)
{
u8 *p1,dx;
u8 posx;
p1=(u8*)strstr((const char *)buf,"$GNGGA");
posx=NMEA_Comma_Pos(p1,6); //得到GPS状态
if(posx!=0XFF)gpsx->gpssta=NMEA_Str2num(p1+posx,&dx);
posx=NMEA_Comma_Pos(p1,7); //得到用于定位的卫星数
if(posx!=0XFF)gpsx->posslnum=NMEA_Str2num(p1+posx,&dx);
posx=NMEA_Comma_Pos(p1,9); //得到海拔高度
if(posx!=0XFF)gpsx->altitude=NMEA_Str2num(p1+posx,&dx);
}
//分析GNGSA信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GNGSA_Analysis(nmea_msg *gpsx,u8 *buf)
{
u8 *p1,dx;
u8 posx;
u8 i;
p1=(u8*)strstr((const char *)buf,"$GNGSA");
posx=NMEA_Comma_Pos(p1,2); //得到定位类型
if(posx!=0XFF)gpsx->fixmode=NMEA_Str2num(p1+posx,&dx);
for(i=0;i<12;i++) //得到定位卫星编号
{
posx=NMEA_Comma_Pos(p1,3+i);
if(posx!=0XFF)gpsx->possl[i]=NMEA_Str2num(p1+posx,&dx);
else break;
}
posx=NMEA_Comma_Pos(p1,15); //得到PDOP位置精度因子
if(posx!=0XFF)gpsx->pdop=NMEA_Str2num(p1+posx,&dx);
posx=NMEA_Comma_Pos(p1,16); //得到HDOP位置精度因子
if(posx!=0XFF)gpsx->hdop=NMEA_Str2num(p1+posx,&dx);
posx=NMEA_Comma_Pos(p1,17); //得到VDOP位置精度因子
if(posx!=0XFF)gpsx->vdop=NMEA_Str2num(p1+posx,&dx);
}
//分析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,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;
}
}
//分析GNVTG信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GNVTG_Analysis(nmea_msg *gpsx,u8 *buf)
{
u8 *p1,dx;
u8 posx;
p1=(u8*)strstr((const char *)buf,"$GNVTG");
posx=NMEA_Comma_Pos(p1,7); //得到地面速率
if(posx!=0XFF)
{
gpsx->speed=NMEA_Str2num(p1+posx,&dx);
if(dx<3)gpsx->speed*=NMEA_Pow(10,3-dx); //确保扩大1000倍
}
}
//提取NMEA-0183信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void GPS_Analysis(nmea_msg *gpsx,u8 *buf)
{
NMEA_GPGSV_Analysis(gpsx,buf); //GPGSV解析
NMEA_BDGSV_Analysis(gpsx,buf); //BDGSV解析
NMEA_GNGGA_Analysis(gpsx,buf); //GNGGA解析
NMEA_GNGSA_Analysis(gpsx,buf); //GPNSA解析
NMEA_GNRMC_Analysis(gpsx,buf); //GPNMC解析
NMEA_GNVTG_Analysis(gpsx,buf); //GPNTG解析
}
下面这段是和GPS模块通讯的部分,不过主要是配置GPS模块,如果我们已经配置好,不打算再做修改,就可以直接注释掉,毕竟只读就可以得到GPS信息。
///////////////////////////////////////////UBLOX 配置代码/////////////////////////////////////
////检查CFG配置执行情况
////返回值:0,ACK成功
//// 1,接收超时错误
//// 2,没有找到同步字符
//// 3,接收到NACK应答
u8 SkyTra_Cfg_Ack_Check(void)
{
u16 len=0,i;
u8 rval=0;
while((USART3_RX_STA&0X8000)==0 && len<100)//等待接收到应答
{
len++;
delay_ms(5);
}
if(len<100) //超时错误.
{
len=USART3_RX_STA&0X7FFF; //此次接收到的数据长度
for(i=0;i<len;i++)
{
if(USART3_RX_BUF[i]==0X83)break;
else if(USART3_RX_BUF[i]==0X84)
{
rval=3;
break;
}
}
if(i==len)rval=2; //没有找到同步字符
}else rval=1; //接收超时错误
USART3_RX_STA=0; //清除接收
return rval;
}
//配置SkyTra_GPS/北斗模块波特率
//baud_id:0~8,对应波特率,4800/9600/19200/38400/57600/115200/230400/460800/921600
//返回值:0,执行成功;其他,执行失败(这里不会返回0了)
u8 SkyTra_Cfg_Prt(u32 baud_id)
{
SkyTra_baudrate *cfg_prt=(SkyTra_baudrate *)USART3_TX_BUF;
cfg_prt->sos=0XA1A0; //引导序列(小端模式)
cfg_prt->PL=0X0400; //有效数据长度(小端模式)
cfg_prt->id=0X05; //配置波特率的ID
cfg_prt->com_port=0X00; //操作串口1
cfg_prt->Baud_id=baud_id; ////波特率对应编号
cfg_prt->Attributes=1; //保存到SRAM&FLASH
cfg_prt->CS=cfg_prt->id^cfg_prt->com_port^cfg_prt->Baud_id^cfg_prt->Attributes;
cfg_prt->end=0X0A0D; //发送结束符(小端模式)
SkyTra_Send_Date((u8*)cfg_prt,sizeof(SkyTra_baudrate));//发送数据给SkyTra
delay_ms(200); //等待发送完成
usart3_init(BAUD_id[baud_id]); //重新初始化串口3
return SkyTra_Cfg_Ack_Check();//这里不会反回0,因为UBLOX发回来的应答在串口重新初始化的时候已经被丢弃了.
}
//配置SkyTra_GPS/北斗模块的时钟脉冲宽度
//width:脉冲宽度1~100000(us)
//返回值:0,发送成功;其他,发送失败.
u8 SkyTra_Cfg_Tp(u32 width)
{
u32 temp=width;
SkyTra_pps_width *cfg_tp=(SkyTra_pps_width *)USART3_TX_BUF;
temp=(width>>24)|((width>>8)&0X0000FF00)|((width<<8)&0X00FF0000)|((width<<24)&0XFF000000);//小端模式
cfg_tp->sos=0XA1A0; //cfg header(小端模式)
cfg_tp->PL=0X0700; //有效数据长度(小端模式)
cfg_tp->id=0X65 ; //cfg tp id
cfg_tp->Sub_ID=0X01; //数据区长度为20个字节.
cfg_tp->width=temp; //脉冲宽度,us
cfg_tp->Attributes=0X01; //保存到SRAM&FLASH
cfg_tp->CS=cfg_tp->id^cfg_tp->Sub_ID^(cfg_tp->width>>24)^(cfg_tp->width>>16)&0XFF^(cfg_tp->width>>8)&0XFF^cfg_tp->width&0XFF^cfg_tp->Attributes; //用户延时为0ns
cfg_tp->end=0X0A0D; //发送结束符(小端模式)
SkyTra_Send_Date((u8*)cfg_tp,sizeof(SkyTra_pps_width));//发送数据给NEO-6M
return SkyTra_Cfg_Ack_Check();
}
//配置SkyTraF8-BD的更新速率
//Frep:(取值范围:1,2,4,5,8,10,20,25,40,50)测量时间间隔,单位为Hz,最大不能大于50Hz
//返回值:0,发送成功;其他,发送失败.
u8 SkyTra_Cfg_Rate(u8 Frep)
{
SkyTra_PosRate *cfg_rate=(SkyTra_PosRate *)USART3_TX_BUF;
cfg_rate->sos=0XA1A0; //cfg header(小端模式)
cfg_rate->PL=0X0300; //有效数据长度(小端模式)
cfg_rate->id=0X0E; //cfg rate id
cfg_rate->rate=Frep; //更新速率
cfg_rate->Attributes=0X01; //保存到SRAM&FLASH .
cfg_rate->CS=cfg_rate->id^cfg_rate->rate^cfg_rate->Attributes;//脉冲间隔,us
cfg_rate->end=0X0A0D; //发送结束符(小端模式)
SkyTra_Send_Date((u8*)cfg_rate,sizeof(SkyTra_PosRate));//发送数据给NEO-6M
return SkyTra_Cfg_Ack_Check();
}
//发送一批数据给Ublox NEO-6M,这里通过串口3发送
//dbuf:数据缓存首地址
//len:要发送的字节数
void SkyTra_Send_Date(u8* dbuf,u16 len)
{
u16 j;
for(j=0;j<len;j++)//循环发送数据
{
while((USART3->SR&0X40)==0);//循环发送,直到发送完毕
USART3->DR=dbuf[j];
}
}
所以最终的GPS.c 文件修改为这样
/*
* GPS.c
*
* Created on: Apr 4, 2020
* Author:
*/
#include "stm32f1xx_hal.h"
#include "GPS.h"
#include "main.h"
#include "gps.h"
#include "stdio.h"
#include "stdarg.h"
#include "string.h"
#include "math.h"
const u32 BAUD_id[9]={4800,9600,19200,38400,57600,115200,230400,460800,921600};//模块支持波特率数组
//从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;
}
//分析GPGSV信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GPGSV_Analysis(nmea_msg *gpsx,u8 *buf)
{
u8 *p,*p1,dx;
u8 len,i,j,slx=0;
u8 posx;
p=buf;
p1=(u8*)strstr((const char *)p,"$GPGSV");
len=p1[7]-'0'; //得到GPGSV的条数
posx=NMEA_Comma_Pos(p1,3); //得到可见卫星总数
if(posx!=0XFF)gpsx->svnum=NMEA_Str2num(p1+posx,&dx);
for(i=0;i<len;i++)
{
p1=(u8*)strstr((const char *)p,"$GPGSV");
for(j=0;j<4;j++)
{
posx=NMEA_Comma_Pos(p1,4+j*4);
if(posx!=0XFF)gpsx->slmsg[slx].num=NMEA_Str2num(p1+posx,&dx); //得到卫星编号
else break;
posx=NMEA_Comma_Pos(p1,5+j*4);
if(posx!=0XFF)gpsx->slmsg[slx].eledeg=NMEA_Str2num(p1+posx,&dx);//得到卫星仰角
else break;
posx=NMEA_Comma_Pos(p1,6+j*4);
if(posx!=0XFF)gpsx->slmsg[slx].azideg=NMEA_Str2num(p1+posx,&dx);//得到卫星方位角
else break;
posx=NMEA_Comma_Pos(p1,7+j*4);
if(posx!=0XFF)gpsx->slmsg[slx].sn=NMEA_Str2num(p1+posx,&dx); //得到卫星信噪比
else break;
slx++;
}
p=p1+1;//切换到下一个GPGSV信息
}
}
//分析BDGSV信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_BDGSV_Analysis(nmea_msg *gpsx,u8 *buf)
{
u8 *p,*p1,dx;
u8 len,i,j,slx=0;
u8 posx;
p=buf;
p1=(u8*)strstr((const char *)p,"$BDGSV");
len=p1[7]-'0'; //得到BDGSV的条数
posx=NMEA_Comma_Pos(p1,3); //得到可见北斗卫星总数
if(posx!=0XFF)gpsx->beidou_svnum=NMEA_Str2num(p1+posx,&dx);
for(i=0;i<len;i++)
{
p1=(u8*)strstr((const char *)p,"$BDGSV");
for(j=0;j<4;j++)
{
posx=NMEA_Comma_Pos(p1,4+j*4);
if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_num=NMEA_Str2num(p1+posx,&dx); //得到卫星编号
else break;
posx=NMEA_Comma_Pos(p1,5+j*4);
if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_eledeg=NMEA_Str2num(p1+posx,&dx);//得到卫星仰角
else break;
posx=NMEA_Comma_Pos(p1,6+j*4);
if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_azideg=NMEA_Str2num(p1+posx,&dx);//得到卫星方位角
else break;
posx=NMEA_Comma_Pos(p1,7+j*4);
if(posx!=0XFF)gpsx->beidou_slmsg[slx].beidou_sn=NMEA_Str2num(p1+posx,&dx); //得到卫星信噪比
else break;
slx++;
}
p=p1+1;//切换到下一个BDGSV信息
}
}
//分析GNGGA信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GNGGA_Analysis(nmea_msg *gpsx,u8 *buf)
{
u8 *p1,dx;
u8 posx;
p1=(u8*)strstr((const char *)buf,"$GNGGA");
posx=NMEA_Comma_Pos(p1,6); //得到GPS状态
if(posx!=0XFF)gpsx->gpssta=NMEA_Str2num(p1+posx,&dx);
posx=NMEA_Comma_Pos(p1,7); //得到用于定位的卫星数
if(posx!=0XFF)gpsx->posslnum=NMEA_Str2num(p1+posx,&dx);
posx=NMEA_Comma_Pos(p1,9); //得到海拔高度
if(posx!=0XFF)gpsx->altitude=NMEA_Str2num(p1+posx,&dx);
}
//分析GNGSA信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GNGSA_Analysis(nmea_msg *gpsx,u8 *buf)
{
u8 *p1,dx;
u8 posx;
u8 i;
p1=(u8*)strstr((const char *)buf,"$GNGSA");
posx=NMEA_Comma_Pos(p1,2); //得到定位类型
if(posx!=0XFF)gpsx->fixmode=NMEA_Str2num(p1+posx,&dx);
for(i=0;i<12;i++) //得到定位卫星编号
{
posx=NMEA_Comma_Pos(p1,3+i);
if(posx!=0XFF)gpsx->possl[i]=NMEA_Str2num(p1+posx,&dx);
else break;
}
posx=NMEA_Comma_Pos(p1,15); //得到PDOP位置精度因子
if(posx!=0XFF)gpsx->pdop=NMEA_Str2num(p1+posx,&dx);
posx=NMEA_Comma_Pos(p1,16); //得到HDOP位置精度因子
if(posx!=0XFF)gpsx->hdop=NMEA_Str2num(p1+posx,&dx);
posx=NMEA_Comma_Pos(p1,17); //得到VDOP位置精度因子
if(posx!=0XFF)gpsx->vdop=NMEA_Str2num(p1+posx,&dx);
}
//分析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,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;
}
}
//分析GNVTG信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GNVTG_Analysis(nmea_msg *gpsx,u8 *buf)
{
u8 *p1,dx;
u8 posx;
p1=(u8*)strstr((const char *)buf,"$GNVTG");
posx=NMEA_Comma_Pos(p1,7); //得到地面速率
if(posx!=0XFF)
{
gpsx->speed=NMEA_Str2num(p1+posx,&dx);
if(dx<3)gpsx->speed*=NMEA_Pow(10,3-dx); //确保扩大1000倍
}
}
//提取NMEA-0183信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void GPS_Analysis(nmea_msg *gpsx,u8 *buf)
{
NMEA_GPGSV_Analysis(gpsx,buf); //GPGSV解析
NMEA_BDGSV_Analysis(gpsx,buf); //BDGSV解析
NMEA_GNGGA_Analysis(gpsx,buf); //GNGGA解析
NMEA_GNGSA_Analysis(gpsx,buf); //GPNSA解析
NMEA_GNRMC_Analysis(gpsx,buf); //GPNMC解析
NMEA_GNVTG_Analysis(gpsx,buf); //GPNTG解析
}
2. GPS.h文件
GPS.h文件按理说不用修改,不过结构体部分有一些版本导致的报错,我看着不爽也给修改了,主要就是
__packed typedef struct 修改为 typedef struct __attribute__((packed))
#ifndef __GPS_H
#define __GPS_H
#include "sys.h"
//GPS NMEA-0183协议重要参数结构体定义
//卫星信息
__packed typedef struct
{
u8 num; //卫星编号
u8 eledeg; //卫星仰角
u16 azideg; //卫星方位角
u8 sn; //信噪比
}nmea_slmsg;
//北斗 NMEA-0183协议重要参数结构体定义
//卫星信息
__packed typedef struct
{
u8 beidou_num; //卫星编号
u8 beidou_eledeg; //卫星仰角
u16 beidou_azideg; //卫星方位角
u8 beidou_sn; //信噪比
}beidou_nmea_slmsg;
//UTC时间信息
__packed typedef struct
{
u16 year; //年份
u8 month; //月份
u8 date; //日期
u8 hour; //小时
u8 min; //分钟
u8 sec; //秒钟
}nmea_utc_time;
//NMEA 0183 协议解析后数据存放结构体
__packed typedef struct
{
u8 svnum; //可见GPS卫星数
u8 beidou_svnum; //可见GPS卫星数
nmea_slmsg slmsg[12]; //最多12颗GPS卫星
beidou_nmea_slmsg beidou_slmsg[12]; //暂且算最多12颗北斗卫星
nmea_utc_time utc; //UTC时间
u32 latitude; //纬度 分扩大100000倍,实际要除以100000
u8 nshemi; //北纬/南纬,N:北纬;S:南纬
u32 longitude; //经度 分扩大100000倍,实际要除以100000
u8 ewhemi; //东经/西经,E:东经;W:西经
u8 gpssta; //GPS状态:0,未定位;1,非差分定位;2,差分定位;6,正在估算.
u8 posslnum; //用于定位的GPS卫星数,0~12.
u8 possl[12]; //用于定位的卫星编号
u8 fixmode; //定位类型:1,没有定位;2,2D定位;3,3D定位
u16 pdop; //位置精度因子 0~500,对应实际值0~50.0
u16 hdop; //水平精度因子 0~500,对应实际值0~50.0
u16 vdop; //垂直精度因子 0~500,对应实际值0~50.0
int altitude; //海拔高度,放大了10倍,实际除以10.单位:0.1m
u16 speed; //地面速率,放大了1000倍,实际除以10.单位:0.001公里/小时
}nmea_msg;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 配置波特率结构体
__packed typedef struct
{
u16 sos; //启动序列,固定为0XA0A1
u16 PL; //有效数据长度0X0004;
u8 id; //ID,固定为0X05
u8 com_port; //COM口,固定为0X00,即COM1
u8 Baud_id; //波特率(0~8,4800,9600,19200,38400,57600,115200,230400,460800,921600)
u8 Attributes; //配置数据保存位置 ,0保存到SRAM,1保存到SRAM&FLASH,2临时保存
u8 CS; //校验值
u16 end; //结束符:0X0D0A
}SkyTra_baudrate;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 配置输出信息结构体
__packed typedef struct
{
u16 sos; //启动序列,固定为0XA0A1
u16 PL; //有效数据长度0X0009;
u8 id; //ID,固定为0X08
u8 GGA; //1~255(s),0:disable
u8 GSA; //1~255(s),0:disable
u8 GSV; //1~255(s),0:disable
u8 GLL; //1~255(s),0:disable
u8 RMC; //1~255(s),0:disable
u8 VTG; //1~255(s),0:disable
u8 ZDA; //1~255(s),0:disable
u8 Attributes; //配置数据保存位置 ,0保存到SRAM,1保存到SRAM&FLASH,2临时保存
u8 CS; //校验值
u16 end; //结束符:0X0D0A
}SkyTra_outmsg;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 配置位置更新率结构体
__packed typedef struct
{
u16 sos; //启动序列,固定为0XA0A1
u16 PL; //有效数据长度0X0003;
u8 id; //ID,固定为0X0E
u8 rate; //取值范围:1, 2, 4, 5, 8, 10, 20, 25, 40, 50
u8 Attributes; //配置数据保存位置 ,0保存到SRAM,1保存到SRAM&FLASH,2临时保存
u8 CS; //校验值
u16 end; //结束符:0X0D0A
}SkyTra_PosRate;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 配置输出脉冲(PPS)宽度结构体
__packed typedef struct
{
u16 sos; //启动序列,固定为0XA0A1
u16 PL; //有效数据长度0X0007;
u8 id; //ID,固定为0X65
u8 Sub_ID; //0X01
u32 width; //1~100000(us)
u8 Attributes; //配置数据保存位置 ,0保存到SRAM,1保存到SRAM&FLASH,2临时保存
u8 CS; //校验值
u16 end; //结束符:0X0D0A
}SkyTra_pps_width;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 ACK结构体
__packed typedef struct
{
u16 sos; //启动序列,固定为0XA0A1
u16 PL; //有效数据长度0X0002;
u8 id; //ID,固定为0X83
u8 ACK_ID; //ACK ID may further consist of message ID and message sub-ID which will become 3 bytes of ACK message
u8 CS; //校验值
u16 end; //结束符
}SkyTra_ACK;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 NACK结构体
__packed typedef struct
{
u16 sos; //启动序列,固定为0XA0A1
u16 PL; //有效数据长度0X0002;
u8 id; //ID,固定为0X84
u8 NACK_ID; //ACK ID may further consist of message ID and message sub-ID which will become 3 bytes of ACK message
u8 CS; //校验值
u16 end; //结束符
}SkyTra_NACK;
int NMEA_Str2num(u8 *buf,u8*dx);
void GPS_Analysis(nmea_msg *gpsx,u8 *buf);
void NMEA_GPGSV_Analysis(nmea_msg *gpsx,u8 *buf);
void NMEA_BDGSV_Analysis(nmea_msg *gpsx,u8 *buf);
void NMEA_GNGGA_Analysis(nmea_msg *gpsx,u8 *buf);
void NMEA_GNGSA_Analysis(nmea_msg *gpsx,u8 *buf);
void NMEA_GNGSA_Analysis(nmea_msg *gpsx,u8 *buf);
void NMEA_GNRMC_Analysis(nmea_msg *gpsx,u8 *buf);
void NMEA_GNVTG_Analysis(nmea_msg *gpsx,u8 *buf);
u8 SkyTra_Cfg_Cfg_Save(void);
u8 SkyTra_Cfg_Msg(u8 msgid,u8 uart1set);
u8 SkyTra_Cfg_Prt(u32 baud_id);
u8 SkyTra_Cfg_Tp(u32 width);
u8 SkyTra_Cfg_Rate(u8 Frep);
void SkyTra_Send_Date(u8* dbuf,u16 len);
u8* data_Little_endian(u8* data,u16 len);
#endif
修改之后的GPS.h文件
/*
* GPS.h
*
* Created on: Apr 4, 2020
* Author:
*/
#ifndef INC_GPS_H_
#define INC_GPS_H_
#include "stm32f1xx_hal_i2c.h"
#define u8 uint8_t
#define u32 uint32_t
#define u16 uint16_t
//GPS NMEA-0183协议重要参数结构体定义
//卫星信息
typedef struct __attribute__((packed))
{
u8 num; //卫星编号
u8 eledeg; //卫星仰角
u16 azideg; //卫星方位角
u8 sn; //信噪比
}nmea_slmsg;
//北斗 NMEA-0183协议重要参数结构体定义
//卫星信息
typedef struct __attribute__((packed))
{
u8 beidou_num; //卫星编号
u8 beidou_eledeg; //卫星仰角
u16 beidou_azideg; //卫星方位角
u8 beidou_sn; //信噪比
}beidou_nmea_slmsg;
//UTC时间信息
typedef struct __attribute__((packed))
{
u16 year; //年份
u8 month; //月份
u8 date; //日期
u8 hour; //小时
u8 min; //分钟
u8 sec; //秒钟
}nmea_utc_time;
//NMEA 0183 协议解析后数据存放结构体
typedef struct __attribute__((packed))
{
u8 svnum; //可见GPS卫星数
u8 beidou_svnum; //可见GPS卫星数
nmea_slmsg slmsg[12]; //最多12颗GPS卫星
beidou_nmea_slmsg beidou_slmsg[12]; //暂且算最多12颗北斗卫星
nmea_utc_time utc; //UTC时间
u32 latitude; //纬度 分扩大100000倍,实际要除以100000
u8 nshemi; //北纬/南纬,N:北纬;S:南纬
u32 longitude; //经度 分扩大100000倍,实际要除以100000
u8 ewhemi; //东经/西经,E:东经;W:西经
u8 gpssta; //GPS状态:0,未定位;1,非差分定位;2,差分定位;6,正在估算.
u8 posslnum; //用于定位的GPS卫星数,0~12.
u8 possl[12]; //用于定位的卫星编号
u8 fixmode; //定位类型:1,没有定位;2,2D定位;3,3D定位
u16 pdop; //位置精度因子 0~500,对应实际值0~50.0
u16 hdop; //水平精度因子 0~500,对应实际值0~50.0
u16 vdop; //垂直精度因子 0~500,对应实际值0~50.0
int altitude; //海拔高度,放大了10倍,实际除以10.单位:0.1m
u16 speed; //地面速率,放大了1000倍,实际除以10.单位:0.001公里/小时
}nmea_msg;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 配置波特率结构体
typedef struct __attribute__((packed))
{
u16 sos; //启动序列,固定为0XA0A1
u16 PL; //有效数据长度0X0004;
u8 id; //ID,固定为0X05
u8 com_port; //COM口,固定为0X00,即COM1
u8 Baud_id; //波特率(0~8,4800,9600,19200,38400,57600,115200,230400,460800,921600)
u8 Attributes; //配置数据保存位置 ,0保存到SRAM,1保存到SRAM&FLASH,2临时保存
u8 CS; //校验值
u16 end; //结束符:0X0D0A
}SkyTra_baudrate;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 配置输出信息结构体
typedef struct __attribute__((packed))
{
u16 sos; //启动序列,固定为0XA0A1
u16 PL; //有效数据长度0X0009;
u8 id; //ID,固定为0X08
u8 GGA; //1~255(s),0:disable
u8 GSA; //1~255(s),0:disable
u8 GSV; //1~255(s),0:disable
u8 GLL; //1~255(s),0:disable
u8 RMC; //1~255(s),0:disable
u8 VTG; //1~255(s),0:disable
u8 ZDA; //1~255(s),0:disable
u8 Attributes; //配置数据保存位置 ,0保存到SRAM,1保存到SRAM&FLASH,2临时保存
u8 CS; //校验值
u16 end; //结束符:0X0D0A
}SkyTra_outmsg;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 配置位置更新率结构体
typedef struct __attribute__((packed))
{
u16 sos; //启动序列,固定为0XA0A1
u16 PL; //有效数据长度0X0003;
u8 id; //ID,固定为0X0E
u8 rate; //取值范围:1, 2, 4, 5, 8, 10, 20, 25, 40, 50
u8 Attributes; //配置数据保存位置 ,0保存到SRAM,1保存到SRAM&FLASH,2临时保存
u8 CS; //校验值
u16 end; //结束符:0X0D0A
}SkyTra_PosRate;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 配置输出脉冲(PPS)宽度结构体
typedef struct __attribute__((packed))
{
u16 sos; //启动序列,固定为0XA0A1
u16 PL; //有效数据长度0X0007;
u8 id; //ID,固定为0X65
u8 Sub_ID; //0X01
u32 width; //1~100000(us)
u8 Attributes; //配置数据保存位置 ,0保存到SRAM,1保存到SRAM&FLASH,2临时保存
u8 CS; //校验值
u16 end; //结束符:0X0D0A
}SkyTra_pps_width;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 ACK结构体
typedef struct __attribute__((packed))
{
u16 sos; //启动序列,固定为0XA0A1
u16 PL; //有效数据长度0X0002;
u8 id; //ID,固定为0X83
u8 ACK_ID; //ACK ID may further consist of message ID and message sub-ID which will become 3 bytes of ACK message
u8 CS; //校验值
u16 end; //结束符
}SkyTra_ACK;
////////////////////////////////////////////////////////////////////////////////////////////////////
//SkyTra S1216F8 NACK结构体
typedef struct __attribute__((packed))
{
u16 sos; //启动序列,固定为0XA0A1
u16 PL; //有效数据长度0X0002;
u8 id; //ID,固定为0X84
u8 NACK_ID; //ACK ID may further consist of message ID and message sub-ID which will become 3 bytes of ACK message
u8 CS; //校验值
u16 end; //结束符
}SkyTra_NACK;
int NMEA_Str2num(u8 *buf,u8*dx);
void GPS_Analysis(nmea_msg *gpsx,u8 *buf);
void NMEA_GPGSV_Analysis(nmea_msg *gpsx,u8 *buf);
void NMEA_BDGSV_Analysis(nmea_msg *gpsx,u8 *buf);
void NMEA_GNGGA_Analysis(nmea_msg *gpsx,u8 *buf);
void NMEA_GNGSA_Analysis(nmea_msg *gpsx,u8 *buf);
void NMEA_GNGSA_Analysis(nmea_msg *gpsx,u8 *buf);
void NMEA_GNRMC_Analysis(nmea_msg *gpsx,u8 *buf);
void NMEA_GNVTG_Analysis(nmea_msg *gpsx,u8 *buf);
u8 SkyTra_Cfg_Cfg_Save(void);
u8 SkyTra_Cfg_Msg(u8 msgid,u8 uart1set);
u8 SkyTra_Cfg_Prt(u32 baud_id);
u8 SkyTra_Cfg_Tp(u32 width);
u8 SkyTra_Cfg_Rate(u8 Frep);
void SkyTra_Send_Date(u8* dbuf,u16 len);
u8* data_Little_endian(u8* data,u16 len);
#endif /* INC_GPS_H_ */
将修改好的GPS.c 和GPS.h 文件添加到Src和Inc文件夹即可。
3.配置串口DMA
模块比特率默认38400
使能串口DMA
4.main.c代码
添加头文件和变量
#include "gps.h"
#include "stdio.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
volatile uint8_t rx_len=0; //接收数据长度
//volatile关键字提醒编译器定义的变量是易变
volatile uint8_t recv_end_flag=0; //接收完成标记
uint8_t rx_buffer[800]; //接收缓存
uint16_t BUFFER_SIZE = 800; //不定长数据的长度
另一些变量
/* USER CODE BEGIN PV */
nmea_msg gpsx; //GPS信息
u8 dtbuf[50] __attribute__ ((aligned (4)));; //打印缓存
float tp;
在串口函数中添加代码
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能idle中断
HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE); //打开DMA接收,数据存入rx_buffer数组
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 38400;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能idle中断
HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE); //打开DMA接收,数据存入rx_buffer数组
/* USER CODE END USART1_Init 2 */
}
编写两个GPS接收和打印函数
void Get_Gps_Data(void)//接受GPS信息
{
if(recv_end_flag ==1)
{
GPS_Analysis(&gpsx,(u8*)rx_buffer);//分析字符
Gps_Msg_Show();
for(uint8_t i=0;i<rx_len;i++)
{
rx_buffer[i]=0; //清接收缓
}
rx_len=0; //清除计数
recv_end_flag=0; //清除接收结束标志
}
}
下面这块偷懒直接把OELD打印写里面了
void Gps_Msg_Show(void)
{
float tp1;
float tp2;
tp1=gpsx.longitude;
sprintf((char *)dtbuf,"Longitude:%.5f %1c",tp1/=100000,gpsx.ewhemi); //得到经度字符
OLED_ShowStr(0,0,dtbuf,1);
tp2=gpsx.latitude;
sprintf((char *)dtbuf,"Latitude:%.5f %1c ",tp2/=100000,gpsx.nshemi); //得到纬度字符
OLED_ShowStr(0,1,dtbuf,1);
sprintf((char *)dtbuf,"UTC Date:%04d/%02d/%02d ",gpsx.utc.year,gpsx.utc.month,gpsx.utc.date); //显示UTC日期
OLED_ShowStr(0,2,dtbuf,1);
sprintf((char *)dtbuf,"UTC Time:%02d:%02d:%02d ",gpsx.utc.hour,gpsx.utc.min,gpsx.utc.sec); //显示UTC时间
OLED_ShowStr(0,3,dtbuf,1);
sprintf((char *)WriteBuffer,"日期:%04d/%02d/%02d 时间:%02d:%02d:%02d 经度:%.5f %1c 纬度:%.5f %1c ",gpsx.utc.year,gpsx.utc.month,gpsx.utc.date,gpsx.utc.hour,gpsx.utc.min,gpsx.utc.sec,tp1/=100000,gpsx.ewhemi,tp2/=100000,gpsx.nshemi);
}
之后只要在while循环中调用这两个函数就可以打印出GPS信息了