GPS开源项目

2023-11-16

GPS数据解析开源项目。 测试数据:

"$GNRMC,013300.00,A,2240.84105,N,11402.70763,E,0.007,,220319,,,D*69\r\n"
"$GNVTG,,T,,M,0.007,N,0.014,K,D*3A\r\n"
"$GNGGA,013300.00,2240.84105,N,11402.70763,E,2,12,0.59,70.5,M,-2.5,M,,0000*68\r\n"
"$GNGSA,A,3,10,12,14,20,25,31,32,26,29,40,41,22,1.09,0.59,0.91*1F\r\n"
"$GNGSA,A,3,74,70,73,80,69,,,,,,,,1.09,0.59,0.91*17\r\n"
"$GPGSV,4,1,16,01,00,300,,10,56,178,51,12,12,038,38,14,47,345,48*79\r\n"
"$GPGSV,4,2,16,16,00,207,,18,06,275,30,20,28,165,43,22,10,319,43*76\r\n"
"$GPGSV,4,3,16,25,46,050,47,26,29,205,44,29,13,108,45,31,50,296,52*7E\r\n"
"$GPGSV,4,4,16,32,56,010,52,40,20,257,40,41,46,237,48,42,46,123,42*77\r\n"
"$GLGSV,2,1,06,69,27,136,49,70,76,057,50,71,34,338,50,73,64,276,55*6B\r\n"
"$GLGSV,2,2,06,74,24,231,46,80,35,019,46*60\r\n"
"$GNGLL,2240.84105,N,11402.70763,E,013300.00,A,D*7C\r\n";

使用说明

主要用到gpc.cgps.h两个文件

  • gps.h: 定义了GPS的数据结构,语句ID的宏定义,ID解析开关;
  • gps.c: 实现语句的解析。

在项目中您只需要调用gps_data_parse(char* gps_src)函数,就可以获取到解析后的数据,具体使用方法请参考main.c文件。

您只需要修改gps.h文件中的两个地方,就可以完成配置:

1.以下宏定义参数需要和您的GPS数据相对应;

// 根据实际的数据修改前缀
#define PRE_GGA     "$GNGGA"
#define PRE_GLL     "$GNGLL"
#define PRE_GSA     "$GNGSA"
#define PRE_GPGSV   "$GPGSV"
#define PRE_GNGSV   "$GNGSV"
#define PRE_GLGSV   "$GLGSV"
#define PRE_RMC     "$GNRMC"
#define PRE_VTG     "$GNVTG"

2.通过以下宏定义,可以设置某个语句是否需要解析,从而减小您的代码体积。

// 语句解析控制 1:使能,0:禁用
#define ENABLE_GGA  1
#define ENABLE_GLL  1
#define ENABLE_GSA  1
#define ENABLE_GSV  1
#define ENABLE_RMC  1
#define ENABLE_VTG  1
#define ENABLE_UTC  1

注意事项

1.为确保您的正常使用,gps.h文件中的<语句解析控制>宏定义块应至少保持一项为1。

2.若是使用UTC解析,请确保ENABLE_RMCENABLE_UTC宏定义都处于 1状态。因为,UTC在解析过程中,会使用到RMC语句中的utc和time两个字段。

3.若是用到GSA和GSV两个语句,在使用完成后,请调用free(gps.gsa_data.gsa_prn)free(gps.gXgsv_data.sat_info)来释放内存。因为,这两个语句中的卫星数据个数不确定,所以需要动态分配内存。

4.为确保数据正常解析,GPS数据中的每个语句应以\r\n结束符结尾。

科普

GPS语句含义

  • GPGSV:可见卫星信息
  • GPGLL:地理定位信息
  • GPRMC:推荐最小定位信息
  • GPVTG:地面速度信息
  • GPGGA:GPS定位信息
  • GPGSA:当前卫星信息

GPRMC 最小定位信息:

例:$GPRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,,,A*50

字段0:$GPRMC,语句ID,表明该语句为Recommended Minimum Specific GPS/TRANSIT Data(RMC)推荐最小定位信息
字段1:UTC时间,hhmmss.sss格式
字段2:状态,A=定位,V=未定位
字段3:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
字段4:纬度N(北纬)或S(南纬)
字段5:经度dddmm.mmmm,度分格式(前导位数不足则补0)
字段6:经度E(东经)或W(西经)
字段7:速度,节,Knots
字段8:方位角,度
字段9:UTC日期,DDMMYY格式
字段10:磁偏角,(000 - 180)度(前导位数不足则补0)
字段11:磁偏角方向,E=东W=西
字段12:模式,A=自动,D=差分,E=估测,N=数据无效(3.0协议内容)
字段13:校验值($与*之间的数异或后的值)

GPGGA GPS定位数据

例:$GPGGA,092204.999,4250.5589,S,14718.5084,E,1,04,24.4,12.2,M,19.7,M,,0000*1F

字段0:$GPGGA,语句ID,表明该语句为Global Positioning System Fix Data(GGA)GPS定位信息
字段1:UTC 时间,hhmmss.sss,时分秒格式
字段2:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
字段3:纬度N(北纬)或S(南纬)
字段4:经度dddmm.mmmm,度分格式(前导位数不足则补0)
字段5:经度E(东经)或W(西经)
字段6:GPS状态,0=不可用(FIX NOT valid),1=单点定位(GPS FIX),2=差分定位(DGPS),3=无效PPS,4=实时差分定位(RTK FIX),5=RTK FLOAT,6=正在估算
字段7:正在使用的卫星数量(00 - 12)(前导位数不足则补0)
字段8:HDOP水平精度因子(0.5 - 99.9)
字段9:海拔高度(-9999.9 - 99999.9)
字段10:单位:M(米)
字段11:地球椭球面相对大地水准面的高度 WGS84水准面划分
字段12:WGS84水准面划分单位:M(米)
字段13:差分时间(从接收到差分信号开始的秒数,如果不是差分定位将为空)
字段14:差分站ID号0000 - 1023(前导位数不足则补0,如果不是差分定位将为空)
字段15:校验值($与*之间的数异或后的值)

GPVTG 地面速度信息

例:$GPVTG,89.68,T,,M,0.00,N,0.0,K*5F

字段0:$GPVTG,语句ID,表明该语句为Track Made Good and Ground Speed(VTG)地面速度信息
字段1:运动角度,000 - 359,(前导位数不足则补0)
字段2:T=真北参照系
字段3:运动角度,000 - 359,(前导位数不足则补0)
字段4:M=磁北参照系
字段5:水平运动速度(0.00)(前导位数不足则补0)
字段6:N=节,Knots
字段7:水平运动速度(0.00)(前导位数不足则补0)
字段8:K=公里/时,km/h
字段9:校验值($与*之间的数异或后的值)

GPGSV 可视卫星状态

例:$GPGSV,3,1,10,20,78,331,45,01,59,235,47,22,41,069,,13,32,252,45*70

字段0:$GPGSV,语句ID,表明该语句为GPS Satellites in View(GSV)可见卫星信息
字段1:本次GSV语句的总数目(1 - 3)
字段2:本条GSV语句是本次GSV语句的第几条(1 - 3)
字段3:当前可见卫星总数(00 - 12)(前导位数不足则补0)
字段4:PRN 码(伪随机噪声码)(01 - 32)(前导位数不足则补0)
字段5:卫星仰角(00 - 90)度(前导位数不足则补0)
字段6:卫星方位角(00 - 359)度(前导位数不足则补0)
字段7:信噪比(00-99)dbHz
字段8:PRN 码(伪随机噪声码)(01 - 32)(前导位数不足则补0)
字段9:卫星仰角(00 - 90)度(前导位数不足则补0)
字段10:卫星方位角(00 - 359)度(前导位数不足则补0)
字段11:信噪比(00-99)dbHz
字段12:PRN 码(伪随机噪声码)(01 - 32)(前导位数不足则补0)
字段13:卫星仰角(00 - 90)度(前导位数不足则补0)
字段14:卫星方位角(00 - 359)度(前导位数不足则补0)
字段15:信噪比(00-99)dbHz
字段16:校验值($与*之间的数异或后的值)

