日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

GPS模块开发详解(转)

發布時間:2023/12/15 综合教程 44 生活家
生活随笔 收集整理的這篇文章主要介紹了 GPS模块开发详解(转) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

大家好,又見面了,我是你們的朋友風君子。

一、了解硬件
我使用的GPS模塊型號為UBX-M8030

參看:UBX-M8030 系列
參看:UBX-M8030 datasheet

1、查看一下它的特性:
多用途 GNSS 芯片,提供三種產品等級
最多可并發接收 3 個 GNSS(GPS、伽利略、GLONASS、北斗)
行業領先的 -167 dBm 導航靈敏度
業界最低電流消耗
在城市峽谷中具有絕佳的定位精度
安全性和完整性保護
支持所有的衛星增強系統
車載級芯片的工作溫度為 -40°至 +105°C
##2、原理圖

可以看出與MCU相連的只有RXD、TXD、GPS_POW三個引腳

其中GPS_POW 模塊主電源使能引腳:
用來使能BL9198穩壓芯片輸入5v輸出3.3v

同4G模塊一樣,GPS_POW 引腳,高電平GPS工作,低電平GPS不工作。

#define GPS_POWER_ON() (GPIO_SetBits (BSP_GPIOA_PORTS, BSP_GPIOA_GPS_POWEN_PINS))
#define GPS_POWER_OFF() (GPIO_ResetBits (BSP_GPIOA_PORTS, BSP_GPIOA_GPS_POWEN_PINS))
1
2
這里不做過多講解了。

二、軟件部分
1、初始化
首先明確一下,我們一共使用了4個串口:

4G模塊 – USART1
GPS – USART2
BLE – USART3
DEBUG – UART4

###串口初始化
其中串口初始化部分我就不講了,參看:STM32開發 – 串口詳解

需要注意的兩點:
1、串口時鐘使能
USART2是掛載在 APB1 下面的外設,所以使能函數為:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
1
2、GPIO端口模式設置
TX的GPIO工作模式為:GPIO_Mode_AF_PP;//復用推挽輸出
RX的GPIO工作模式為:GPIO_Mode_IN_FLOATING;//浮空輸入或者上拉輸入
###DMA配置
通過DMA方式接收GPS過來的數據。

void GpsRxDMACfg( uint8_t buf[],uint16_t BufferSize)
{

DMA_InitTypeDef DMA_InitStructure;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //開啟DMA1時鐘
USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE); //打開串口2 DMA接收使能 開啟串口DMA接收

DMA_DeInit(GPS_RxDMA_Ch); //恢復缺省值
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART2->DR); //設置USART2發送數據寄存器
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buf; //設置發送緩沖區首地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //設置外設位目標,內存緩沖區->外設寄存器
DMA_InitStructure.DMA_BufferSize = BufferSize; //需要發送的字節數
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外設地址不做增加調整,調整不調整都是DMA自動實現的
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //內存緩沖區地址增加調整
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外設數據寬度8位,1個字節
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //內存數據寬度8位,1個字節
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //單次傳輸模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //優先級設置
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //關閉內存到內存的DMA模式
DMA_Init(GPS_RxDMA_Ch, &DMA_InitStructure); //寫入配置
DMA_Cmd(GPS_RxDMA_Ch, ENABLE); //開啟DMA通信,等待接收數據
}

這里留下一個小疑問,DMA是什么作用?
參看:STM32開發 – DMA詳解

三、GNSS衛星協議
參看:GNSS衛星協議

NMEA(National Marine Electronics Association) 0183協議簡介
NMEA 0183 是美國國家海洋電子協會為海用電子設備制定的標準格式,是一種航海、海運方面有關于數字信號傳遞的標準,此標準定義了電子信號所需要的傳輸協議,傳輸數據時間。這個協議是文本格式的。大致格式如下:

NMEA0183消息輸出格式 : $–sss,df1,df2,…[CR][LF]
數據標識是表示某種衛星發射。 –標識如下:

