C语言实例_解析GPS源数据

一、GPS数据格式介绍

GPS(全球定位系统)数据格式常见的是NMEA 0183格式,NMEA 0183格式是一种用于导航设备间传输数据的标准格式,定义了一套规范,使得不同厂商的设备可以通过串行通信接口(常见的是RS-232)进行数据交换。这个标准最初由美国航海电子协会(National Marine Electronics Association,简称NMEA)在1980年推出,并被广泛应用于全球的导航系统。

NMEA 0183格式的数据通常以ASCII字符流的形式传输,每条数据都以$开始,以回车符(\r)和换行符(\n)结束。数据被分为不同的消息类型,每个消息类型都有特定的字段和含义。

在导航中,最常见的NMEA 0183消息类型包括:

  • GGA(Global Positioning System Fix Data):包含定位相关的信息,如纬度、经度、定位质量指示、使用卫星数量、水平定位精度因子等。
  • GLL(Geographic Position -- Latitude/Longitude):提供纬度、经度和时间信息。
  • GSA(GNSS DOP and Active Satellites):包含定位模式、使用卫星编号和位置精度因子等信息。
  • GSV(GNSS Satellites in View):提供可见卫星的信息,包括卫星编号、仰角、方位角和信噪比等。
  • RMC(Recommended Minimum Specific GNSS Data):包含定位状态、纬度、经度、地面速度、地面航向等。
  • VTG(Course Over Ground and Ground Speed):提供地面航向和速度信息。
  • ZDA(Time and Date):包含UTC时间和日期信息。

这些消息类型涵盖了定位、导航和时间相关的数据,可以用于实时定位、航行导航以及时间同步等应用。

NMEA 0183格式的数据通常由GPS接收器、导航仪、自动驾驶系统等设备产生,并通过串口输出。其他设备可以通过读取串口数据,并按照NMEA 0183的规范解析数据。这样,不同设备之间就可以进行数据交换和共享,实现设备之间的互操作性。

随着技术的发展,新一代的GPS设备也开始采用更高级的数据格式,例如NMEA 2000。然而,由于广泛应用和兼容性的要求,NMEA 0183仍然被广泛支持,并被许多设备和导航系统所使用。

下面是支持NMEA 0183格式的GPS模块输出的定位数据:

cpp 复制代码
$GNGGA,114955.000,2842.4158,N,11549.5439,E,1,05,3.8,54.8,M,0.0,M,,*4F
$GNGLL,2842.4158,N,11549.5439,E,114955.000,A,A*4D
$GPGSA,A,3,10,31,18,,,,,,,,,,5.7,3.8,4.2*37
$BDGSA,A,3,07,10,,,,,,,,,,,5.7,3.8,4.2*2A
$GPGSV,3,1,10,10,49,184,42,12,16,039,,14,54,341,,18,22,165,23*7B
$GPGSV,3,2,10,22,11,318,,25,51,055,,26,24,205,,29,13,110,*7C
$GPGSV,3,3,10,31,50,287,36,32,66,018,*7F
$BDGSV,1,1,04,03,,,07,05,,,29,07,79,246,33,10,52,232,19*62
$GNRMC,114955.000,A,2842.4158,N,11549.5439,E,0.00,44.25,061117,,,A*4D
$GNVTG,44.25,T,,M,0.00,N,0.00,K,A*14
$GNZDA,114955.000,06,11,2017,00,00*47
$GPTXT,01,01,01,ANTENNA OK*35

二、GPS字段含义

这段GPS数据是NMEA 0183格式的数据,它包含了不同类型的GPS消息,每个消息都有特定的含义和字段。