GPGSA 当前卫星信息

例:$GPGSA,A,3,01,20,19,13,,,,,,,,,40.4,24.4,32.2*0A

字段0:$GPGSA,语句ID,表明该语句为GPS DOP and Active Satellites(GSA)当前卫星信息
字段1:定位模式(选择2D/3D),A=自动选择,M=手动选择
字段2:定位类型,1=未定位,2=2D定位,3=3D定位
字段3:PRN码(伪随机噪声码),第1信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段4:PRN码(伪随机噪声码),第2信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段5:PRN码(伪随机噪声码),第3信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段6:PRN码(伪随机噪声码),第4信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段7:PRN码(伪随机噪声码),第5信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段8:PRN码(伪随机噪声码),第6信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段9:PRN码(伪随机噪声码),第7信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段10:PRN码(伪随机噪声码),第8信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段11:PRN码(伪随机噪声码),第9信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段12:PRN码(伪随机噪声码),第10信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段13:PRN码(伪随机噪声码),第11信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段14:PRN码(伪随机噪声码),第12信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
字段15:PDOP综合位置精度因子(0.5 - 99.9)
字段16:HDOP水平精度因子(0.5 - 99.9)
字段17:VDOP垂直精度因子(0.5 - 99.9)
字段18:校验值($与*之间的数异或后的值)

代码分析

代码较多,这里只分析RMC、GSA和GSV三个语句的。

RMC解析

RMC结构体

//RMC数据结构体(推荐定位信息数据格式)
typedef struct
{
    char utc[11];                     // UTC时间,hhmmss.sss格式
    unsigned char pos_status;         // 状态,A=定位,V=未定位
    double lat;                       // 纬度ddmm.mmmm,度分格式
    char lat_dir;                     // 纬度N(北纬)或S(南纬)
    double lon;                       // 经度dddmm.mmmm,度分格式
    char lon_dir;                     // 经度E(东经)或W(西经)
    double speed_Kn;                  // 速度
    double track_true;                // 方位角,度
    char date[7];                     // UTC日期,DDMMYY格式
    double mag_var;                   // 磁偏角,(000 - 180)度
    char var_dir;                     // 磁偏角方向,E=东W=西
    char mode_ind;                    // 模式,A=自动,D=差分,E=估测,N=数据无效(3.0协议内容)
}RMC;

RMC解析函数

// RMC数据解析
static RMC rmc_data_parse(char *rmc_data)             // 定义RMC结构体函数
{
    RMC rmc;
    unsigned char times = 0;
    char *p;
    char *s = strdup(rmc_data);                       // 将传入的数据拷贝一份,否则分割函数会影响原始数据

    // strtok遇到两个连续的分割符(,)时,无法正常切割,所以自己写了个函数,在源文件中
    p = strsplit(&s, ",");                            // 开始分割,按','切分,p为切割出来的字段
    while (p)
    {
        switch (times)                                // times记录当前切割的位置
        {
            case 1:   // UTC
                strcpy(rmc.utc, p);
                break;
            case 2:   // pos status
                rmc.pos_status = p[0];
                break;
            case 3:   // lat
                rmc.lat = strtod(p, NULL);
                break;
            case 4:   // lat dir
                rmc.lat_dir = p[0];
                break;
            case 5:   // lon
                rmc.lon = strtod(p, NULL);
                break;
            case 6:   // lon dir
                rmc.lon_dir = p[0];
                break;
            case 7:   // speen Kn
                rmc.speed_Kn = strtod(p, NULL);
                break;
            case 8:   // track true
                rmc.track_true = strtod(p, NULL);
                break;
            case 9:   // date
                strcpy(rmc.date, p);
                break;
            case 10:  // mag var
                rmc.mag_var = strtod(p, NULL);
                break;
            case 11:  // var dir
                rmc.var_dir = p[0];
                break;
            case 14:  // mode ind
                rmc.mode_ind = p[0];
                break;
            default:
                break;
        }
        p = strsplit(&s, ",");                          // 继续切割
        times++;
    }
    free(s);
    return rmc;
}

GSA解析

GSA结构体

#pragma pack(1)                       // 便于指针偏移取值
// 信道信息结构体
typedef struct
{
    unsigned char total;              // 总信道个数
    unsigned char prn_ID;             // prn信道
    unsigned char prn;                // PRN 码(伪随机噪声码)
}GSA_PRN;
#pragma pack()

//GPGSA数据结构体(当前卫星信息)
typedef struct
{
    unsigned char mode_MA;            // 定位模式(选择2D/3D),A=自动选择,M=手动选择
    unsigned char mode_123;           // 定位类型,1=未定位,2=2D定位,3=3D定位
    double pdop;                      // PDOP综合位置精度因子(0.5 - 99.9)
    double hdop;                      // HDOP水平精度因子(0.5 - 99.9)
    double vdop;                      // VDOP垂直精度因子(0.5 - 99.9)
    GSA_PRN *gsa_prn;                 // 存放信道信息
}GSA;

GSA解析函数

// 得到GSA数据中的信道信息,由于一帧GPS数据中,GSA语句的个数不一致,所以需要传入原始的GPS数据,找出所有的GSA字段
static GSA_PRN *get_prn_data(char *gps_data)
{
    GSA_PRN *gsa_prn;
    unsigned char times = 0;
    unsigned char i;
    unsigned char sentences_index = 0;  // 累计找到gsa字段的个数
    // 从语句中切割的字段
    char *p;
    // 存放拷贝的语句
    char *s;
    // 从原始数据中切割出来的字段
    char *sentences;
    // gsa语句的个数 
    int gsa_count;

    // 统计GSA字段的个数
    gsa_count = strstr_cnt(gps_data, PRE_GSA);
    
    // 根据GSA语句的个数,动态分配内存
    gsa_prn = (GSA_PRN *)malloc(sizeof(GSA_PRN) * (gsa_count * 12 + 1));
    memset(gsa_prn, 0, sizeof(GSA_PRN) * (gsa_count * 12 + 1));
    // 切割原始数据
    sentences = strtok(gps_data, "\r\n");
    while (sentences)
    {
        // 判断切割出来的语句是否是GSA语句
        if (strstr(sentences, PRE_GSA))
        {
            // 每找到一条GSA语句,就加1
            sentences_index++;
            s = strdup(sentences);
            // 开始切割语句
            p = strsplit(&s, ",");
            while (p)
            {
                if (times == 2)
                {
                    // 每条GSA语句包含12个卫星信息
                    for (i=0; i<12; i++)
                    {
                        p = strsplit(&s, ",");
                        (gsa_prn+i+(sentences_index-1)*12)->total = (unsigned char)gsa_count * 12;
                        (gsa_prn+i+(sentences_index-1)*12)->prn_ID = i + (sentences_index - 1) * 12;
                        (gsa_prn+i+(sentences_index-1)*12)->prn = (unsigned char)strtol(p, NULL, 10);
                    }
                }
                // 继续下一次语句切割
                p = strsplit(&s, ",");
                times++;
            }
            times = 0;
        }
        // 继续下一次原始数据切割
        sentences = strtok(NULL, "\r\n");
    }
    free(s);
    return gsa_prn;
}

// GSA数据解析
//gsa_data: 传入的GSA语句
//gpsdata: 传入的原始GPS数据
static GSA gsa_data_parse(char *gsa_data, char *gpsdata)
{
    GSA gsa;
    unsigned char times = 0;
    char *p;
    char *end;
    // GSA语句拷贝到s中,方便切割
    char *s = strdup(gsa_data);
    // 将原始数据拷贝一份
    char *alldata = strdup(gpsdata);

    p = strsplit(&s, ",");
    while (p)
    {
        switch (times)
        {
            case 1:   // mode_MA
                gsa.mode_MA = p[0];
                break;
            case 2:   // mode_123
                gsa.mode_123 = p[0];
                break;
            case 3:   // prn
                // 获得所有GSA语句中的PRN信息,传入原始的GPS数据
                gsa.gsa_prn = get_prn_data(alldata);
                break;
            case 15:  // pdop
                gsa.pdop = strtod(p, NULL);
                break;
            case 16:  // hdop
                gsa.hdop = strtod(p, NULL);
                break;
            case 17:  // vdop
                // 提取最后一个数据
                end = (char *)malloc(sizeof(p));
                strncpy(end, p, strlen(p)-3);
                end[strlen(p)-3] = '\0';
                gsa.vdop = strtod(end, NULL);
                free(end);
            default:
                break;
        }
        p = strsplit(&s, ",");
        times++;
    }
    free(s);
    return gsa;
}