各主要 GNNS 消息內容識別碼的含義如下:
GGA:時間、位置、定位數據
GLL:經緯度,UTC時間和定位狀態
GSA:接收機模式和衛星工作數據,包括位置和水平/豎直稀釋精度等。稀釋精度(Dilution of Precision)是個地理定位
術語.一個接收器可以在同一時間得到許多顆衛星定位信息,但在精密定位上,只要四顆衛星訊號即已足夠了
GSV:接收機能接收到的衛星信息,包括衛星 ID,海拔,仰角,方位角,信噪比(SNR)等
RMC:日期,時間,位置,方向,速度數據。是最常用的一個消息
VTG:方位角與對地速度
MSS:信噪比(SNR),信號強度,頻率,比特率
ZDA:時間和日期數據
注: GNSS系統還含有一些未在此列出的其它信號,特定軟硬件平臺只能處理的特定的信號

與地理信息密切相關的消息及其所含主要內容如下,各消息之間的信息字段有出入也有重復,在一輪消息循環里,各消息相同的字段中包含相同的地理數據,可綜合多個消息來獲取完整的數據。

各信息內容識別碼下的信號分析如下:
1. GGA(時間、位置、定位數據)
例樣數據:
$–GGA,1661229.478,3723.2475,N,12158.3416,W,1,07,1.0,9.0,M,7.3,M, ,0000*18

2. GLL(經緯度,UTC時間和定位狀態)
例樣數據:
$–GLL,3723.2475,N,12158.3416,W,161229.487,A,0*2C

3. GSA(接收機模式和衛星工作數據,包括位置和水平/豎直稀釋精度等)
例樣數據:
$–GSA,A,3,07,02,26,27,09,04,15, , , , , ,1.8,1.0,1.5*33

4. GSV(接收機能接收到的衛星信息,包括衛星ID,仰角,方位角,信噪比(SNR)等)
例樣數據:
$–GSV,2,1,07,07,79,048,42,02,51,062,43,26,36,256,42,27,27,138,42*71

$–GSV,2,2,07,09,23,313,42,04,19,159,41,15,12,041,42*41
這兩條語句描述一個完整的衛星信息(這里共描述7顆衛星,每顆衛星的描述部分已用不同顏色標出),每顆衛星用4個段來描述:衛星ID(又稱隨機偽代碼, PRC)、衛星高程(仰角,衛星和接收點連線與水平面的夾角)、方位角(連線在水平面上的投影與正北方向的順時針旋轉夾角)、信噪比。

5. MSS(信噪比(SNR),信號強度,頻率,比特率)
例樣數據:
$–MSS,55,27,318.0,100,*66

6. RMC(日期,時間,位置,方向,速度數據。是最常用的一個消息)
例樣數據:
$–RMC,161229.487,A,3723.2475,N,12158.3416,W,0.13,309.62,120598, , ,A*10
這條語句基本上包含了GPS應用程序所需的全部數據:緯度、經度、速度、方向、衛星時間、狀態以及磁場變量

7. VTG(方位角與對地速度)
例樣數據:
$–VTG,309.62,T, ,M,0.13,N,0.2,K,A*6E

8. TXT(短文本信息傳送)
例樣數據:
$–TXT,01,01,01,ANTENNA OK*2B

四、數據接收
我們知道了GPS使用的是USART2,DMA接收使能
參看:STM32開發 – DMA詳解

一個比較重要的函數,獲取當前剩余數據量大小:

uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx)
1
則:
先配置DMA

GpsRxDMACfg( GpsTransferBuffer,DEF_GPS_RBUFSIZE );
//GpsTransferBuffer為接收buffer,DEF_GPS_RBUFSIZE 為設置的接收buffer大小(512)
1
2
根據設置的接收buff大小減去當前剩余數據量,得到當前接收數據大小。

curcount = DEF_GPS_RBUFSIZE – DMA_GetCurrDataCounter( GPS_RxDMA_Ch );
1
五、GNNS 消息解析
最重要的是將接收到的GNNS 消息解析,提取出自己想要的數據。

這部分根據GNNS 消息格式來看。

舉個栗子:
$GPGSV,2,1,07,07,79,048,42,02,51,062,43,26,36,256,42,27,27,138,42*71

$GPGSV,2,2,07,09,23,313,42,04,19,159,41,15,12,041,42*41

