调试串口通过USB串口接收GPS北斗模块数据和数据说明+ ESP32的 Arduino接收与解析GPRMC报文程序
Windows USB串口接收GPS北斗模块数据和数据说明
陈拓 2022/05/07-2022/05/09
1. 简介
本文以GPS+北斗卫星定位授时导航模块HT1818Z3G5L为例,在Win10下读数据。
产品参数
引脚定义
2. 连接PC机和HT1818Z3G5L模块
如图,用CH340G USB转串口线连接PC和HT1818Z3G5L模块。
3. Win10使用CH340 USB-SERIAL串口读数据
https://blog.csdn.net/chentuo2000/article/details/112323488?spm=1001.2014.3001.5501
打开串口调试助手,设置波特率为9600,就能读到HT1818Z3G5L模块的数据了。
HT1818Z3G5L模块每秒发送一次数据。每次发送若干行组成一帧,一帧数据样例:
$GNGGA,132506.000,2233.87430,N,11407.13740,E,1,13,1.0,103.3,M,-2.8,M,,*5E
$GNGLL,2233.87430,N,11407.13740,E,132506.000,A,A*4E
$GNGSA,A,3,02,05,15,23,24,29,195,,,,,,1.6,1.0,1.3,1*07
$GNGSA,A,3,07,10,16,21,34,42,,,,,,,1.6,1.0,1.3,4*33
$GPGSV,3,1,09,02,34,134,15,05,40,044,14,15,71,308,25,18,32,326,26,0*68
$GPGSV,3,2,09,20,25,074,,23,13,293,37,24,32,174,31,29,45,251,37,0*6B
$GPGSV,3,3,09,195,50,158,31,0*6A
$BDGSV,3,1,11,03,,,28,07,13,193,27,10,14,207,32,12,,,35,0*71
$BDGSV,3,2,11,16,66,191,29,21,47,308,41,22,41,027,,34,33,309,25,0*74
$BDGSV,3,3,11,40,,,33,42,12,265,36,44,,,28,0*4B
$GNRMC,132506.000,A,2233.87430,N,11407.13740,E,0.00,244.71,080522,,,A,V*0A
$GNVTG,244.71,T,,M,0.00,N,0.00,K,A*27
$GNZDA,132506.000,08,05,2022,00,00*44
$GPTXT,01,01,01,ANTENNA OPEN*25
4. 数据格式和解析
HT1818Z3G5L模块使用NMEA-0183协议的报文,详细说明见《CASIC多模卫星导航接收机协议规范》
https://download.csdn.net/download/chentuo2000/85317996
标识符和消息名
每帧数据由若干行组成,每行从标识符和消息名开始。
$:起始符
接下来的2个字母
接下来的3个字母
数据解析
第1行
$GNGGA,132506.000,2233.87430,N,11407.13740,E,1,13,1.0,103.3,M,-2.8,M,,*5E
$GNGGA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>,<13>,*CS
GGA接收机定位数据。GN是GPS+北斗双模式
<1> 132506.000:UTC时间,hhmmss.sss(时分秒.毫秒)格式
<2> 2233.87430:纬度ddmm.mmmm(度分)格式(前导位数不足补0)
<3> N:纬度半球N(北半球)或S(南半球)
<4> 11407.13740:经度dddmm.mmmm(度分)格式(前导位数不足补0)
<5> E:经度半球E(东经)或W(西经)
<6> 1: GPS状态:0=未定位,1=非差分定位,2=差分定位,3=PPS模式
<7> 13:正在使用解算位置的卫星数量(00~24)(前导位数不足补0)
<8> 1.0:HDOP水平精度因子(0.5~99.9)
<9> 103.3:海拔高度(-9999.9~99999.9)
<10> M:高度单位
<11> -2.8:地球椭球面相对于海平面的高度
<12> M:高度单位
<13> :差分修订时间。如果不是差分定位,此项为空
<CS> *5E:校验和,$和*之间(不包括$和*)所有字符的异或结果
第2行
$GNGLL,2233.87430,N,11407.13740,E,132506.000,A,A*4E
$GNGLL,<1>,<2>,<3>,<4>,<5>,<6>,*CS
GLL地理位置-经度/纬度
<1> 2233.87430:纬度ddmm.mmmm(度分)格式(前导位数不足补0)
<2> N:纬度半球N(北半球)或S(南半球)
<3> 11407.13740:经度dddmm.mmmm(度分)格式(前导位数不足补0)
<4> E:经度半球E(东经)或W(西经)
<5> 132506.000:UTC时间,hhmmss.sss(时分秒.毫秒)格式
<6> A: 定位状态,A=定位,V=未定位
<CS> A*4E:校验和
第3行、第4行(当接收机处于多系统联合工作时,每个系统的可用卫星对应一条 GSA语句, 每条GSA语句都包含根据组合卫星系统得到的PDOP、HDOP 和VDOP。当前接收机处于GPS+BD联合工作,所有有2条GSA语句)
$GNGSA,A,3,02,05,15,23,24,29,195,,,,,,1.6,1.0,1.3,1*07
$GNGSA,A,3,07,10,16,21,34,42,,,,,,,1.6,1.0,1.3,4*33
$GNGSA,<1>,<2>,<3>,<4>~<14>,<15>,<16>,<17>,*CS
GSA精度因子与有效卫星
<1> A:定位模式,M:手动;A:自动
<2> 3:定位类型,1 无定位信息;2 二维定位;3 三维定位
<3> 02:第1信道正在使用的卫星PRN编号,01~32,最多可接收12颗卫星信息
<4>~<14> 第2信道~第12信道正在使用的卫星PRN码
<15> 1.6:PDOP综合位置精度因子,范围:0.5–99.9
<16> 1.0:HDOP水平精度因子,范围:0.5–99.9
<17> 1.3:VDOP垂直精度因子,范围:0.5–99.9
<CS> 1*07:校验和
第5行、第6行、第7行(每条GSV语句最多输出 4 颗可见卫星信息,因此,当该系统可见卫星多于4颗时,将需要多条GSV语句。)
$GPGSV,3,1,09,02,34,134,15,05,40,044,14,15,71,308,25,18,32,326,26,0*68
$GPGSV,3,2,09,20,25,074,,23,13,293,37,24,32,174,31,29,45,251,37,0*6B
$GPGSV,3,3,09,195,50,158,31,0*6A
$GPGSV,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>~<11>,<12>~<15>,<16>~<19>,*CS
GSV可见卫星
<1> 3:本次GSV语句的总数目,范围:1-3
<2> 1:当前GSV语句序号,范围:1-3
<3> 09:当前可见卫星总数
<4> 02:卫星PRN码编号,范围:01-32
<5> 34:卫星仰角,单位:度,范围:00-90
<6> 134:卫星方位角,单位:度,范围:000-359
<7> 15:信噪比,单位:dbHz,范围:00-99
<8>~<11>、<12>~<15>、<16>~<19>同<4>~<7>,共09(当前可见卫星总数)组数据
<CS> 0*68、0*6B\0*6A:校验和
第8行、第9行、第10行
$BDGSV,3,1,11,03,,,28,07,13,193,27,10,14,207,32,12,,,35,0*71
$BDGSV,3,2,11,16,66,191,29,21,47,308,41,22,41,027,,34,33,309,25,0*74
$BDGSV,3,3,11,40,,,33,42,12,265,36,44,,,28,0*4B
北斗GSV:参数说明与GPGSV相同。
第11行
$GNRMC,132506.000,A,2233.87430,N,11407.13740,E,0.00,244.71,080522,,,A,V*0A
$GNRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>,<13>,*CS
RMC推荐的最少专用导航数据
<1> 132506.000:定位点的UTC时间,hhmmss.sss(时分秒.毫秒)格式
<2> A: 定位状态,A=定位,V=未定位
<3> 2233.87430:纬度ddmm.mmmm(度分)格式(前导位数不足补0)
<4> N:纬度半球N(北半球)或S(南半球)
<5> 11407.13740:经度dddmm.mmmm(度分)格式(前导位数不足补0)
<6> E:经度半球E(东经)或W(西经)
<7> 0.00:对地航速,单位:Knots,范围:000.0-999.9
<8> 244.71:对地航向,单位:度,以真北为参考基准,二维方向指向,相当于二维罗盘
<9> 080522:定位到UTC日期,格式:ddmmyy(日月年)
<10> :磁偏角,单位:度,范围:000-180
<11> :磁偏角方向,E:东,W:西
<12> A:定位模式标志,A:自主模式,E:估算模式,N:数据无效,D:差分模式
<13> V:导航状态标志,V表示系统不输出导航状态信息
<CS> *0A:校验和
第12行
$GNVTG,244.71,T,,M,0.00,N,0.00,K,A*27
$GNVTG,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,*CS
VTG对地速度与航向
<1> 244.71:对地航向,单位:度,以真北为参考基准,二维方向指向,相当于二维罗盘
<2> T:真北参考系
<3> :磁偏角
<4> M:磁北参考系
<5> 0.00:对地航速,单位:Knots,范围:000.0-999.9
<6> N:航速单位:节
<7> 0.00:水平运动速度
<8> K:速度单位:公里/时,km/h
<CS> A*27:校验和
第13行
$GNZDA,132506.000,08,05,2022,00,00*44
$GNZDA,<1>,<2>,<3>,<4>,<5>,<6>,*CS
ZDA时间与日期
<1> 132506.000:定位时的UTC时间,hhmmss.sss(时分秒.毫秒)格式
<2> 08:日day,固定2位数字,范围:01-31
<3> 05:月month,固定2位数字,范围:01-12
<4> 2022:年year,固定4位数字
<5> 00:本时区小时,不支持,固定位00
<6> 00:本时区分钟,不支持,固定位00
<CS> *44:校验和
第14 行
$GPTXT,01,01,01,ANTENNA OPEN*25
$GPTXT,<1>,<2>,<3>,<4>,*CS
TXT天线状态
<1> 01:当前消息的语句总数01-99,如果某个消息过长,需要分为多条信息显示
<2> 01:语句编号01-99
<3> 01:文本识别符,固定位01
<4> ANTENNA OPEN:文本信息,ANTENNA OPEN=天线开路,ANTENNA OK=天线良好,ANTENNA SHORT=天线短路
<CS> *25:校验和
5. 经纬度转换及地图验证
将度.分格式转换为度的十进制
原始数据:
2233.87430:纬度ddmm.mmmm度分.分格式
11407.13740:经度dddmm.mmmm度分.分格式
转换为度的十进制
22+33.87430/60 = 22.564571666666667
114+07.13740/60 = 114.118956666666667
将度的十进制转换为百度地图格式
用百度服务器转换:
https://api.map.baidu.com/geoconv/v1/?coords=114.118956666666667, 22.564571666666667&from=1&to=5&ak=yBeph9or2paaHVyhddaCvGWQ44SSVUjA
结果:
{"status":0,"result":[{"x":114.13049746053471,"y":22.568222248485843}]}
在百度地图上验证
https://api.map.baidu.com/lbsapi/getpoint/index.html
输入坐标:
114.13049746053471,22.568222248485843
勾选坐标反查,点击放大镜按钮:
参考文档
- GPS坐标转化为百度坐标
https://blog.csdn.net/zjj084/article/details/123197553
————————————————
版权声明:本文为CSDN博主「晨之清风」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/chentuo2000/article/details/124675258
c语言 字符串转换为int或float
在c语言编程中,经常会遇到将字符串或者字符数组内的数据转换为int型数据或者float型数据,网上找了好多方法,结果都不可行,可能是C++的函数吧。在经过多方询问后,发现可以用atoi和atof函数来进行转换,具体如下:(它们都存在于<stdlib.h>中)
atoi:
atoi 是把字符串转换成int型的一个c语言函数,很方便的进行使用。
其函数参数是一个字符串,如果第一个非空格字符存在,是数字或者正负号则开始做类型转换,之后检测到非数字(包括结束符 \0) 字符时停止转换,返回整型数。否则,返回零。
例程:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int n;
char* str = "23.5";
n = atoi(str);
printf("string=%s,n=%d\n",str,n);
return0;
}
atof:
atof是把字符串转换成float型的一个c语言函数,可以很方便的进行转换。
其函数参数是一个字符串。atof()会扫描参数字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\0')才结束转换,并将结果返回。参数nptr字符串可包含正负号、小数点或E(e)来表示指数部分,如123.456或123e-2。返回值是转换后的浮点型数。
例程:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
float f;
char* str = "23.5";
f = atof(str);
printf("string=%s,f=%f\n",str,f);
return0;
}
参考具体使用用法:
atoi:http://baike.baidu.com/link?url=5NtPSd87w0FmglMzOz5_LfEqiPVzLUK9cBlAoI4audhuKZzY_RK9261M6T5vB_ipvu4B5m1YJZLjr17fbcPM3K
atof:http://baike.baidu.com/link?url=MWN9ksPFdF-mQNZ4zOQF8NifC0DcW6j5tON40_gd13w_J_-c8fdwtR7xRQCwM4Yxxkc9WSeF8C9MYuRxlA2b0a
————————————————
版权声明:本文为CSDN博主「飘飘花吹雪」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/li6727975/article/details/42875641
外接模块时测试:
外接天线放在室外无遮挡时,GPS电源过低=>电源正常时,报文变化。
[2024-07-06 21:32:32.981]# RECV ASCII> $GPTXT,01,0? [2024-07-06 21:32:33.060]# RECV ASCII> $GPTXT,01,0? [2024-07-06 21:32:34.962]# RECV ASCII> $GPTXT,01,01,02,u-blox ag - www.u-blox.com*50 $GPTXT,01,01,02,HW UBX-G60xx 00040007 FF7FFFFFp*53 $GPTXT,01,01,02,ROM CORE 7.03 (45969) Mar 17 2011 16:18:34*59 $GPTXT,01,01,02,ANTSUPERV=AC SD PDoS SR*20 $GPTXT,01,01,02,ANTSTATUS=DONTKNOW*33 $GPRMC,,V,,,,,,,,,,N*53 $GPVTG,,,,,,,,,N*30 $GPGGA,,,,,,0,00,99.99,,,,,,*48 $GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30 $GPGSV,1,1,00*79 $GPGLL,,,,,,V,N*64
报文正常时
$GPRMC,133458.00,A,3202.19619,N,11846.46919,E,0.158,,060724,,,A*7F $GPVTG,,T,,M,0.158,N,0.292,K,A*26 $GPGGA,133458.00,3202.19619,N,11846.46919,E,1,03,2.69,-2.5,M,2.4,M,,*4A $GPGSA,A,2,26,28,32,,,,,,,,,,2.87,2.69,1.00*0D $GPGSV,2,1,05,10,42,188,17,26,32,209,21,28,61,320,34,31,39,275,33*71 $GPGSV,2,2,05,32,71,051,36*4A $GPGLL,3202.19619,N,11846.46919,E,133458.00,A,A*6D
arduino esp32s3接收GPS数据并显示
#define GPS_RX_PIN 41 // 接到GPS模块TX引脚 #define GPS_UART Serial2 void setup() { Serial.begin(115200); GPS_UART.begin(9600, SERIAL_8N1, GPS_RX_PIN, -1); // -1 保持引脚不变 while (!GPS_UART) { delay(10); } Serial.println("----GPS-----"); } void loop() { while (GPS_UART.available()) { byte gpsData = GPS_UART.read(); Serial.write(gpsData); } }
arduino esp32s3接收GPS提取“$GPRMC”并显示
#include "Arduino.h" #define GPS_RX_PIN 41 // 接到GPS模块TX引脚 #define GPS_UART Serial2 void setup() { Serial.begin(115200); GPS_UART.begin(9600, SERIAL_8N1, GPS_RX_PIN, -1); // -1 保持引脚不变 while (!GPS_UART) { delay(10); } Serial.println("----GPS-----"); } String gpsString; void loop() { int Position_$ = -1; int Position_star = -1; while (GPS_UART.available()) { while (GPS_UART.available()) { byte gpsData = GPS_UART.read(); //Serial.write(gpsData); gpsString += char(gpsData); delay(1); // 按波特率计算,延时约1ms,不延时的话就会跳出while循环,因为Arduino处理速度比串口传输快多了 }; delay(10); }; if (gpsString.length() > 10) { //Serial.println(gpsString); Position_$ = gpsString.indexOf("$GPRMC"); if (Position_$ != -1) { String gpsSubString =gpsString.substring(Position_$); //从第3个数开始一直都末尾 Position_star = gpsSubString.indexOf("*"); if (Position_star != -1) { Serial.println("**$GPRMC**************"); gpsSubString =gpsSubString.substring(0, Position_star + 3); //提取"$GPRMC"完整报文 Serial.println(gpsSubString); gpsString = ""; } } } }
arduino esp32s3接收GPS提取“$GPRMC”内的时间和经纬度并显示
#include "Arduino.h" #define GPS_RX_PIN 41 // 接到GPS模块TX引脚 #define GPS_UART Serial2
void setup() { Serial.begin(115200); GPS_UART.begin(9600, SERIAL_8N1, GPS_RX_PIN, -1); // -1 保持引脚不变 while (!GPS_UART) { delay(10); } Serial.println("----GPS-----"); } String gpsString; void loop() { int Position_$ = -1; int Position_star = -1; int segment_counter; int Position_comma_start; int Position_comma_end; String gps_segments[21]; // 用字符数组存储字段信息 while (GPS_UART.available()) { while (GPS_UART.available()) { byte gpsData = GPS_UART.read(); //Serial.write(gpsData); gpsString += char(gpsData); delay(1); // 按波特率计算,延时约1ms,不延时的话就会跳出while循环,因为Arduino处理速度比串口传输快多了 }; delay(10); }; if (gpsString.length() > 100) { //举例:$GNRMC,132506.000,A,2233.87430,N,11407.13740,E,0.00,244.71,080522,,,A,V*0A //Serial.println(gpsString); Position_$ = gpsString.indexOf("$GPRMC"); if (Position_$ != -1) { String gpsSubString = gpsString.substring(Position_$); //从第Position_$字符开始一直都末尾 Position_star = gpsSubString.indexOf("*"); String xor_check = ""; if (Position_star != -1) { xor_check = gpsSubString.substring(Position_star, Position_star + 3); Serial.println(xor_check); Serial.println("**$GPRMC**************"); gpsSubString = gpsSubString.substring(0, Position_star); //提取"$GPRMC"完整报文 // 参考例:$GNRMC,132506.000,A,2233.87430,N,11407.13740,E,0.00,244.71,080522,,,A,V Serial.println(gpsSubString); for (segment_counter = 0; segment_counter < 21; segment_counter++) { //循环次数同数组gps_segments的元素个数 Position_comma_start = gpsSubString.indexOf(","); //第一个逗号(comma)位置。 if (Position_comma_start == -1) { // 无逗号,结束 Serial.println("Position_comma_start == -1"); break; //无 信息段, 退出 } gpsSubString = gpsSubString.substring(Position_comma_start + 1); //提取首个","后报文 Position_comma_end = gpsSubString.indexOf(","); //第一个逗号(comma)位置。 if (Position_comma_end == -1) { //无符号 gps_segments[segment_counter] = gpsSubString; //结束 段 Serial.println(gps_segments[segment_counter]); Serial.println("Position_comma_end == -1"); break; //无 信息段, 退出 } gps_segments[segment_counter] = gpsSubString.substring(0, Position_comma_end); //提取首个","后报文 Serial.println(String(segment_counter) + ":"); // 打印字段信息 Serial.println(gps_segments[segment_counter]); // 打印字段信息 } gpsString = ""; //提取结束,清空 //int num = str.toInt(); // 使用String类自带的toInt()函数将字符串转换为整数 } } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)