GSV解析

GSV结构体

// 可见卫星信息结构体
typedef struct
{
    unsigned char prn;                // PRN 码(伪随机噪声码)
    unsigned char elev;               // 卫星仰角(00 - 90)度
    unsigned short azimuth;           // 卫星方位角(00 - 359)度
    unsigned char SNR;                // 信噪比
}SAT_INFO;
#pragma pack()

// GPGSV数据结构体(可见卫星信息)
typedef struct
{
    unsigned char msgs;               // 本次GSV语句的总数目(1 - 3)
    unsigned char msg;                // 本条GSV语句是本次GSV语句的第几条(1 - 3)
    unsigned char sats;               // 当前可见卫星总数(00 - 12)
    SAT_INFO *sat_info;               // 卫星信息
}GSV;

GSV解析函数

/*
 * function:  获取GSV字段中的GPS信息
 * gps_data:  最原始的GPS字符串,用于找到所有的GSV语句
 * stas:      卫星数量
 * prefix:    GSV信息字段前缀
*/
static SAT_INFO *get_sats_info(char *gps_data, unsigned char sats, char *prefix)
{
    SAT_INFO *sats_info;
    unsigned char times = 0;
    // 保存GSV语句总数
    unsigned char msgs = 0;
    // 记录当前时第几条GSV语句
    unsigned char msg = 0;
    // 存放计算完的for循环次数
    unsigned char for_times;
    unsigned char i;
    // 语句切割出来的字段
    char *p;
    // 拷贝一份语句便于切割
    char *s;
    // 从原始数据中切割出来的语句
    char *sentences;

    sats_info = (SAT_INFO *)malloc(sizeof(SAT_INFO) * (sats+1));
    memset(sats_info, 0, sizeof(SAT_INFO) * (sats+1));
    sentences = strtok(gps_data, "\r\n");
    while (sentences)
    {
        if (strstr(sentences, prefix))
        {
            s = strdup(sentences);
            p = strsplit(&s, ",");
            while (p)
            {
                switch (times)
                {
                    case 1:   // msgs
                        msgs = (unsigned char) strtol(p, NULL, 10);
                        break;
                    case 2:   // msg
                        msg = (unsigned char) strtol(p, NULL, 10);
                        break;
                    case 3:   // sat info
                        // 计算当前GSV语句卫星信息的个数,也就是for循环的次数
                        for_times = (msgs == msg) ? ((sats % 4) ? sats % 4 : 4) : 4;
                        for (i = 0; i < for_times; i++)
                        {
                            // 从第4个字段开始,每4段代表一个卫星的信息
                            p = strsplit(&s, ",");
                            (sats_info+(msg-1)*4+i)->prn = (unsigned char) strtol(p, NULL, 10);
                            p = strsplit(&s, ",");
                            (sats_info+(msg-1)*4+i)->elev = (unsigned char) strtol(p, NULL, 10);
                            p = strsplit(&s, ",");
                            (sats_info+(msg-1)*4+i)->azimuth = (unsigned short) strtol(p, NULL, 10);
                            p = strsplit(&s, ",");
                            (sats_info+(msg-1)*4+i)->SNR = (unsigned char) strtol(p, NULL, 10);
                        }
                        break;
                    default:
                        break;
                }
                p = strsplit(&s, ",");
                times++;
            }
            times = 0;
        }
        // 切割出下一个语句
        sentences = strtok(NULL, "\r\n");
    }
    free(s);
    return sats_info;
}

// GSV数据解析
// gsv_data: 传入的GSV语句,用于提取GSV语句总数和卫星总数
// gps_data: 原始的GPS数据,用于在函数get_sats_info中找到所有的GSV语句
// prefix:  GSV语句的前缀,根据不同的定位组合方式,在一组GPS数据中可能包含GPGSV、GLGSV和GNGSV,根据需要传入
static GSV gsv_data_parse(char *gsv_data, char *gps_data, char *prefix)
{
    GSV gsv;
    unsigned char times = 0;
    char *p;
    char *s = strdup(gsv_data);
    char *src_data = strdup(gps_data);

    p = strsplit(&s, ",");
    while (p)
    {
        switch (times)
        {
            case 1:   // msgs
                gsv.msgs = (unsigned char)strtol(p, NULL, 10);
                break;
            case 2:   // msg
                gsv.msg = (unsigned char)strtol(p, NULL, 10);
                break;
            case 3:   // sats
                gsv.sats = (unsigned char)strtol(p, NULL, 10);
                // 获得所有GSV语句中的卫星信息。传入原始的GPS数据,卫星总数和GSV语句的ID
                gsv.sat_info = get_sats_info(src_data, gsv.sats, prefix);
                break;
            default:
                break;
        }
        p = strsplit(&s, ",");
        times++;
    }
    free(s);
    return gsv;
}

 

以下是GPS完整的解析程序,包括:gps.h,gps.c,main.c

 

1、GPS.H

//
// Created by ihz on 2020/6/4.
//

#ifndef __GPS_H__
#define __GPS_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 根据实际的数据修改ID
#define PRE_GGA     "$GNGGA"
#define PRE_GLL     "$GNGLL"
#define PRE_GSA     "$GNGSA"
#define PRE_GPGSV   "$GPGSV"
#define PRE_GNGSV   "$GNGSV"
#define PRE_GLGSV   "$GLGSV"
#define PRE_RMC     "$GNRMC"
#define PRE_VTG     "$GNVTG"

// 语句解析控制 1:使能,0:禁用
#define ENABLE_GGA  1
#define ENABLE_GLL  1
#define ENABLE_GSA  1
#define ENABLE_GSV  1
#define ENABLE_RMC  1
#define ENABLE_VTG  1
#define ENABLE_UTC  1

#if ENABLE_GGA
// GGA字段结构体(GPS定位数据)
typedef struct
{
    char utc[11];                     // UTC时间,格式为hhmmss.sss
    double lat;                       // 纬度,格式为ddmm.mmmm
    char lat_dir;                     // 纬度半球,N或S
    double lon;                       // 经度,格式为dddmm.mmmm
    char lon_dir;                     // 经度半球,E或W
    unsigned char quality;            // 0=定位无效,1=定位有效
    unsigned char sats;               // 使用卫星数量,从00到12
    double hdop;                      // 水平精确度,0.5到99.9,单位m
    double alt;                       // 海平面的高度,-9999.9到9999.9米
    double undulation;                // 大地水准面高度,-9999.9到9999.9米
    unsigned char age;                // 差分时间
    unsigned short stn_ID;            // 差分站ID号0000 - 1023
} GGA;
#endif

#if ENABLE_GLL
// GPGLL数据结构体(地理定位信息)
typedef struct
{
    double lat;                       // 纬度,格式为ddmm.mmmm
    char lat_dir;                     // 纬度半球,N或S
    double lon;                       // 经度,格式为dddmm.mmmm
    char lon_dir;                     // 经度半球,E或W
    char utc[11];                     // UTC时间,格式为hhmmss.sss
    char data_status;                 // 状态标志位,A:有效,V无效
}GLL;
#endif

#if ENABLE_GSA
#pragma pack(1)                       // 便于指针偏移取值
// 信道信息结构体
typedef struct
{
    unsigned char total;              // 总信道个数
    unsigned char prn_ID;             // prn信道
    unsigned char prn;                // PRN 码(伪随机噪声码)
}GSA_PRN;
#pragma pack()