循環到接收buffer里 ‘$’位置,然后為信息內容識別碼 GPGSV,然后就是數逗號。
最后提取想要的數據。

gps.c 代碼如下:

#include “gps.h”
#include “led.h”
#include “delay.h”
#include “usart3.h”
#include “stdio.h”
#include “stdarg.h”
#include “string.h”
#include “math.h”
//
//本程序只供學習使用,未經作者許可,不得用于其它任何用途
//ALIENTEK STM32F103開發板
//ATK-S1216F8 GPS模塊驅動代碼
//正點原子@ALIENTEK
//技術論壇:www.openedv.com
//修改日期:2015/04/11
//版本:V1.0
//版權所有,盜版必究。
//Copyright(C) 廣州市星翼電子科技有限公司 2014-2024
//All rights reserved
//

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解析
}
///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(u8 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();
}
//發送一批數據給SkyTraF8-BD,這里通過串口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];
}
}

其中字符串函數,和進制間轉換、進制和字符串間轉換有點難度。
參看:STM32開發 – 進制與字符串間的轉換

六、GPS位置拾取
舉個栗子:
gpsifo=092128.00,2948.63490,12127.56768,191218,12,0.57,0.015
對應:
時間分秒時,緯度,經度, RMC 時間日期,GGA衛星數,精度因子,VTG 方向,速度

其中,GPS精度因子大于7的GPS信息是不上報的

通過 GGA(時間、位置、定位數據)我們可以知道經緯度這些信息。
如得到的緯度和經度為:
2312.49700,11314.65422

具體參看方法:GPS經緯度的表示方法及換算

2312.49700,11314.65422
ddmm.mmmmm,dddmm.mmmmm

23°12′
0.49700′ * 60 = 29.82″

113°14′
0.65422′ * 60 = 39.25″
即:北緯N23°12′29.82″ 東經E113°14′39.25″

也可以這么算:
2312.49700,11314.65422
ddmm.mmmmm,dddmm.mmmmm

23°
12.49700′ / 60 = 0.2082833333°

113°
14.65422′ / 60 = 0.2442370000°
即:23.2082833333,113.2442370000

因此轉換為應該為:
23.2082833333,113.2442370000
打開:GPS經緯度坐標拾取

就可以定位當前的位置。
當然你也可以反向查詢當前位置的坐標地址。
參看:日常生活小技巧 – 百度地圖坐標拾取

七、UBX-CFG
需要ublox-m8030設置成GPS+北斗模式,使用SBAS衛星增強系統。

查看相關手冊
查看相關手冊:u-blox 8 / u-blox M8 Receiver Description Including Protocol Specification

查看UBX-CFG:

我們重點關注的就是兩個部分,UBX-CFG-GNSS(0x06 0x3E)和UBX-CFG-SBAS(0x06 0x16)

UBX-CFG-GNSS(0x06 0x3E)

UBX-CFG-SBAS(0x06 0x16)

UBX-CFG-NMEA(0x06 0x17)

u-center軟件使用
上面的手冊看完了,你以為這樣我就會配置了嗎?哈哈,太天真了。
我真的不會配置。。。
但是呢,u-center軟件可以配置,并得到我要的報文。

1、在菜單欄選擇Receiver->Port,選擇對應的COM口和Baudrate

2、在菜單欄選擇View->Text Console,查看相關輸出信息

輸出信息:

2、在菜單欄選擇View->Messages View,進行配置

在Messages View中找到 UBX->CFG->GNSS(GNSS Config),點擊后會出現衛星模式設置對話框,我們可以設置成GPS+BeiDou

里面的16進制碼就是我們要的報文咯,通過串口發送即可配置為GPS+北斗模式。

八、ublox-m8030設置成GPS+北斗模式和使用SBAS衛星增強系統
配置 UBX->CFG->CFG

配置 UBX->CFG->PRT
設置波特率

配置UBX->CFG->NMEA
在NMEA中選擇NMEA的版本號為V4.1,查看GBGSV信息,同時還可以顯示出北斗的SNR值

配置UBX->CFG->GNSS
設置成GPS+北斗模式和使用SBAS衛星增強系統的報文

