微空GPS模组出厂默认配置:UBX协议,NAV-PVT语句, 波特率115200。
协议具体内容可以参考官方协议手册,M10(M10050)和M9(M9140)的协议基本完全一致,除某个别地方。
下面提供一个可用于配置ublox模组和解析NAV-PVT语句的参考例程。
#ifndef __UBLOX_H
#define __UBLOX_H
#include <stdint.h>
#define UBLOX_SYNC1 0xB5
#define UBLOX_SYNC2 0x62
#define UBLOX_NAV_CLASS 0x01
#define UBLOX_RXM_CLASS 0x02
#define UBLOX_ACK_CLASS 0x05
#define UBLOX_CFG_CLASS 0x06
#define UBLOX_MON_CLASS 0x0a
#define UBLOX_AID_CLASS 0x0b
#define UBLOX_TIM_CLASS 0x0d
#define UBLOX_NAV_POSLLH 0x02
#define UBLOX_NAV_DOP 0x04
#define UBLOX_NAV_SOL 0x06
#define UBLOX_NAV_PVT 0x07
#define UBLOX_NAV_VALNED 0x12
#define UBLOX_NAV_TIMEUTC 0x21
#define UBLOX_NAV_SBAS 0x32
#define UBLOX_NAV_SVINFO 0x30
#define UBLOX_ACK_NAK 0x00
#define UBLOX_ACK_ACK 0x01
#define UBLOX_AID_REQ 0x00
#define UBLOX_RXM_RAW 0x10
#define UBLOX_RXM_SFRB 0x11
#define UBLOX_MON_VER 0x04
#define UBLOX_MON_HW 0x09
#define UBLOX_TIM_TP 0x01
#define UBLOX_CFG_PRT 0x00
#define UBLOX_CFG_MSG 0x01
#define UBLOX_CFG_TP 0x07
#define UBLOX_CFG_RTATE 0x08
#define UBLOX_CFG_CFG 0x09
#define UBLOX_CFG_SBAS 0x16
#define UBLOX_CFG_NAV5 0x24
#define UBLOX_MAX_PAYLOAD 256
typedef struct {
float time; //时间
double latitude; //纬度
double longitude; //经度
float altitude; //高度
float velN; //北向速度
float velE; //东向速度
float velD; //天向速度
float speed; //地面速度
float heading; //航向
float hAcc; //水平定位精度
float vAcc; //垂直定位精度
float sAcc; //速度精度
float cAcc; //航向精度
uint8_t fixed; //定位状态
uint8_t numSV; //卫星数量
} GPS_t;
enum
{
UBLOX_WAIT_SYNC1 = 0,
UBLOX_WAIT_SYNC2,
UBLOX_WAIT_CLASS,
UBLOX_WAIT_ID,
UBLOX_WAIT_LEN1,
UBLOX_WAIT_LEN2,
UBLOX_PAYLOAD,
UBLOX_CHECK1,
UBLOX_CHECK2
};
enum
{
PORTABLE = 0,
STATIONARY = 2,
PEDESTRIAN = 3,
AUTOMOTIVE = 4,
SEA = 5,
AIRBORNE_1G = 6,
AIRBORNE_2G = 7,
AIRBORNE_4G = 8
};
#pragma pack (1)
typedef struct {
uint32_t iTOW; //GPS Millisecond Time of Week ms
uint16_t year; //Year, range 1999..2099 (UTC)
uint8_t month; //Month, range 1..12 (UTC)
uint8_t day; //Day of Month, range 1..31 (UTC)
uint8_t hour; //Hour of Day, range 0..23 (UTC)
uint8_t min; //Minute of Hour, range 0..59 (UTC)
uint8_t sec; //Seconds of Minute, range 0..59 (UTC)
uint8_t valid; //Validity Flags
uint32_t tAcc; //Time Accuracy Estimate
int32_t nano; //Fraction of second, range -1e9 .. 1e9 (UTC)
uint8_t gpsFix; //GPSfix Type, range 0..5 0: no fix 1: dead reckoning only 2: 2D-fix 3: 3D-fix 4: GNSS + dead reckoning combined 5: time only fix
uint8_t flags; //Fix status flags
uint8_t flags2; //Additional flags
uint8_t numSV; //Number of SVs used in Nav Solution
int32_t lon; //Longitude
int32_t lat; //Latitude
int32_t height; //Height above Ellipsoid
int32_t hMSL; //Height above mean sea level
uint32_t hAcc; //Horizontal Accuracy Estimate
uint32_t vAcc; //Vertical Accuracy Estimate
int32_t velN; //NED north velocity cm/s
int32_t velE; //NED east velocity cm/s
int32_t velD; //NED down velocity cm/s
int32_t gSpeed; //Ground Speed (2-D) cm/s
int32_t heading; //Heading 2-D deg
uint32_t sAcc; //Speed Accuracy Estimate cm/s
uint32_t cAcc; //Course / Heading Accuracy Estimate deg
uint16_t pDOP; //Position DOP
uint8_t res1; //reserved
int32_t headVeh; //Heading of vehicle (2-D)
uint8_t res2; //reserved
} UBLOX_PVT_t;
typedef struct {
union
{
UBLOX_PVT_t pvt;
char other[UBLOX_MAX_PAYLOAD];
} payload;
uint8_t state;
uint16_t count;
uint8_t class;
uint8_t id;
uint16_t length;
uint16_t checksumErrors;
uint8_t ubloxRxCK_A;
uint8_t ubloxRxCK_B;
uint8_t ubloxTxCK_A;
uint8_t ubloxTxCK_B;
} UBLOX_RAW_t;
typedef struct {
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t min;
uint8_t sec;
} UTC_TIME_t;
#pragma pack ()
void ublox_init(void);
#endif
#include "ublox.h"
// GPS默认波特率
#define GPS_DEFAULT_BAUDRATE 115200
GPS_t gps_data;
UTC_TIME_t time;
static void ublox_parse_char(uint8_t data);
static void ublox_enable_message(uint8_t class, uint8_t id, uint8_t rate);
static void ublox_cfg_rate(uint16_t rate);
static void ublox_cfg_port(uint32_t baudrate);
static void ublox_cfg_nav5(void);
// 串口发送数据,需用户根据平台来实现该函数
void ublox_send_message(uint8_t *data, uint8_t length)
{
// 根据平台实现串口发送函数
}
// ublox数据解析函数,在串口中断或串口数据处理中调用该函数,传入串口数据
void ublox_decode(uint8_t data)
{
ublox_parse_char(data);
}
// 毫秒级延时函数,用户根据平台来实现
void delay_ms(uint32_t ms)
{
}
/**********************************************************************************************************
*函 数 名: ublox_init
*功能说明: ublox配置初始化
*形 参: 无
*返 回 值: 无
**********************************************************************************************************/
void ublox_init(void)
{
// 根据平台实现串口初始化 MG90X默认波特率为115200
// usart_init(GPS_DEFAULT_BAUDRATE);
// GPS模块上电300ms后才能进行配置
delay_ms(300);
// ublox UART端口配置
// 波特率115200
// 输入协议NMEA+UBX+RTCM
// 输出协议UBX
ublox_cfg_port(GPS_DEFAULT_BAUDRATE);
delay_ms(5);
// 配置输出速率
// 输入参数为时间间隔,单位ms
// 当输出速率>=10Hz时,ublox-m9140(MG-902/903)的导航参与卫星颗数将限制为16颗(从可见卫星中挑选信号质量最好的16颗)
// 如果想使用最大卫星数参与导航(M9为32颗),可以设置输出速率最高为8Hz
ublox_cfg_rate(125); // 125ms输出间隔
delay_ms(5);
// 导航参数配置
// AIRBORNE_2G模式(无人机推荐)
ublox_cfg_nav5();
delay_ms(5);
// 使能PVT语句输出
// PVT语句里包含了经纬度、时间、速度等等所有导航需要用的数据,所以只输出并解析这一帧就足够了
ublox_enable_message(UBLOX_NAV_CLASS, UBLOX_NAV_PVT, 1);
}
/**********************************************************************************************************
*函 数 名: ublox_payload_decode
*功能说明: ublox数据负载解析
*形 参: 输入数据
*返 回 值: 无
**********************************************************************************************************/
static void ublox_payload_decode(UBLOX_RAW_t raw_data)
{
if(raw_data.class == UBLOX_NAV_CLASS)
{
switch(raw_data.id)
{
case UBLOX_NAV_PVT:
gps_data.time = (float)raw_data.payload.pvt.iTOW / 1000;
gps_data.latitude = (double)raw_data.payload.pvt.lat * (double)1e-7; // 单位:deg
gps_data.longitude = (double)raw_data.payload.pvt.lon * (double)1e-7; // 单位:deg
gps_data.altitude = (float)raw_data.payload.pvt.hMSL * 0.001f; // 单位:m
gps_data.hAcc = (float)raw_data.payload.pvt.hAcc * 0.001f; // 单位:m
gps_data.vAcc = (float)raw_data.payload.pvt.vAcc * 0.001f; // 单位:m
gps_data.velN = (float)raw_data.payload.pvt.velN * 0.001f; // 单位:m/s
gps_data.velE = (float)raw_data.payload.pvt.velE * 0.001f; // 单位:m/s
gps_data.velD = (float)raw_data.payload.pvt.velD * 0.001f; // 单位:m/s
gps_data.speed = (float)raw_data.payload.pvt.gSpeed * 0.001f; // 单位:m/s
gps_data.heading = (float)raw_data.payload.pvt.heading * 1e-5f; // 单位:deg
gps_data.sAcc = (float)raw_data.payload.pvt.sAcc * 0.001f; // 单位:m/s
gps_data.cAcc = (float)raw_data.payload.pvt.cAcc * 1e-5f; // 单位:deg
gps_data.numSV = raw_data.payload.pvt.numSV;
gps_data.fixed = raw_data.payload.pvt.gpsFix;
time.year = raw_data.payload.pvt.year;
time.month = raw_data.payload.pvt.month;
time.day = raw_data.payload.pvt.day;
time.hour = raw_data.payload.pvt.hour;
time.min = raw_data.payload.pvt.min;
time.sec = raw_data.payload.pvt.sec;
break;
default:
break;
}
}
else if(raw_data.class == UBLOX_ACK_CLASS)
{
if(raw_data.id == UBLOX_ACK_ACK)
{
}
}
}
/**********************************************************************************************************
*函 数 名: ublox_parse_char
*功能说明: ublox协议字符串解析
*形 参: 输入数据
*返 回 值: 无
**********************************************************************************************************/
static void ublox_parse_char(uint8_t data)
{
static UBLOX_RAW_t ublox_raw;
switch (ublox_raw.state)
{
/*帧头1*/
case UBLOX_WAIT_SYNC1:
if (data == UBLOX_SYNC1)
ublox_raw.state = UBLOX_WAIT_SYNC2;
break;
/*帧头2*/
case UBLOX_WAIT_SYNC2:
if (data == UBLOX_SYNC2)
ublox_raw.state = UBLOX_WAIT_CLASS;
else
ublox_raw.state = UBLOX_WAIT_SYNC1;
break;
/*消息类型*/
case UBLOX_WAIT_CLASS:
ublox_raw.class = data;
//校验值初始化
ublox_raw.ubloxRxCK_A = 0;
ublox_raw.ubloxRxCK_B = 0;
//校验值计算
ublox_raw.ubloxRxCK_A += data;
ublox_raw.ubloxRxCK_B += ublox_raw.ubloxRxCK_A;
ublox_raw.state = UBLOX_WAIT_ID;
break;
/*消息ID*/
case UBLOX_WAIT_ID:
ublox_raw.id = data;
//校验值计算
ublox_raw.ubloxRxCK_A += data;
ublox_raw.ubloxRxCK_B += ublox_raw.ubloxRxCK_A;
ublox_raw.state = UBLOX_WAIT_LEN1;
break;
/*消息长度低8位*/
case UBLOX_WAIT_LEN1:
ublox_raw.length = data;
//校验值计算
ublox_raw.ubloxRxCK_A += data;
ublox_raw.ubloxRxCK_B += ublox_raw.ubloxRxCK_A;
ublox_raw.state = UBLOX_WAIT_LEN2;
break;
/*消息长度高8位*/
case UBLOX_WAIT_LEN2:
ublox_raw.length += (data << 8);
//校验值计算
ublox_raw.ubloxRxCK_A += data;
ublox_raw.ubloxRxCK_B += ublox_raw.ubloxRxCK_A;
if (ublox_raw.length >= (UBLOX_MAX_PAYLOAD-1))
{
ublox_raw.length = 0;
ublox_raw.state = UBLOX_WAIT_SYNC1;
}
else if (ublox_raw.length > 0)
{
ublox_raw.count = 0;
ublox_raw.state = UBLOX_PAYLOAD;
}
else
{
ublox_raw.state = UBLOX_CHECK1;
}
break;
/*消息负载*/
case UBLOX_PAYLOAD:
*((char *)(&ublox_raw.payload) + ublox_raw.count) = data;
if (++ublox_raw.count == ublox_raw.length)
{
ublox_raw.state = UBLOX_CHECK1;
}
//校验值计算
ublox_raw.ubloxRxCK_A += data;
ublox_raw.ubloxRxCK_B += ublox_raw.ubloxRxCK_A;
break;
/*CKA校验位对比*/
case UBLOX_CHECK1:
if (data == ublox_raw.ubloxRxCK_A)
{
ublox_raw.state = UBLOX_CHECK2;
}
else
{
ublox_raw.state = UBLOX_WAIT_SYNC1;
ublox_raw.checksumErrors++;
}
break;
/*CKB校验位对比*/
case UBLOX_CHECK2:
ublox_raw.state = UBLOX_WAIT_SYNC1;
if (data == ublox_raw.ubloxRxCK_B)
{
//接收完毕,解析数据负载
ublox_payload_decode(ublox_raw);
}
else
{
ublox_raw.checksumErrors++;
}
break;
default:
break;
}
}
/**********************************************************************************************************
*函 数 名: ublox_enable_message
*功能说明: 使能ublox消息输出
*形 参: 消息类型 消息id 输出速率(0表示不输出,1表示一个周期输出一次(最快),数值越大输出速率越低)
*返 回 值: 无
**********************************************************************************************************/
static void ublox_enable_message(uint8_t class, uint8_t id, uint8_t rate)
{
uint8_t data[11];
uint8_t msg_len = 11;
uint8_t ck_a = 0, ck_b = 0;
data[0] = UBLOX_SYNC1; //帧头1
data[1] = UBLOX_SYNC2; //帧头2
data[2] = UBLOX_CFG_CLASS; //消息类型
data[3] = UBLOX_CFG_MSG; //消息id
data[4] = 0x03; //消息负载长度低8位
data[5] = 0x00; //消息负载长度高8位
data[6] = class; //设置消息类型
data[7] = id; //设置消息id
data[8] = rate; //设置消息输出速率
for(uint8_t i=2; i<msg_len-2; i++)
{
ck_a += data[i];
ck_b += ck_a;
}
data[9] = ck_a;
data[10] = ck_b;
ublox_send_message(data, msg_len);
}
/**********************************************************************************************************
*函 数 名: ublox_cfg_rate
*功能说明: 设置ublox输出速率
*形 参: 输出速率(单位:ms)
*返 回 值: 无
**********************************************************************************************************/
static void ublox_cfg_rate(uint16_t rate)
{
uint8_t data[14];
uint8_t msg_len = 14;
uint8_t ck_a = 0, ck_b = 0;
data[0] = UBLOX_SYNC1; //帧头1
data[1] = UBLOX_SYNC2; //帧头2
data[2] = UBLOX_CFG_CLASS; //消息类型
data[3] = UBLOX_CFG_RTATE; //消息id
data[4] = 0x06; //消息负载长度低8位
data[5] = 0x00; //消息负载长度高8位
data[6] = (uint8_t)rate; //输出速率低八位
data[7] = (uint8_t)(rate >> 8); //输出速率高八位
data[8] = 0x01; //导航周期低八位
data[9] = 0x00; //导航周期高八位
data[10] = 0x01; //timeRef 0:UTC, 1:GPS time
data[11] = 0x00; //高八位
for(uint8_t i=2; i<msg_len-2; i++)
{
ck_a += data[i];
ck_b += ck_a;
}
data[12] = ck_a;
data[13] = ck_b;
ublox_send_message(data, msg_len);
}
/**********************************************************************************************************
*函 数 名: ublox_cfg_port
*功能说明: 设置ublox输出配置
*形 参: 波特率
*返 回 值: 无
**********************************************************************************************************/
static void ublox_cfg_port(uint32_t baudrate)
{
uint8_t data[28];
uint8_t msg_len = 28;
uint8_t ck_a = 0, ck_b = 0;
data[0] = UBLOX_SYNC1; //帧头1
data[1] = UBLOX_SYNC2; //帧头2
data[2] = UBLOX_CFG_CLASS; //消息类型
data[3] = UBLOX_CFG_PRT; //消息id
data[4] = 0x14; //消息负载长度低8位
data[5] = 0x00; //消息负载长度高8位
data[6] = 0x01; //端口号 1:uart1
data[7] = 0x00; //预留
data[8] = 0x00; //TX Ready高八位
data[9] = 0x00; //TX Ready低八位
data[10] = (uint8_t)(0x08D0); //串口配置
data[11] = (uint8_t)(0x08D0 >> 8); //8位
data[12] = (uint8_t)(0x08D0 >> 16); //1个停止位
data[13] = (uint8_t)(0x08D0 >> 24); //无校验位
data[14] = (uint8_t)(baudrate); //串口波特率
data[15] = (uint8_t)(baudrate >> 8); //
data[16] = (uint8_t)(baudrate >> 16); //
data[17] = (uint8_t)(baudrate >> 24); //
data[18] = 0x07; //输入协议配置
data[19] = 0x00; //ubx+nmea+rtcm
data[20] = 0x01; //输出协议配置
data[21] = 0x00; //ubx
data[22] = 0x00; //flags低八位
data[23] = 0x00; //flags高八位
data[24] = 0x00; //reserved
data[25] = 0x00; //reserved
for(uint8_t i=2; i<msg_len-2; i++)
{
ck_a += data[i];
ck_b += ck_a;
}
data[26] = ck_a;
data[27] = ck_b;
ublox_send_message(data, msg_len);
}
/**********************************************************************************************************
*函 数 名: ublox_cfg_nav5
*功能说明: 导航相关参数配置
*形 参: 无
*返 回 值: 无
**********************************************************************************************************/
static void ublox_cfg_nav5(void)
{
uint8_t data[44];
uint8_t msg_len = 44;
uint8_t ck_a = 0, ck_b = 0;
data[0] = UBLOX_SYNC1; //帧头1
data[1] = UBLOX_SYNC2; //帧头2
data[2] = UBLOX_CFG_CLASS; //消息类型
data[3] = UBLOX_CFG_NAV5; //消息id
data[4] = 0x24; //消息负载长度低8位
data[5] = 0x00; //消息负载长度高8位
data[6] = 0xFF; // Mask
data[7] = 0xFF; // Mask
data[8] = AIRBORNE_2G; // 动态平台模型,无人机推荐使用AIRBORNE_2G模式
data[9] = 0x03; // position fixing mode 3=auto 2D/3D
data[10] = (uint8_t)(0x00); // Fixed altitude(mean sea level) for 2D fix mode
data[11] = (uint8_t)(0x00 >> 8);
data[12] = (uint8_t)(0x00 >> 16);
data[13] = (uint8_t)(0x00 >> 24);
data[14] = (uint8_t)(10000); // Fixed altitude variance for 2D mode
data[15] = (uint8_t)(10000 >> 8);
data[16] = (uint8_t)(10000 >> 16);
data[17] = (uint8_t)(10000 >> 24);
data[18] = 0x0A; // 使用卫星的最低角度:10°
data[19] = 0x00; // drLimit
data[20] = (uint8_t)(250); // pDop
data[21] = (uint8_t)(250 >> 8);
data[22] = (uint8_t)(250); // tDop
data[23] = (uint8_t)(250 >> 8);
data[24] = (uint8_t)(100); // pAcc Mask
data[25] = (uint8_t)(100 >> 8);
data[26] = (uint8_t)(350); // tAcc Mask
data[27] = (uint8_t)(350 >> 8);
data[28] = 0; // Static hold threshold
data[29] = 60; // DGNSS timeout
data[30] = 0; // cn0ThreshNumSVs
data[31] = 25; // 参与导航的卫星所需最低C/N0
data[32] = 0; // pAccAdr
data[33] = 0;
data[34] = 0; // staticHoldMaxDist
data[35] = 0;
data[36] = 0; // utcStandard
data[37] = 0; // reserved
data[38] = 0;
data[39] = 0;
data[40] = 0;
data[41] = 0;
for(uint8_t i=2; i<msg_len-2; i++)
{
ck_a += data[i];
ck_b += ck_a;
}
data[42] = ck_a;
data[43] = ck_b;
ublox_send_message(data, msg_len);
}