//GPGSA数据结构体(当前卫星信息)
typedef struct
{
    unsigned char mode_MA;            // 定位模式(选择2D/3D),A=自动选择,M=手动选择
    unsigned char mode_123;           // 定位类型,1=未定位,2=2D定位,3=3D定位
    double pdop;                      // PDOP综合位置精度因子(0.5 - 99.9)
    double hdop;                      // HDOP水平精度因子(0.5 - 99.9)
    double vdop;                      // VDOP垂直精度因子(0.5 - 99.9)
    GSA_PRN *gsa_prn;                 // 存放信道信息
}GSA;
#endif

#if ENABLE_GSV
#pragma pack(1)                       // 便于指针偏移取值
// 可见卫星信息结构体
typedef struct
{
    unsigned char prn;                // PRN 码(伪随机噪声码)
    unsigned char elev;               // 卫星仰角(00 - 90)度
    unsigned short azimuth;           // 卫星方位角(00 - 359)度
    unsigned char SNR;                // 信噪比
}SAT_INFO;
#pragma pack()

// GPGSV数据结构体(可见卫星信息)
typedef struct
{
    unsigned char msgs;               // 本次GSV语句的总数目(1 - 3)
    unsigned char msg;                // 本条GSV语句是本次GSV语句的第几条(1 - 3)
    unsigned char sats;               // 当前可见卫星总数(00 - 12)
    SAT_INFO *sat_info;               // 卫星信息
}GSV;
#endif

#if ENABLE_RMC
//RMC数据结构体(推荐定位信息数据格式)
typedef struct
{
    char utc[11];                     // UTC时间,hhmmss.sss格式
    unsigned char pos_status;         // 状态,A=定位,V=未定位
    double lat;                       // 纬度ddmm.mmmm,度分格式
    char lat_dir;                     // 纬度N(北纬)或S(南纬)
    double lon;                       // 经度dddmm.mmmm,度分格式
    char lon_dir;                     // 经度E(东经)或W(西经)
    double speed_Kn;                  // 速度
    double track_true;                // 方位角,度
    char date[7];                     // UTC日期,DDMMYY格式
    double mag_var;                   // 磁偏角,(000 - 180)度
    char var_dir;                     // 磁偏角方向,E=东W=西
    char mode_ind;                    // 模式,A=自动,D=差分,E=估测,N=数据无效(3.0协议内容)
}RMC;
#endif

#if ENABLE_VTG
//VTG数据结构体(地面速度信息)
typedef struct
{
    double track_true;                // 运动角度,000 - 359,真北参照系
    double track_mag;                 // 运动角度,000 - 359,磁北参照系
    double speed_Kn;                  // 水平运动速度(0.00),节,Knots
    double speed_Km;                  // 水平运动速度(0.00), 公里/时,km/h
}VTG;
#endif

#if ENABLE_UTC
//UTC时间结构体
typedef struct
{
    unsigned char YY;                 // 年
    unsigned char DD;                 // 日
    unsigned char MM;                 // 月
    unsigned char hh;                 // 时
    unsigned char mm;                 // 分
    unsigned char ss;                 // 秒
    unsigned short ds;                // 毫秒
}UTC;
#endif

//定义GPS结构体
typedef struct
{
#if ENABLE_GGA
    GGA gga_data;
#endif
#if ENABLE_GLL
    GLL gll_data;
#endif
#if ENABLE_GSA
    GSA gsa_data;
#endif
#if ENABLE_GSV
    GSV gpgsv_data;
    GSV gngsv_data;
    GSV glgsv_data;
#endif
#if ENABLE_RMC
    RMC rmc_data;
#endif
#if ENABLE_VTG
    VTG vtg_data;
#endif
#if ENABLE_UTC
    UTC utc;
#endif
}GPS;

GPS gps_data_parse(char* gps_src);

#endif //__GPS_H__

2.GPS.C

//
// Created by ihz on 2020/6/4.
//
#include "gps.h"

// 数据分割,可以分割两个连续的分隔符
static char* strsplit(char** stringp, const char* delim)
{
    char* start = *stringp;
    char* p;

    p = (start != NULL) ? strpbrk(start, delim) : NULL;

    if (p == NULL)
    {
        *stringp = NULL;
    }
    else
    {
        *p = '\0';
        *stringp = p + 1;
    }

    return start;
}

// 统计字符串在另一个字符串中出现的次数
static int strstr_cnt(char *str, char *substr)
{
    char *srcStr = str;
    int count = 0;

    do
    {
        srcStr = strstr(srcStr, substr);
        if(srcStr != NULL)
        {
            count++;
            srcStr = srcStr + strlen(substr);
        }
        else
        {
            break;
        }
    }while (*srcStr != '\0');

    return count;
}

#if ENABLE_GGA
// GGA数据解析
static GGA gga_data_parse(char *gga_data)
{
    GGA gga;
    unsigned char times = 0;
    char *p;
    char *end;
    char *s = strdup(gga_data);

    p = strsplit(&s, ",");
    while (p)
    {
        switch (times)
        {
            case 1:   // UTC
                strcpy(gga.utc, p);
                break;
            case 2:   // lat
                gga.lat = strtod(p, NULL);
                break;
            case 3:   // lat dir
                gga.lat_dir = p[0];
                break;
            case 4:   // lon
                gga.lon = strtod(p, NULL);
                break;
            case 5:   // lon dir
                gga.lon_dir = p[0];
                break;
            case 6:   // quality
                gga.quality = (unsigned char)strtol(p, NULL, 10);
                break;
            case 7:   // sats
                gga.sats = (unsigned char)strtol(p, NULL, 10);
                break;
            case 8:   // hdop
                gga.hdop = (unsigned char)strtol(p, NULL, 10);
                break;
            case 9:   // alt
                gga.alt = strtof(p, NULL);
                break;
            case 11:  // undulation
                gga.undulation = strtof(p, NULL);
                break;
            case 13:  // age
                gga.age = (unsigned char)strtol(p, NULL, 10);
                break;
            case 14:  // stn_ID
                end = (char *)malloc(sizeof(p));
                strncpy(end, p, strlen(p)-3);
                end[strlen(p)-3] = '\0';
                gga.stn_ID = (unsigned short )strtol(end, NULL, 10);
                free(end);
                break;
            default:
                break;
        }
        p = strsplit(&s, ",");
        times++;
    }
    free(s);
    return gga;
}
#endif

#if ENABLE_GLL
// GLL数据解析
static GLL gll_data_parse(char *gll_data)
{
    GLL gll;
    unsigned char times = 0;
    char *p;
    char *s = strdup(gll_data);

    p = strsplit(&s, ",");
    while (p)
    {
        switch (times)
        {
            case 1:   // lat
                gll.lat = strtod(p, NULL);
                break;
            case 2:   // lat dir
                gll.lat_dir = p[0];
                break;
            case 3:   // lon
                gll.lon = strtod(p, NULL);
                break;
            case 4:   // lon dir
                gll.lon_dir = p[0];
                break;
            case 5:   // lon dir
                strcpy(gll.utc, p);
                break;
            case 6:  // data status
                gll.data_status = p[0];
                break;
            default:
                break;
        }
        p = strsplit(&s, ",");
        times++;
    }
    free(s);
    return gll;
}
#endif