通過查看u-center軟件可以查看定位衛星:包含GPS/BD/SBAS

串口發送代碼實現:

// UBX Protocol sync chars
#define UBX_SYNC_CHAR_1 (0xB5) // First synchronization character of UBX Protocol
#define UBX_SYNC_CHAR_2 (0x62) // Second synchronization character of UBX Protocol
#define UBX_MIN_SIZE (8) // sync-2, class-1, ID-1, size-2, crc-2
#define UBX_MAX_INCOMING_SIZE (500)
#define UBX_INVALID_INCOMING_SIZE (0xFFFF)

typedef enum /*__attribute__((__packed__)) UBX_CLASS_ID_t*/
{

UBX_CLASS_NAV = 0x01,
UBX_CLASS_RXM = 0x02,
UBX_CLASS_INF = 0x04,
UBX_CLASS_ACK = 0x05,
UBX_CLASS_CFG = 0x06,
UBX_CLASS_MON = 0x0A,
UBX_CLASS_AID = 0x0B,
UBX_CLASS_TIM = 0x0D,
} UBX_CLASS_ID;

typedef enum /*__attribute__((__packed__)) UBX_MSG_ID_t*/
{

// NAV Class
UBX_MSG_NAV_POSECEF = 0x01,
UBX_MSG_NAV_POSLLH = 0x02,
UBX_MSG_NAV_STATUS = 0x03,
UBX_MSG_NAV_DOP = 0x04,
UBX_MSG_NAV_SOL = 0x06,
UBX_MSG_NAV_VELECEF = 0x11,
UBX_MSG_NAV_VELNED = 0x12,
UBX_MSG_NAV_TIMEGPS = 0x20,
UBX_MSG_NAV_TIMEUTC = 0x21,
UBX_MSG_NAV_CLOCK = 0x22,
UBX_MSG_NAV_SVINFO = 0x30,
UBX_MSG_NAV_SBAS = 0x32,

// RXM Class
UBX_MSG_RXM_SVSI = 0x20, // SV Status Info

// ACK Class
UBX_MSG_ACK_NAK = 0x00, // Not Acknowledged
UBX_MSG_ACK_ACK = 0x01, // Acknowledged

// class CFG
UBX_CFG_PRT = 0x00, // Configure port
UBX_CFG_MSG = 0x01, // Configure Message Rate
UBX_CFG_INF = 0x02, // Configure Protocol
UBX_CFG_RST = 0x04, // Perform Reset
UBX_CFG_DAT = 0x06, // Set Standard Datum
UBX_CFG_TP = 0x07, // Configure Time Pulse
UBX_CFG_RATE = 0x08, // Configure Nav Rates
UBX_CFG_CFG = 0x09, // Save/load configuration
UBX_CFG_RXM = 0x11, // Configure Low Power Mode
UBX_CFG_ANT = 0x13, // Configure Antenna
UBX_CFG_SBAS = 0x16, // Configure SBAS
UBX_CFG_NMEA = 0x17, // Configure NMEA Protocol
UBX_CFG_USB = 0x1B, // Configure USB
UBX_CFG_TMODE = 0x1D, // Save/load configuration
UBX_CFG_NAVX5 = 0x23, // Save/load configuration
UBX_CFG_NAV5 = 0x24, // Save/load configuration
UBX_CFG_GNSS = 0x3E, // Save/load configuration

// class MON
UBX_CFG_MON_IO = 0x02, // I/O Status
UBX_CFG_MON_VER = 0x04, // HW/SW Version
UBX_CFG_MON_MSGPP = 0x06, // Message Parse/Process Status
UBX_CFG_MON_RXBUF = 0x07, // RX Buffer Status
UBX_CFG_MON_TXBUF = 0x08, // TX Buffer Status
UBX_CFG_MON_HW = 0x09, // HW Status
} UBX_MSG_ID;

