调试串口通过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

勾选坐标反查,点击放大镜按钮:

参考文档

    1. 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()函数将字符串转换为整数
      }
    }
  }
}
复制代码

 

posted @   辛河  阅读(1071)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示