#if ENABLE_GSA
// 得到GSA数据中的信道信息
static GSA_PRN *get_prn_data(char *gps_data)
{
    GSA_PRN *gsa_prn;
    unsigned char times = 0;
    unsigned char i;
    unsigned char sentences_index = 0;  // 累计找到gsa字段的个数
    char *p;
    char *s;
    char *sentences;
    int gsa_count;

    // 统计GSA字段的个数
    gsa_count = strstr_cnt(gps_data, PRE_GSA);

    gsa_prn = (GSA_PRN *)malloc(sizeof(GSA_PRN) * (gsa_count * 12 + 1));
    memset(gsa_prn, 0, sizeof(GSA_PRN) * (gsa_count * 12 + 1));
    sentences = strtok(gps_data, "\r\n");
    while (sentences)
    {
        if (strstr(sentences, PRE_GSA))
        {
            sentences_index++;
            s = strdup(sentences);
            p = strsplit(&s, ",");
            while (p)
            {
                if (times == 2)
                {
                    for (i=0; i<12; i++)
                    {
                        p = strsplit(&s, ",");
                        (gsa_prn+i+(sentences_index-1)*12)->total = (unsigned char)gsa_count * 12;
                        (gsa_prn+i+(sentences_index-1)*12)->prn_ID = i + (sentences_index - 1) * 12;
                        (gsa_prn+i+(sentences_index-1)*12)->prn = (unsigned char)strtol(p, NULL, 10);
                    }
                }
                p = strsplit(&s, ",");
                times++;
            }
            times = 0;
        }
        sentences = strtok(NULL, "\r\n");
    }
    free(s);
    return gsa_prn;
}

// GSA数据解析
static GSA gsa_data_parse(char *gsa_data, char *gpsdata)
{
    GSA gsa;
    unsigned char times = 0;
    char *p;
    char *end;
    char *s = strdup(gsa_data);
    char *alldata = strdup(gpsdata);

    p = strsplit(&s, ",");
    while (p)
    {
        switch (times)
        {
            case 1:   // mode_MA
                gsa.mode_MA = p[0];
                break;
            case 2:   // mode_123
                gsa.mode_123 = p[0];
                break;
            case 3:   // prn
                gsa.gsa_prn = get_prn_data(alldata);
                break;
            case 15:  // pdop
                gsa.pdop = strtod(p, NULL);
                break;
            case 16:  // hdop
                gsa.hdop = strtod(p, NULL);
                break;
            case 17:  // vdop
                end = (char *)malloc(sizeof(p));
                strncpy(end, p, strlen(p)-3);
                end[strlen(p)-3] = '\0';
                gsa.vdop = strtod(end, NULL);
                free(end);
            default:
                break;
        }
        p = strsplit(&s, ",");
        times++;
    }
    free(s);
    return gsa;
}
#endif

#if ENABLE_RMC
// RMC数据解析
static RMC rmc_data_parse(char *rmc_data)
{
    RMC rmc;
    unsigned char times = 0;
    char *p;
    char *s = strdup(rmc_data);

    p = strsplit(&s, ",");
    while (p)
    {
        switch (times)
        {
            case 1:   // UTC
                strcpy(rmc.utc, p);
                break;
            case 2:   // pos status
                rmc.pos_status = p[0];
                break;
            case 3:   // lat
                rmc.lat = strtod(p, NULL);
                break;
            case 4:   // lat dir
                rmc.lat_dir = p[0];
                break;
            case 5:   // lon
                rmc.lon = strtod(p, NULL);
                break;
            case 6:   // lon dir
                rmc.lon_dir = p[0];
                break;
            case 7:   // speen Kn
                rmc.speed_Kn = strtod(p, NULL);
                break;
            case 8:   // track true
                rmc.track_true = strtod(p, NULL);
                break;
            case 9:   // date
                strcpy(rmc.date, p);
                break;
            case 10:  // mag var
                rmc.mag_var = strtod(p, NULL);
                break;
            case 11:  // var dir
                rmc.var_dir = p[0];
                break;
            case 14:  // mode ind
                rmc.mode_ind = p[0];
                break;
            default:
                break;
        }
        p = strsplit(&s, ",");
        times++;
    }
    free(s);
    return rmc;
}
#endif

#if ENABLE_VTG
// VTG数据解析
static VTG vtg_data_parse(char *vtg_data)
{
    VTG vtg;
    unsigned char times = 0;
    char *p;
    char *s = strdup(vtg_data);

    p = strsplit(&s, ",");
    while (p)
    {
        switch (times)
        {
            case 1:   // track true
                vtg.track_true = strtod(p, NULL);
                break;
            case 3:   // track mag
                vtg.track_mag = strtod(p, NULL);
                break;
            case 5:   // speed Kn
                vtg.speed_Kn = strtod(p, NULL);
                break;
            case 7:   // speed Km
                vtg.speed_Km = strtod(p, NULL);
                break;
            default:
                break;
        }
        p = strsplit(&s, ",");
        times++;
    }
    free(s);
    return vtg;
}
#endif

#if ENABLE_GSV
/*
 * function:  获取GSV字段中的GPS信息
 * gps_data:  最原始的GPS字符串
 * stas:      卫星数量
 * prefix:    GSV信息字段前缀
*/
static SAT_INFO *get_sats_info(char *gps_data, unsigned char sats, char *prefix)
{
    SAT_INFO *sats_info;
    unsigned char times = 0;
    unsigned char msgs = 0;
    unsigned char msg = 0;
    unsigned char for_times;
    unsigned char i;
    char *p;
    char *s;
    char *sentences;

    sats_info = (SAT_INFO *)malloc(sizeof(SAT_INFO) * (sats+1));
    memset(sats_info, 0, sizeof(SAT_INFO) * (sats+1));
    sentences = strtok(gps_data, "\r\n");
    while (sentences)
    {
        if (strstr(sentences, prefix))
        {
            s = strdup(sentences);
            p = strsplit(&s, ",");
            while (p)
            {
                switch (times)
                {
                    case 1:   // msgs
                        msgs = (unsigned char) strtol(p, NULL, 10);
                        break;
                    case 2:   // msg
                        msg = (unsigned char) strtol(p, NULL, 10);
                        break;
                    case 3:   // sat info
                        for_times = (msgs == msg) ? ((sats % 4) ? sats % 4 : 4) : 4;
                        for (i = 0; i < for_times; i++)
                        {
                            p = strsplit(&s, ",");
                            (sats_info+(msg-1)*4+i)->prn = (unsigned char) strtol(p, NULL, 10);
                            p = strsplit(&s, ",");
                            (sats_info+(msg-1)*4+i)->elev = (unsigned char) strtol(p, NULL, 10);
                            p = strsplit(&s, ",");
                            (sats_info+(msg-1)*4+i)->azimuth = (unsigned short) strtol(p, NULL, 10);
                            p = strsplit(&s, ",");
                            (sats_info+(msg-1)*4+i)->SNR = (unsigned char) strtol(p, NULL, 10);
                        }
                        break;
                    default:
                        break;
                }
                p = strsplit(&s, ",");
                times++;
            }
            times = 0;
        }
        sentences = strtok(NULL, "\r\n");
    }
    free(s);
    return sats_info;
}

// GSV数据解析
static GSV gsv_data_parse(char *gsv_data, char *gps_data, char *prefix)
{
    GSV gsv;
    unsigned char times = 0;
    char *p;
    char *s = strdup(gsv_data);
    char *src_data = strdup(gps_data);

    p = strsplit(&s, ",");
    while (p)
    {
        switch (times)
        {
            case 1:   // msgs
                gsv.msgs = (unsigned char)strtol(p, NULL, 10);
                break;
            case 2:   // msg
                gsv.msg = (unsigned char)strtol(p, NULL, 10);
                break;
            case 3:   // sats
                gsv.sats = (unsigned char)strtol(p, NULL, 10);
                gsv.sat_info = get_sats_info(src_data, gsv.sats, prefix);
                break;
            default:
                break;
        }
        p = strsplit(&s, ",");
        times++;
    }
    free(s);
    return gsv;
}
#endif

#if ENABLE_UTC
// UTC数据解析
static UTC utc_parse(char *date, char *time)
{
    UTC utc_data;
    unsigned int date_int;
    double time_float;

    date_int = (unsigned int)strtol(date, NULL, 10);
    utc_data.DD = date_int / 10000;
    utc_data.MM = date_int % 10000 / 100;
    utc_data.YY = date_int % 100;
    time_float = strtod(time, NULL);
    utc_data.hh = (unsigned int)time_float / 10000;
    utc_data.mm = (unsigned int)time_float % 10000 / 100;
    utc_data.ss = (unsigned int)time_float % 100;
    utc_data.ds = (unsigned short)(time_float - (unsigned int)time_float);

    return utc_data;
}
#endif