/*F************************************************************************
*
* UINT16 gps_CalcChecksum()
*
* Calculate the 16 Bit checksum as defined in the UBX protocol spec.
*/
static uint16_t gps_CalcChecksum(const uint8_t *Payload, uint16_t Length)
{

uint16_t i;
uint8_t Ck_A = 0; // First Byte of Checksum
uint8_t Ck_B = 0; // Second Byte of Checksum
uint16_t Checksum = 0; // Final result
if (NULL != Payload){

for (i = 0; i < Length; i++) {

Ck_A = Ck_A + Payload[i];
Ck_B = Ck_B + Ck_A;
}
Checksum = (Ck_A<<8) | Ck_B;
}
return (Checksum);
}

static uint8_t sendUbxMessage(uint8_t ClassId, uint8_t MsgId, uint8_t *Payload, uint16_t PayloadLength)
{

static uint8_t ubxMessage[100];
uint16_t Checksum = 0xFFFF, i = 0;

if((Payload != NULL) && /*(PayloadLength > 0) && */(PayloadLength < sizeof(ubxMessage))){

// Fill in the PacketArray to be sent to I2C
// UBX_SYNC_CHAR_1 will be passed to the i2c_Write in the RegAddr field.
// The Data structure starts with CHAR2
ubxMessage[i++] = UBX_SYNC_CHAR_1;
ubxMessage[i++] = UBX_SYNC_CHAR_2;
ubxMessage[i++] = ClassId;
ubxMessage[i++] = MsgId;
ubxMessage[i++] = (uint8_t)(PayloadLength & 0xff);
ubxMessage[i++] = (uint8_t)((PayloadLength >> 8) & 0xff);
// Now the Payload
memcpy(&ubxMessage[i], Payload, PayloadLength);
i += PayloadLength;
// Finally the Checksum
{

Checksum = gps_CalcChecksum(&ubxMessage[2], PayloadLength+4); // Do not include Sync Char2. Do include Class,ID,Length,Payload
ubxMessage[i++] = (Checksum >> 8) & 0xff;
ubxMessage[i++] = Checksum & 0xff;
}
ComSendByteFra(USART2, ubxMessage, i);
return 0;
}else
return 2;
}

static uint8_t configPortGPS(uint8_t EnableNMEA)
{

Uart portID 0x1, default disable out Protocl NMEA
uint8_t PortCfgPayload[]={0x01, 0x00, 0x00, 0x00, 0xC0, 0x08, \
0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, \
0x00, 0x00, 0x00, 0x00};

if ( EnableNMEA )
{

PortCfgPayload[14] = 0x03;
}

return sendUbxMessage(UBX_CLASS_CFG,UBX_CFG_PRT, PortCfgPayload,sizeof(PortCfgPayload));
}

九、NMEA版本4.1介紹

文檔里有這樣一段話,建議希望使用NMEA協議的Beidou和/或Galieo客戶,建議使用NMEA版本4.1,因為早期版本不支持這兩個GNSS。

接下來我們需要了解一下NMEA版本4.1,如下圖所示NMEA協議消息的結構:

標識符:
NMEA標準區分GNSS的方法之一是使用雙字母消息標識符,‘Talker ID’。 u-blox接收器使用的特定Talker ID取決于設備型號和系統組態。
下表顯示了將用于各種GNSS配置的Talker ID。

NMEA 4.1及以上版本的額外字段

消息概述
使用UBX協議消息UBX-CFG-MSG配置NMEA消息時,顯示的類/ ID
應使用該表

對應的 UBX-CFG-MSG

十、衛星定位幾個重要概念
參看:衛星定位幾個重要概念

概念
1、GNSS的全稱是全球導航衛星系統(Global Navigation Satellite System),它是泛指所有的衛星導航系統,包括全球的、區域的和增強的,如美國的GPS、俄羅斯的Glonass、歐洲的Galileo、中國的北斗衛星導航系統,以及相關的增強系統,如美國的WAAS(廣域增強系統)、歐洲的EGNOS(歐洲靜地導航重疊系統)和日本的MSAS(多功能運輸衛星增強系統)等,還涵蓋在建和以后要建設的其他衛星導航系統。
2、NMEA是美國國家海洋電子協會的簡稱,是GPS導航設備統一的RTCM標準協議。北斗協議和NMEA協議的數據格式一模一樣,這兩種協議的唯一區別是協議頭不一樣,如:NMEA協議:”GPGGA“,對應的北斗協議為”BDGGA“
另外,GNGGA表示GPS與北斗混合定位,比如定位的衛星共7顆,其中5顆是GPS定位,2顆是北斗定位
3、AGPS,輔助全球衛星定位系統,是一種GPS的運行方式。它可以利用手機基地站的資訊,配合傳統GPS衛星,讓定位的速度更快。
4、GPGSA(BDGSA)、GPGSV(BDGSV);GNGGA、GNGLL、GNRMC、GNVTG

