电子产业一站式赋能平台

PCB联盟网

搜索
查看: 63|回复: 0
收起左侧

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

[复制链接]

317

主题

317

帖子

3149

积分

四级会员

Rank: 4

积分
3149
发表于 2024-11-14 11:51:00 | 显示全部楼层 |阅读模式
一、GPS数据格式介绍GPS(全球定位系统)数据格式常见的是NMEA 0183格式,NMEA 0183格式是一种用于导航设备间传输数据的标准格式,定义了一套规范,使得不同厂商的设备可以通过串行通信接口(常见的是RS-232)进行数据交换。这个标准最初由美国航海电子协会(National Marine Electronics Association,简称NMEA)在1980年推出,并被广泛应用于全球的导航系统。
NMEA 0183格式的数据通常以ASCII字符流的形式传输,每条数据都以$开始,以回车符(\r)和换行符(
)结束。数据被分为不同的消息类型,每个消息类型都有特定的字段和含义。
在导航中,最常见的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仍然被广泛支持,并被许多设备和导航系统所使用。

uk0qkmqift16402747401.png

uk0qkmqift16402747401.png

下面是支持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
#include
// 函数声明
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
        parseNMEA(data);
    }
    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
", str);
}
3.2 解析定位数据定义了一个名为GPSData的结构体,并将解析后的定位数据存储在该结构体的各个变量中:
cpp
#include
#include
// 定义结构体
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
        GPSData gpsData;
        parseNMEA(data, &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
", gpsData->time);
    printf("Latitude: %s
", gpsData->latitude);
    printf("Longitude: %s
", gpsData->longitude);
    printf("Fix Status: %d
", gpsData->fixStatus);
    printf("Satellites: %d
", gpsData->satellites);
    printf("HDOP: %.1f
", gpsData->hdop);
    printf("Altitude: %.1f meters
", gpsData->altitude);
    printf("
");
}
这段代码会解析NMEA 0183格式的数据,并将解析的结果存储在GPSData结构体的对应变量中。使用printGPSData函数将数据打印到串口。
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


联系客服 关注微信 下载APP 返回顶部 返回列表