// 解析全部的GPS数据
GPS gps_data_parse(char* gps_src)
{
    GPS gps_all;
    char *str_buffer = strdup(gps_src);

    // GGA数据解析
#if ENABLE_GGA
    GGA default_gga_data = {"\0",0.0,'N',0.0,'S',0,0,0,0,0,0,0};
    gps_src = strdup(str_buffer);
    gps_all.gga_data = strstr(gps_src, PRE_GGA) ? gga_data_parse(strtok(strstr(gps_src, PRE_GGA), "\r\n")) : default_gga_data;
#endif

    // GLL数据解析
#if ENABLE_GLL
    GLL default_gll_data = {0.0,'\0',0.0,'\0',"\0",'\0'};
    gps_src = strdup(str_buffer);
    gps_all.gll_data = strstr(gps_src, PRE_GLL) ? gll_data_parse(strtok(strstr(gps_src, PRE_GLL), "\r\n")) : default_gll_data;
#endif

    // GSA数据解析
#if ENABLE_GSA
    GSA_PRN default_gsa_prn_data = {0,0,0};
    GSA default_gsa_data = {'\0','\0',0.0,0.0,0.0,&default_gsa_prn_data};
    gps_src = strdup(str_buffer);
    gps_all.gsa_data = strstr(gps_src, PRE_GSA) ? gsa_data_parse(strtok(strstr(gps_src, PRE_GSA), "\r\n"), str_buffer) : default_gsa_data;
#endif

    // RMC数据解析
#if ENABLE_RMC
    RMC default_rmc_data = {"\0",'\0',0.0,'\0',0.0,'\0',0.0,0.0,"\0",0.0,'\0','\0'};
    gps_src = strdup(str_buffer);
    gps_all.rmc_data = strstr(gps_src, PRE_RMC) ? rmc_data_parse(strtok(strstr(gps_src, PRE_RMC), "\r\n")) : default_rmc_data;
#endif

    // VTG数据解析
#if ENABLE_VTG
    VTG default_vtg_data = {0.0,0.0,0.0,0.0};
    gps_src = strdup(str_buffer);
    gps_all.vtg_data = strstr(gps_src, PRE_VTG) ? vtg_data_parse(strtok(strstr(gps_src, PRE_VTG), "\r\n")) : default_vtg_data;
#endif

    // GSV数据解析
#if ENABLE_GSV
    SAT_INFO default_sat_info_data = {0,0,0,0};
    GSV default_gsv_data = {0,0,0,&default_sat_info_data};
    // GPGSV数据段解析
    gps_src = strdup(str_buffer);
    gps_all.gpgsv_data = strstr(gps_src, PRE_GPGSV) ? gsv_data_parse(strtok(strstr(gps_src, PRE_GPGSV), "\r\n"), str_buffer, PRE_GPGSV) : default_gsv_data;
    // GNGSV数据段解析
    gps_src = strdup(str_buffer);
    gps_all.gngsv_data = strstr(gps_src, PRE_GNGSV) ? gsv_data_parse(strtok(strstr(gps_src, PRE_GNGSV), "\r\n"), str_buffer, PRE_GNGSV) : default_gsv_data;
    // GLGSV数据段解析
    gps_src = strdup(str_buffer);
    gps_all.glgsv_data = strstr(gps_src, PRE_GLGSV) ? gsv_data_parse(strtok(strstr(gps_src, PRE_GLGSV), "\r\n"), str_buffer, PRE_GLGSV) : default_gsv_data;
#endif

    // UTC数据解析,UTC数据取自RMC段数据
#if ENABLE_UTC && ENABLE_RMC
    gps_all.utc = utc_parse(gps_all.rmc_data.date, gps_all.rmc_data.utc);
#endif

    free(str_buffer);
    free(gps_src);
    return gps_all;
}

3. main.c

  
#include <stdio.h>
#include "gps.h"

