打印
[应用相关]

STM32 驱动GPS模块

[复制链接]
5749|34
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
GPS模块特点包括:
1, 模块采用 U-BLOX NEO-6M 模组,体积小巧,性能优异。
2, 模块自带陶瓷天线及 MAXIM 公司 20.5dB 高增益 LNA 芯片,搜星能力强。
3, 模块可通过串口进行各种参数设置,并可保存在 EEPROM,使用方便。
4, 模块自带 IPX 接口,可以连接各种有源天线,适应能力强。
5, 模块兼容 3.3V/5V 电平,方便连接各种单片机系统。
6, 模块自带可充电后备电池,可以掉电保持星历数据


沙发
dingbo95|  楼主 | 2018-7-25 20:54 | 只看该作者
模块通过串口与外部系统连接,串口波特率支持 4800、9600、19200、38400) (默认)、57600、115200、230400 等不同速率,兼容 5V/3.3V 单片机系统,可以非常方便的与您的产品进行连接。
模块各参数如表


使用特权

评论回复
板凳
dingbo95|  楼主 | 2018-7-25 20:56 | 只看该作者
电气特性:

使用特权

评论回复
地板
dingbo95|  楼主 | 2018-7-25 20:57 | 只看该作者
NMEA- -3 0183 协议
NMEA 0183 是美国国家海洋电子协会(National Marine Electronics Association)为海用
电子设备制定的标准格式。目前业已成了 GPS 导航设备统一的 RTCM(Radio Technical
Commission for Maritime services)标准协议。
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):帧结束,回车和换行符

使用特权

评论回复
5
dingbo95|  楼主 | 2018-7-25 20:57 | 只看该作者
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

使用特权

评论回复
6
dingbo95|  楼主 | 2018-7-25 20:58 | 只看该作者
$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

使用特权

评论回复
7
dingbo95|  楼主 | 2018-7-25 20:58 | 只看该作者
$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

使用特权

评论回复
8
dingbo95|  楼主 | 2018-7-25 20:59 | 只看该作者
$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

使用特权

评论回复
9
dingbo95|  楼主 | 2018-7-25 21:00 | 只看该作者
$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

使用特权

评论回复
10
dingbo95|  楼主 | 2018-7-25 21:01 | 只看该作者
$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

使用特权

评论回复
11
dingbo95|  楼主 | 2018-7-25 21:02 | 只看该作者
$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

使用特权

评论回复
12
dingbo95|  楼主 | 2018-7-25 21:02 | 只看该作者
NMEA-0183协议命令帧部分就介绍到这里,接下来我们看看NMEA-0183协议的校验,
通过前面的介绍,我们知道每一帧最后都有一个 hh 的校验和,该校验和是通过计算$与*之
间所有字符 ASCII 码的异或运算得到,将得到的结果以 ASCII 字符表示就是该校验(hh)。
例如语句:$GPZDA,082710.00,16,09,2002,00,00*64,校验和(红色部分参与计算)计
算方法为:
0X47 xor 0X50 xor 0X5A xor 0X44 xor 0X41 xor 0X2C xor 0X30 xor 0X38 xor 0X32 xor
0X37 xor 0X31 xor 0X30 xor 0X2E xor 0X30 xor 0X30 xor 0X2C xor 0X31 xor 0X36 xor 0X2C
xor 0X30 xor 0X39 xor 0X2C xor 0X32 xor 0X30 xor 0X30 xor 0X32 xor 0X2C xor 0X30 xor
0X30 xor 0X2C xor 0X30 xor 0X30
得到的结果就是 0X64,用 ASCII 表示就是 64。
NMEA-0183 协议我们就介绍到这里,了解了该协议,我们就可以编写单片机代码,解
析 NMEA-0183 数据,从而得到 GPS 定位的各种信息了。

使用特权

评论回复
13
dingbo95|  楼主 | 2018-7-25 21:04 | 只看该作者
模块与单片机连接最少只需要 4 根线即可:VCC、GND、TXD、RXD。其中 VCC 和
GND 用于给模块供电,模块 TXD 和 RXD 则连接单片机的 RXD 和 TXD 即可。本模块兼容
5V 和 3.3V 单片机系统,所以可以很方便的连接到你的系统里面去。

使用特权

评论回复
14
dingbo95|  楼主 | 2018-7-25 21:11 | 只看该作者
驱动函数:
//从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;         
}

使用特权

评论回复
15
dingbo95|  楼主 | 2018-7-25 21:12 | 只看该作者
//m^n函数
//返回值:m^n次方.
u32 NMEA_Pow(u8 m,u8 n)
{
        u32 result=1;         
        while(n--)result*=m;   
        return result;
}

使用特权

评论回复
16
dingbo95|  楼主 | 2018-7-25 21:12 | 只看该作者
//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;
}                 

使用特权

评论回复
17
dingbo95|  楼主 | 2018-7-25 21:15 | 只看该作者
//分析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信息
        }   
}

使用特权

评论回复
18
dingbo95|  楼主 | 2018-7-25 21:16 | 只看该作者
//分析GPGGA信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GPGGA_Analysis(nmea_msg *gpsx,u8 *buf)
{
        u8 *p1,dx;                         
        u8 posx;   
        p1=(u8*)strstr((const char *)buf,"$GPGGA");
        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);  
}

使用特权

评论回复
19
dingbo95|  楼主 | 2018-7-25 21:16 | 只看该作者
//分析GPGSA信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GPGSA_Analysis(nmea_msg *gpsx,u8 *buf)
{
        u8 *p1,dx;                         
        u8 posx;
        u8 i;   
        p1=(u8*)strstr((const char *)buf,"$GPGSA");
        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);  
}

使用特权

评论回复
20
dingbo95|  楼主 | 2018-7-25 21:17 | 只看该作者
//分析GPRMC信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GPRMC_Analysis(nmea_msg *gpsx,u8 *buf)
{
        u8 *p1,dx;                         
        u8 posx;     
        u32 temp;          
        float rs;  
        p1=(u8*)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;                  
        }
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

52

主题

1197

帖子

5

粉丝