經驗分享
其中上面這段GNGGA表示GPS與北斗混合定位
困擾了我好久,我要做GPS+北斗模式定位,一開始以為可以同時獲得GPS(GPGGA)和北斗(BDGGA)的定位信息。其實是不對的,GPS與北斗混合定位其定位信息為GNGGA。

比如之前獲取的GPS信息:
(可用衛星數范圍0~12)

這里的可用衛星數范圍0~12由來:

十一、GPS飄移
什么是GPS的漂移?
用過GPS的人大概都有這種體會:當GPS終端靜止的時候,其定位坐標(經緯度)經常在變,偶爾變化還比較大,甚至還會顯示有速度。業內人士把這種現象稱為“漂移”。

其實,GPS漂移不僅在靜止的時候會產生,動態的時候也會產生,只不過漂移的程度沒那么明顯,產生的幾率小些罷了,這是GPS的一個基本特性。(至于GPS為什么會產生漂移,了解GPS的定位原理就不難解釋,在此不再詳述。)

GPS的神奇就在于不論你走到哪里,它都知道你的位置坐標。然而在實際應用中,它也會讓你感到難堪或委屈。

假如你是某單位司機,單位領導為了加強對車輛的管理,都裝了GPS監控設備,限定車輛在某段時間內只能在某個指定的區域行駛,對違反該規定的司機作出處罰。也許某天你就會收到處罰通知:某時某刻,你違反了此項規定。而你卻莫名其妙,深感委屈。如果你真的委屈了,請別怪管理人員,因為是“GPS出錯了”,GPS當時發生了漂移,漂到其他一個地方而導致了“越區行駛”!

GPS漂移現象還會導致其他更多問題,如里程統計偏差較大。車輛停在單位門口一天,卻顯示其行駛里程為十幾公里,甚至上百公里。由此可見,很多GPS應用中的問題都和“漂移現象”有關。

如果GPS漂移問題不能較好的解決,將會使越來越多的用戶對GPS產生誤解甚至懷疑,在一定程度上制約著GPS應用的推廣。

導致GPS飄移的原因
參看:GPS定位不準及產生漂移的原因詳解
參看:【GPS】導致GPS定位飄移的幾種原因

1、天氣情況
下雨天,空氣中水分多,影響了信號的傳輸。這也是為什么夏季手機信號稍弱的原因,夏季雨多潮濕,再加之高溫蒸發,使得空氣中的水分變多,從而影響GPS信號的傳輸。

2.高樓因素影響GPS接受信號
在一些高層建筑物的低層或者地下建筑,如地下停車場、地下商場、地鐵、隧道等,由于受到墻體的遮擋,室內信號衰減非常大,就形成了信號覆蓋弱點,所以造成定位不精準,誤差大等情況。

3.衛星數量
農村及偏僻地區上空安置衛星數量少,造成位置偏差大等情況。
當定位器搜索不到GPS信號而自動啟用基站定位的話,則誤差更大,范圍幾十到幾百米都有可能。

4.信號傳播過程
GPS信號從衛星向地面傳輸的過程中,會受到大氣電離層、地面建筑物、森林、水面等因素 的影響,導致GPS接受器計算出現偏差,所以會出現漂移。尤其是車輛靜止時,更容易出現飄移。博實結車載GPS的漂移一般是幾十米范圍內。

解決GPS漂移
參看:關于解決GPS定位設備:GPS靜態漂移的方法
GPS漂移是GPS應用時需要處理的問題之一,漂移主要有兩個方面,
第一, 速度過快,以至于GPS的響應時間短于當前運行速度,出現漂移;
第二, 在高大建筑密集或天氣情況不好的地方,因為GPS信號經過多次的折、反射,造成信號誤差,出現漂移。