int main()
{
    GPS gps;
    unsigned char i;
    char gps_data[] = "$GNRMC,013300.00,A,2240.84105,N,11402.70763,E,0.007,,220319,,,D*69\r\n"
                        "$GNVTG,,T,,M,0.007,N,0.014,K,D*3A\r\n"
                        "$GNGGA,013300.00,2240.84105,N,11402.70763,E,2,12,0.59,70.5,M,-2.5,M,,0000*68\r\n"
                        "$GNGSA,A,3,10,12,14,20,25,31,32,26,29,40,41,22,1.09,0.59,0.91*1F\r\n"
                        "$GNGSA,A,3,74,70,73,80,69,,,,,,,,1.09,0.59,0.91*17\r\n"
                        "$GPGSV,4,1,16,01,00,300,,10,56,178,51,12,12,038,38,14,47,345,48*79\r\n"
                        "$GPGSV,4,2,16,16,00,207,,18,06,275,30,20,28,165,43,22,10,319,43*76\r\n"
                        "$GPGSV,4,3,16,25,46,050,47,26,29,205,44,29,13,108,45,31,50,296,52*7E\r\n"
                        "$GPGSV,4,4,16,32,56,010,52,40,20,257,40,41,46,237,48,42,46,123,42*77\r\n"
                        "$GLGSV,2,1,06,69,27,136,49,70,76,057,50,71,34,338,50,73,64,276,55*6B\r\n"
                        "$GLGSV,2,2,06,74,24,231,46,80,35,019,46*60\r\n"
                        "$GNGLL,2240.84105,N,11402.70763,E,013300.00,A,D*7C\r\n";
    gps = gps_data_parse(gps_data);

#if ENABLE_GGA
    printf("----------GGA DATA----------\n");
    printf("utc:%s\n", gps.gga_data.utc);
    printf("lat:%f\n", gps.gga_data.lat);
    printf("lat_dir:%c\n", gps.gga_data.lat_dir);
    printf("lon:%f\n", gps.gga_data.lon);
    printf("lon_dir:%c\n", gps.gga_data.lon_dir);
    printf("quality:%d\n", gps.gga_data.quality);
    printf("sats:%d\n", gps.gga_data.sats);
    printf("hdop:%f\n", gps.gga_data.hdop);
    printf("alt:%f\n", gps.gga_data.alt);
    printf("undulation:%f\n", gps.gga_data.undulation);
    printf("age:%d\n", gps.gga_data.age);
    printf("stn_ID:%d\n", gps.gga_data.stn_ID);
#endif
#if ENABLE_GLL
    printf("----------GLL DATA----------\n");
    printf("utc:%s\n", gps.gll_data.utc);
    printf("lat:%f\n", gps.gll_data.lat);
    printf("lat_dir:%c\n", gps.gll_data.lat_dir);
    printf("lon:%f\n", gps.gll_data.lon);
    printf("lon_dir:%c\n", gps.gll_data.lon_dir);
    printf("data_status:%c\n", gps.gll_data.data_status);
#endif
#if ENABLE_GSA
    printf("----------GSA DATA----------\n");
    printf("mode_MA:%c\n", gps.gsa_data.mode_MA);
    printf("mode_123:%c\n", gps.gsa_data.mode_123);
    printf("total:%d\n", gps.gsa_data.gsa_prn[0].total);
    for (i=0; i<gps.gsa_data.gsa_prn[0].total; i++)
    {
        printf("prn%d:%d\n", (i+1), gps.gsa_data.gsa_prn[i].prn);
    }
    printf("pdop:%f\n", gps.gsa_data.pdop);
    printf("hdop:%f\n", gps.gsa_data.hdop);
    printf("vdop:%f\n", gps.gsa_data.vdop);
    // gps.gsa_data.gsa_prn是动态分配的内存,用完记得释放,否则会造成内存泄漏
    free(gps.gsa_data.gsa_prn);
#endif
#if ENABLE_RMC
    printf("----------RMC DATA----------\n");
    printf("utc:%s\n", gps.rmc_data.utc);
    printf("lat:%f\n", gps.rmc_data.lat);
    printf("lat_dir:%c\n", gps.rmc_data.lat_dir);
    printf("lon:%f\n", gps.rmc_data.lon);
    printf("lon_dir:%c\n", gps.rmc_data.lon_dir);
    printf("speed_Kn:%f\n", gps.rmc_data.speed_Kn);
    printf("track_true:%f\n", gps.rmc_data.track_true);
    printf("date:%s\n", gps.rmc_data.date);
    printf("mag_var:%f\n", gps.rmc_data.mag_var);
    printf("var_dir:%c\n", gps.rmc_data.var_dir);
    printf("mode_ind:%c\n", gps.rmc_data.mode_ind);
#endif
#if ENABLE_VTG
    printf("----------VTG DATA----------\n");
    printf("track_true:%f\n", gps.vtg_data.track_true);
    printf("track_mag:%f\n", gps.vtg_data.track_mag);
    printf("speen_Kn:%f\n", gps.vtg_data.speed_Kn);
    printf("speed_Km:%f\n", gps.vtg_data.speed_Km);
#endif
#if ENABLE_GSV
    printf("----------GPGSV DATA----------\n");
    printf("msgs:%d\n", gps.gpgsv_data.msgs);
    printf("msg:%d\n", gps.gpgsv_data.msg);
    printf("sats:%d\n", gps.gpgsv_data.sats);
    for (i=0;i<gps.gpgsv_data.sats; i++)
    {
        printf("prn%d:%d\n", i+1, gps.gpgsv_data.sat_info[i].prn);
        printf("evel%d:%d\n", i+1, gps.gpgsv_data.sat_info[i].elev);
        printf("azimuth%d:%d\n", i+1, gps.gpgsv_data.sat_info[i].azimuth);
        printf("SNR%d:%d\n", i+1, gps.gpgsv_data.sat_info[i].SNR);
    }
    // 用完释放gps.gpgsv_data.sat_info内存
    if (gps.gpgsv_data.sats) free(gps.gpgsv_data.sat_info);

    printf("----------GNGSV DATA----------\n");
    printf("msgs:%d\n", gps.gngsv_data.msgs);
    printf("msg:%d\n", gps.gngsv_data.msg);
    printf("sats:%d\n", gps.gngsv_data.sats);
    for (i=0; i<gps.gngsv_data.sats; i++)
    {
        printf("prn%d:%d\n", i+1, gps.gngsv_data.sat_info[i].prn);
        printf("evel%d:%d\n", i+1, gps.gngsv_data.sat_info[i].elev);
        printf("azimuth%d:%d\n", i+1, gps.gngsv_data.sat_info[i].azimuth);
        printf("SNR%d:%d\n", i+1, gps.gngsv_data.sat_info[i].SNR);
    }
    if (gps.gngsv_data.sats) free(gps.gngsv_data.sat_info);

    printf("----------GLGSV DATA----------\n");
    printf("msgs:%d\n", gps.glgsv_data.msgs);
    printf("msg:%d\n", gps.glgsv_data.msg);
    printf("sats:%d\n", gps.glgsv_data.sats);
    for (i=0;i<gps.glgsv_data.sats; i++)
    {
        printf("prn%d:%d\n", i+1, gps.glgsv_data.sat_info[i].prn);
        printf("evel%d:%d\n", i+1, gps.glgsv_data.sat_info[i].elev);
        printf("azimuth%d:%d\n", i+1, gps.glgsv_data.sat_info[i].azimuth);
        printf("SNR%d:%d\n", i+1, gps.glgsv_data.sat_info[i].SNR);
    }
    if (gps.glgsv_data.sats) free(gps.glgsv_data.sat_info);
#endif
#if ENABLE_UTC && ENABLE_RMC
    printf("----------UTC DATA----------\n");
    printf("year:20%02d\n", gps.utc.YY);
    printf("month:%02d\n", gps.utc.MM);
    printf("date:%02d\n", gps.utc.DD);
    printf("hour:%02d\n", gps.utc.hh);
    printf("minutes:%02d\n", gps.utc.mm);
    printf("second:%02d\n", gps.utc.ss);
    printf("ds:%02d\n", gps.utc.ds);
#endif
    return 0;
}

https://github.com/iE-zhi/NMEA_GPS_parse

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GPS开源项目 的相关文章

  • Android 手机和模拟器中的mapView不同

    关于应用程序 这是一个简单的应用程序 可以查找用户当前位置 问题 该应用程序在模拟器上运行良好 请参见图片 但在手机中它没有显示MapView 请看图片 请告诉我手机出了什么问题 在手机中 它只下载巨大的 20 MB 数据 但不显示实际地图
  • 如何通过 GPS 检查距 x,y 位置 10 米的半径

    我从 GPS 得到这个位置 40 715192 74 005795 如何判断i是否在10米半径范围内 提前致谢 使用半正矢公式http en wikipedia org wiki Haversine formula http en wiki
  • 如何在 JavaScript 中查找到已知位置的距离

    在浏览器中使用 JavaScript 如何确定从我当前位置到另一个我有纬度和经度的位置的距离 如果您的代码在浏览器中运行 您可以使用 HTML5 地理定位 API window navigator geolocation getCurren
  • 如何停止位置管理器?

    不知道为什么 但有时 LocationManager 在关闭应用程序后仍然工作 我在一个 Activity 的 onCreate Methode 中调用 startGPS 只有一个 让我称之为 StartActivity protected
  • 通过js获取WebView中的位置

    我正在尝试创建 WebView 它将通过 js 获取 GPS 本地化 但是当我单击应该显示本地化的按钮时 在android 4 1 1 模拟器 中 错误代码2 无法启动地理定位服务 在 android 4 1 2 phone 中什么也没有发
  • 位置侦听器从服务工作,但不是 IntentService

    我有一个应用程序 我试图定期获取用户位置并将其发送到服务器 我有一项服务附加到AlarmManager每分钟执行一次 用于测试 该服务正确找到用户位置并注销 GPS 坐标 一旦出现 GPS 锁定 我就会取消位置请求并停止服务 当我请求位置更
  • C#:GPS跟踪系统[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 如何在 C net 中构建带有移动设备 带 GPS 的 GPS 跟踪系统 场景是 通过支持 GPS 的手机跟踪用户 服务工程师 这里没
  • 设置模拟位置时 GPS 提供商未知错误?

    我正在尝试设置我的模拟位置 但是 我收到以下错误 提供商 gps 未知 并且不确定出了什么问题 我已经获得了在manifest xml 中声明的所有权限以及所有参数 模拟定位法 Initiates the method to set the
  • 如何通过 GPRS 向 GPS 追踪器(TK103、GT02、GT06、TK102 等)发送命令

    这已经被问过这里https stackoverflow com questions 25460743 gps tracker tk103 how to send message through server https stackoverf
  • 使用 GPS 获取 Android 手机的位置

    我还有一个关于基本 Android 编程的问题 如何访问 GPS 来获取运行应用程序的手机的当前位置 检索信息需要多长时间 在这种情况下 GPS 可能被禁用 如何再次启用 禁用它 必须在 andorid 清单中授予哪些权限 问候并感谢您的回
  • Android 中如何在不使用 getLastKnownLocation 方法的情况下获取当前的纬度和经度?

    我正在尝试获取current手机的位置 为此我使用GPS追踪器教程 http www androidhive info 2012 07 android gps location manager tutorial 问题总是使用该方法getLa
  • 从 GPS 坐标获取城市名称

    我想从 GPS 坐标获取城市的名称 我可以使用 Google API 获取 GPS 点的详细信息 http maps googleapis com maps api geocode output parameters 输出是 XML 但我不
  • 使用纬度/经度计算从 A 点到线段的距离

    我正在开发一个使用 GPS 的 Android 应用程序 我想知道如果 新位置 C 点 距离线段 AB 太远 是否有办法可以丢弃 GPS 位置数据 我正在使用发现的点到线段公式在维基百科上 http en wikipedia org wik
  • 谷歌地图定位是如何工作的?

    我的问题是谷歌地图或移动 GPS 如何找到我的当前位置 读完本文后我的高层次理解article http www physics org article questions asp id 55就是 GPS接收器通过这些卫星获取位置坐标 该位
  • PWA 可以访问联系人、GPS 或使用手机摄像头吗?

    PWA 可以访问联系人 GPS 或使用手机摄像头吗 这在任何系统 ios android 中都可能吗 是否有任何开发计划来实现这些功能 PWA 无法克服一些限制 you cannot访问电话上的联系人列表 另一方面 你can拍照并使用 GP
  • Fused Location Provider 是不错的选择吗?

    我正在开发一个应用程序 我想在其中使用融合位置提供程序 但我有一些疑问 还有几个问题 当 GPS 关闭并且我将优先级设置为 HIGH 时 是否意味着 GPS 会自动打开 我可以根据需要将 UpdateLocation 设置为具有高优先级的
  • Ruby on Rails:如何使用 TCP 套接字连接 GPS 设备

    ruby 2 3 0p0 2015 12 25 修订版 53290 x86 64 linux 轨道 4 2 4 我正在使用 cloud9 IDE 和 webrick 服务器 我的项目是实时跟踪GPS 我想使用TCP连接与GPS跟踪设备进行通
  • python:查找围绕某个 GPS 位置的圆的 GPS 坐标的优雅方法

    我有一组以十进制表示的 GPS 坐标 并且我正在寻找一种方法来查找每个位置周围半径可变的圆中的坐标 这是一个例子 http green and energy com downloads test circle html我需要什么 这是一个圆
  • 获取当前 GPS 时出现 NullPointerException

    我有一个测试屏幕 其中有一个按钮 按下它会调用该服务 我正在尝试实现一种方法来获取当前用户的当前 GPS 位置 但在尝试调用时它崩溃了 谁能告诉我问题是什么吗 package com example whereyouapp import j
  • Android 上下文不在活动中?还有其他无活动编程吗?

    我会非常努力地将其变成一个综合问题 我正在编写一个方法来获取一个包含 Android 设备城市名称的字符串 该名称由LocationManager and getLastKnownLocation 等等 然后我意识到我需要在另一个活动中再次