(1)$GNGGA,114955.000,2842.4158,N,11549.5439,E,1,05,3.8,54.8,M,0.0,M,,*4F 这是GGA(Global Positioning System Fix Data)消息,包含了以下关键信息:

  • 时间:11时49分55秒(UTC时间)
  • 纬度:28度42.4158分北纬
  • 经度:115度49.5439分东经
  • 定位质量指示:1(表示定位有效)
  • 使用卫星数量:5颗卫星
  • HDOP(Horizontal Dilution of Precision)水平定位精度因子:3.8
  • 海拔高度:54.8米
  • 大地水准面高度:0.0米

(2)$GNGLL,2842.4158,N,11549.5439,E,114955.000,A,A*4D 这是GLL(Geographic Position -- Latitude/Longitude)消息,包含了以下关键信息:

  • 纬度:28度42.4158分北纬
  • 经度:115度49.5439分东经
  • 时间:11时49分55秒(UTC时间)
  • 定位状态:A(表示定位有效)
  • 导航模式指示:A(自主定位导航)

(3)$GPGSA,A,3,10,31,18,,,,,,,,,,5.7,3.8,4.2*37 这是GSA(GNSS DOP and Active Satellites)消息,包含了以下关键信息:

  • 定位模式:自主定位模式
  • 定位类型:三维定位
  • 使用卫星编号:10、31、18
  • PDOP(Position Dilution of Precision)位置精度因子:5.7
  • HDOP(Horizontal Dilution of Precision)水平定位精度因子:3.8
  • VDOP(Vertical Dilution of Precision)垂直定位精度因子:4.2

(4)$BDGSA,A,3,07,10,,,,,,,,,,,5.7,3.8,4.2*2A 这是BDGSA(Beidou GNSS DOP and Active Satellites)消息,与GPGSA消息类似,但使用的是北斗导航系统的数据。

  • 消息序号:这组消息是一共分为3个消息,这是第1个消息
  • 可见卫星总数:10颗卫星
  • 卫星编号、仰角、方位角和信噪比等信息

(5)$BDGSV,1,1,04,03,,,07,05,,,29,07,79,246,33,10,52,232,19*62 这是BDGSV(Beidou GNSS Satellites in View)消息,与GPGSV消息类似,但使用的是北斗导航系统的数据。

(6)$GNRMC,114955.000,A,2842.4158,N,11549.5439,E,0.00,44.25,061117,,,A*4D 这是RMC(Recommended Minimum Specific GNSS Data)消息,包含了以下关键信息:

  • 时间:11时49分55秒(UTC时间)
  • 定位状态:A(表示定位有效)
  • 纬度:28度42.4158分北纬
  • 经度:115度49.5439分东经
  • 地面速度:0.00节
  • 地面航向:44.25度
  • 日期:06日11月17年

(7)$GNVTG,44.25,T,,M,0.00,N,0.00,K,A*14 这是VTG(Course Over Ground and Ground Speed)消息,包含了以下关键信息:

  • 地面航向:44.25度(真北参考)
  • 地面速度:0.00节(节与海里/小时是相同的)
  • 地面速度:0.00千米/小时
  • 模式指示:A(自主定位导航模式)

(8)$GNZDA,114955.000,06,11,2017,00,00*47 这是ZDA(Time and Date)消息,包含了以下关键信息:

  • UTC时间:11时49分55秒
  • 日期:06日11月17年
  • 本地时区偏移:00小时00分钟

(9)$GPTXT,01,01,01,ANTENNA OK*35 这是TXT(Text Transmission)消息,包含了以下关键信息:

  • 文本内容:ANTENNA OK(表示天线状态良好)

这些消息提供了GPS设备的时间、位置、定位质量、可见卫星数量等信息。其中涉及到的字段包括时间(UTC时间)、纬度、经度、定位质量指示、使用卫星编号、定位精度因子、海拔高度、速度等。根据不同的应用需求,可以从这些数据中提取出需要的信息来进行处理和分析。

三、C语言解析数据代码

3.1 解析每个字段数据

以下是使用C语言解析NMEA 0183数据字段并将其打印到串口:

cpp 复制代码
#include <stdio.h>
#include <string.h>
​
// 函数声明
void parseNMEA(const char* sentence);
void printField(const char* field);
​
int main() {
    // NMEA数据
    const char* data[] = {
        "$GNGGA,114955.000,2842.4158,N,11549.5439,E,1,05,3.8,54.8,M,0.0,M,,*4F",
        "$GNGLL,2842.4158,N,11549.5439,E,114955.000,A,A*4D",
        "$GPGSA,A,3,10,31,18,,,,,,,,,,5.7,3.8,4.2*37",
        "$BDGSA,A,3,07,10,,,,,,,,,,,5.7,3.8,4.2*2A",
        "$GPGSV,3,1,10,10,49,184,42,12,16,039,,14,54,341,,18,22,165,23*7B",
        "$GPGSV,3,2,10,22,11,318,,25,51,055,,26,24,205,,29,13,110,*7C",
        "$GPGSV,3,3,10,31,50,287,36,32,66,018,*7F",
        "$BDGSV,1,1,04,03,,,07,05,,,29,07,79,246,33,10,52,232,19*62",
        "$GNRMC,114955.000,A,2842.4158,N,11549.5439,E,0.00,44.25,061117,,,A*4D",
        "$GNVTG,44.25,T,,M,0.00,N,0.00,K,A*14",
        "$GNZDA,114955.000,06,11,2017,00,00*47",
        "$GPTXT,01,01,01,ANTENNA OK*35"
    };
​
    int dataSize = sizeof(data) / sizeof(data[0]);
​
    // 解析并打印每个数据
    for (int i = 0; i < dataSize; i++) {
        parseNMEA(data[i]);
    }
​
    return 0;
}
​
// 解析NMEA语句
void parseNMEA(const char* sentence) {
    const char* field;
    int count = 0;
​
    // 跳过$和逗号
    field = strchr(sentence, ',');
    if (field == NULL) {
        return;
    }
    field++;
​
    // 解析每个字段
    while (*field != '*') {
        printField(field);
​
        // 查找下一个逗号或结束符
        field = strchr(field, ',');
        if (field == NULL) {
            break;
        }
        field++;
        
        count++;
    }
}
​
// 打印字段数据
void printField(const char* field) {
    char str[50];
    int len = 0;
​
    // 查找字段的长度
    while (field[len] != ',' && field[len] != '\0' && field[len] != '*') {
        len++;
    }
​
    // 复制字段数据到缓冲区
    strncpy(str, field, len);
    str[len] = '\0';
​
    // 打印字段数据到串口
    printf("%s\n", str);
}

3.2 解析定位数据

定义了一个名为GPSData的结构体,并将解析后的定位数据存储在该结构体的各个变量中:

cpp 复制代码
#include <stdio.h>
#include <string.h>
​
// 定义结构体
typedef struct {
    char time[10];
    char latitude[10];
    char longitude[11];
    int fixStatus;
    int satellites;
    float hdop;
    float altitude;
} GPSData;
​
// 函数声明
void parseNMEA(const char* sentence, GPSData* gpsData);
void printGPSData(const GPSData* gpsData);
​
int main() {
    // NMEA数据
    const char* data[] = {
        "$GNGGA,114955.000,2842.4158,N,11549.5439,E,1,05,3.8,54.8,M,0.0,M,,*4F",
        "$GNGLL,2842.4158,N,11549.5439,E,114955.000,A,A*4D",
        "$GPGSA,A,3,10,31,18,,,,,,,,,,5.7,3.8,4.2*37",
        "$BDGSA,A,3,07,10,,,,,,,,,,,5.7,3.8,4.2*2A",
        "$GPGSV,3,1,10,10,49,184,42,12,16,039,,14,54,341,,18,22,165,23*7B",
        "$GPGSV,3,2,10,22,11,318,,25,51,055,,26,24,205,,29,13,110,*7C",
        "$GPGSV,3,3,10,31,50,287,36,32,66,018,*7F",
        "$BDGSV,1,1,04,03,,,07,05,,,29,07,79,246,33,10,52,232,19*62",
        "$GNRMC,114955.000,A,2842.4158,N,11549.5439,E,0.00,44.25,061117,,,A*4D",
        "$GNVTG,44.25,T,,M,0.00,N,0.00,K,A*14",
        "$GNZDA,114955.000,06,11,2017,00,00*47",
        "$GPTXT,01,01,01,ANTENNA OK*35"
    };
​
    int dataSize = sizeof(data) / sizeof(data[0]);
​
    // 解析并打印每个数据
    for (int i = 0; i < dataSize; i++) {
        GPSData gpsData;
        parseNMEA(data[i], &gpsData);
        printGPSData(&gpsData);
    }
​
    return 0;
}
​
// 解析NMEA语句并存储到结构体中
void parseNMEA(const char* sentence, GPSData* gpsData) {
    const char* field;
    int count = 0;
​
    // 跳过$和逗号
    field = strchr(sentence, ',');
    if (field == NULL) {
        return;
    }
    field++;
​
    // 解析每个字段
    while (*field != '*') {
        switch (count) {
            case 0:
                strncpy(gpsData->time, field, 6);
                gpsData->time[6] = '\0';
                break;
            case 1:
                strncpy(gpsData->latitude, field, 9);
                gpsData->latitude[9] = '\0';
                break;
            case 2:
                strncpy(gpsData->longitude, field, 10);
                gpsData->longitude[10] = '\0';
                break;
            case 6:
                sscanf(field, "%d", &gpsData->fixStatus);
                break;
            case 7:
                sscanf(field, "%d", &gpsData->satellites);
                break;
            case 8:
                sscanf(field, "%f", &gpsData->hdop);
                break;
            case 9:
                sscanf(field, "%f", &gpsData->altitude);
                break;
            default:
                break;
        }
​
        // 查找下一个逗号或结束符
        field = strchr(field, ',');
        if (field == NULL) {
            break;
        }
        field++;
        
        count++;
    }
}
​
// 打印GPS数据到串口
void printGPSData(const GPSData* gpsData) {
    printf("Time: %s\n", gpsData->time);
    printf("Latitude: %s\n", gpsData->latitude);
    printf("Longitude: %s\n", gpsData->longitude);
    printf("Fix Status: %d\n", gpsData->fixStatus);
    printf("Satellites: %d\n", gpsData->satellites);
    printf("HDOP: %.1f\n", gpsData->hdop);
    printf("Altitude: %.1f meters\n", gpsData->altitude);
    printf("\n");
}

这段代码会解析NMEA 0183格式的数据,并将解析的结果存储在GPSData结构体的对应变量中。使用printGPSData函数将数据打印到串口。

相关推荐
evans在进步16 小时前
Spring Boot 工程化核心详解:Parent、Starter、热部署、事务与多数据源
spring boot·后端·python
宫水三叶的刷题日记17 小时前
馋猫外卖:AI 让字节式试错没有天花板
后端
SomeB1oody18 小时前
【RustyML入门】7.4. 按需裁剪与模块化集成
开发语言·后端·机器学习·rust·教程
罗超驿18 小时前
SpringBoot 快速入门
java·spring boot·后端
卷无止境18 小时前
除了开发api,FastAPI其实也可以配合jinja2模板写页面
后端·python·fastapi
newerp18 小时前
Redis 操作与缓存策略
后端·程序员·go
newerp18 小时前
GORM ORM 基础
后端·程序员·go
小岛前端19 小时前
AI Skills 已经封神,但新的问题却越来越严重!
前端·后端·github
拖孩19 小时前
一个人 + AI 做的小程序,上线 15 天赚了 10 块 5
前端·后端·微信小程序
newerp19 小时前
CRUD 操作与预处理语句
后端·程序员·go