GPS漂移的兩種表現:靜態位置漂移、速度(位置)漂移
靜態速度漂移可以解決,不動時候為零。位置漂移是屬于正常的,這是精度的問題,現在民用一般在10米以下,好的時候5米。另外測量型的精度很高,如果再用差分技術可以達到更高,不過這種產品很貴,用的少。

解決GPS漂移主要從兩方面入手:

一、 主系統的設計主要減少在近距離內對GPS信號的干擾。
二、 軟件處理。軟件處理主要集中在導航軟件處完成,導航軟件會將坐標定位在道路之內,如果GPS接收到的信號超出道路的半徑范圍將自動過濾這個數據,并根據上次的速度及方向推算出當前點的位置。

對于GPS靜態飄移,也有建議做軟件判斷:
1、檢測到的狀態為靜止時,強制速度為0
2、速度為0時,強制方向為0
3、數據中的速度值為0時,就不去更新地圖上的經緯度
4、通過比較上次定位數據的經緯度差的絕對值(同時包括時間)再來判斷是否有慢速移動
5、對于車載終端,只能通過輔助手段來解決GPS靜態飄移的問題,如通過檢查ACC鑰匙電的方法來檢測是否為靜態飄移,因為鑰匙電是關閉時,車一定是不動的,另外有些GPS模塊(UBLOX)可設置靜止模式、行走模式、汽車模式、海上模式、飛行模式,通過設置這些參數來解決漂移問題。
6、通過判斷PDOP(定位精度因子)來判斷,是否要傳當前這個定位經緯度數據,當PDOP值≥3.0時,定位精度會比較差,建議不要傳這個經緯度數據,可以再GPGSA語句獲得。
7、2D數據定位精度比較差,并且容易出現疊加飄移,所以也不建議上傳數據,也可以再GPGSA里面獲得。
8、在定位設備采用電子圍欄方式處理,連續判斷5-10次。如果該點連續判斷5-10次在設置的圍欄以外,可以確定該點確實處于移動狀態,并出電子圍欄以外,如果該點只有1次或者2次在電子圍欄以外,可以判斷該點是飄移出去的點,進行數據過濾,丟掉此點數據。

擴展:
參看:GPS漂移過濾算法
參看:計算兩個GPS坐標的距離
參看:【GPS】GPS定位原理
參看:GPS坐標轉化工具類
參看:GPS定位基本原理淺析
參看:10分鐘開發 GPS 應用,了解一下
參看:GPS精度因子
參看:NMEA data

GPS定位要求要接收至少4顆衛星的位置才能完成定位,這是因為接收機的時鐘和衛星的時鐘存在差異,所以三顆衛星計算位置,另一顆衛星用來修正誤差。

WGS84坐標系 地球坐標系,國際通用坐標系
GCJ02坐標系 火星坐標系,WGS84坐標系加密后的坐標系;Google國內地圖、高德、QQ地圖 使用
BD09坐標系 百度坐標系,GCJ02坐標系加密后的坐標系

HDOP(horizontal dilution of precision )水平分量精度因子:為緯度和經度等誤差平方和的開根號值。
DOP值的大小與GPS定位的誤差成正比,DOP值越大,定位誤差越大,定位的精度就低

獲取信號強度??
查看相關手冊,里面沒有信號強度(GPMSS),只有信噪比(GPGSV)
NMEA標準中稱為SNR(信噪比)的字段通常被稱為信號強度。 SNR是原始信號強度的間接但更有用的值。 它的范圍從0到99,并且根據NMEA標準具有dB單位,但是各個制造商發送具有不同起始編號的不同數字范圍,因此這些值本身不一定用于評估不同的單位。 給定gps中的工作值范圍通常在最低值和最高值之間顯示大約25到35的差異,但是0是特殊情況,并且可以顯示在視圖中但未被跟蹤的衛星上。
信噪比越大越好!!

原文:https://juyou.blog.csdn.net/article/details/82110535

總結

以上是生活随笔為你收集整理的GPS模块开发详解(转)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。