随机推荐

  • 【unity】【jit】【游戏开发】讲解ios系统不支持JIT的来龙去脉,以及unity在IOS上需要使用反射时候的替代方案

    标题有点长啊 很彪 所以我们叫彪题 咋地 东北地 你瞅啥 1 带有增高垫IL的c c 语言作为一种高级语言 是不能直接在我们的CPU上来直接运行的 需要编译成IL语言 Intermediate Language 即中间层语言 就是这么高冷
  • 《机器学习实战》第六章 Python3代码-(亲自修改测试可成功运行)

    由于Peter Harrington所著的这本 机器学习实战 中的官方代码是Python2版本的且有一些勘误 使用Python3的朋友运行起来会有很多问题 所以我将自己在学习过程中修改好的Python3版本代码分享给大家 以供大家交流学习
  • STM32 bool

    STM32中基于库V3 5的头文件中 去掉了对bool类型变量的定义 而将它放在了文件stdbool h中 d Keil v5 ARM ARMCC include stdbool h stdbool文件内容如下 stdbool h ISO
  • C++将字符串中包含指定字符串范围内的字符串全部替换

    概述 将指定字符串所在的范围之内的字符串全部替换为指定的字符串 如 源字符串 START dfh待到花开月圆时 两首相顾心相连 END dhussd2434xhuhu是别人十大海归 转换后的字符串 dfh待到花开月圆时 两首相顾心相连 dh
  • XXE漏洞

    何为XXE 简单来说 XXE就是XML外部实体注入 当允许引用外部实体时 通过构造恶意内容 就可能导致任意文件读取 系统命令执行 内网端口探测 攻击内网网站等危害 典型攻击手法 XML又是什么呢 XML用于标记电子文件使其具有结构性的标记语
  • 自动填充固定行数的 GridView

    效果图 代码 C lt script runat server gt 计算数据 这里可以适当修改从数据库中获取
  • Android学习一课一得

    Android学习一课一得 文章目录 引言 1 学习入门 1 1Android开发入门 1 2用户界面设计与布局 1 3数据存储与持久化 1 4网络通信与数据获取 1 5结语 2 学习成果 2 1学习经验与方法 2 2在Android应用中
  • Gym 102152(CDZSC——2020寒假大一愉悦个人赛)

    Gym 102152 A B C D E F G H I J K L http codeforces com gym 102152 A B Memory Management System It is your first day in y
  • c++实现文件版本类b+树

    一 插入 无根节点 当没有根结点时 操作相当简单 只是从存储空间中申请一个新结点 然后设置该结点的prev next is inner 然后将要插入的数据插入该结点 void insert const t var key t val v 没
  • "1,2;3,4,5;6,7,8,9" 转换成[1,2][3,4,5][6,7,8,9]

    1 2 3 4 5 6 7 8 9 转换成 1 2 3 4 5 6 7 8 9 public class Test public static void main String args String s 1 2 3 4 5 6 7 8 9
  • hduoj 2002

    计算球体积 Problem Description 根据输入的半径值 计算球的体积 Input 输入数据有多组 每组占一行 每行包括一个实数 表示球的半径 Output 输出对应的球的体积 对于每组输入数据 输出一行 计算结果保留三位小数
  • Unity报错之【NullReferenceException: Object reference not set to an instance of an object】

    空指针错误 Object并没有作为一个对象的实例 一般都是引用类型的变量没有实例化便使用变量进行一些实例对象才能进行的操作 例如list没有new实例 便对其进行添加元素 private List
  • Python中对文件的常规操作

    文章目录 一 读取文本文件数据 1 1 读文件 r 标识符 1 2 写文件 w操作 1 3 写文件 write only a操作 1 4 r 操作 1 5 w 操作 1 6 a 操作 二 读取非纯文本数据 三 指针的变化 四 上下文管理器
  • web漏洞类型概述(owasp top10笔记)

    一 owasp top10是什么 OWASP 开放式Web应用程序安全项目 OWASP Open Web Application Security Project 是一个非营利组织 不附属于任何企业或财团 它提供有关计算机和互联网应用程序的
  • 基于opencv -python--银行卡识别

    import cv2 def sort contours cnts method left to right reverse False i 0 if method right to left or method bottom to top
  • R 修改安装包默认存放位置的方法

    目录 R语言修改安装包的默认储存位置 查看默认的安装包位置 第一种方法会修改当前用户的R包位置 第二种方法 永久改变 永久有效 第三种方法 修改环境变量 总结 R语言修改安装包的默认储存位置 查看默认的安装包位置 一般会有两个目录 如下 第
  • 计算机操作系统-进程篇

    一 进程 进程 progress 是指计算机中已运行的程序 每个进程都有自己的地址空间 内存 寄存器和堆栈等资源 它们与其他进程相互隔离 互不干扰 进程是操作系统中最基本的资源分配单位 也是操作系统中最重要的概念之一 在操作系统中 进程是由
  • 动态规划:样例讲解一篇通

    概念讲解 动态规划是把大问题分解成子问题 但不能简单的分解 子问题要具有相同子结构的解 并综合子问题的解 导出大问题的解 问题求解耗时会按问题规模呈幂级数增加 基本方法 为了节约重复求相同子问题的时间 引入一个数组 不管它们是否对最终解有用
  • 运行jar包提示 “XXX中没有主清单属性” “找不到主类”两种解决办法

    运行jar包提示 XXX中没有主清单属性 找不到主类 两种解决办法 这种情况一般都是使用maven打成jar包后运行出现的 这种情况是因为jar包里面没有主类路径 解决办法有两个 1 使用IDEA自带的构建jar包流程 不使用Maven打包
  • GPS开源项目

    GPS数据解析开源项目 测试数据 GNRMC 013300 00 A 2240 84105 N 11402 70763 E 0 007 220319 D 69 r n GNVTG T M 0 007 N 0 014 K D 3A r n G