NMEA 0183 · GPS数据格式

这两天买了个GPS模块回来研究,型号是GT-7U。这个模块会把GPS定位数据用NEMA-0183制定的格式通过串口发送出来。 现在记录一下我用C语言在Linux/MacOS下读取模块数据的方法。

读取数据

#include <fcntl.h>
#include <termios.h>
#include <unistd.h>

既然数据是通过串口发送的,那么读取数据也就是读取串口数据。 在Linux/MacOS下,串口是作为一个设备文件存在的,读取串口跟读取文件是一样的。在Linux/MacOS下,C语言打开文件主要有两种方法,一种是经常使用的fopen函数,另一种是open函数。fopen函数返回的叫做“文件指针”,而open返回的是“文件描述符”。fopen是C语言的标准,而open是类Unix系统下偏向底层的函数。
而串口的设备文件很明显不是一般的文件,我们读取之前要设置它的波特率等信息,而设置波特率需要用到文件描述符,所以我使用open函数打开文件。

//打开GPS模块
int fd = open("/dev/tty.usbserial", O_RDWR);
if (fd == -1)
    return perror("Open serial fail"), -1;

open函数的第一个参数是我要打开的文件的路径,表示串口的文件通常在/dev/文件夹下,在bash下用ls /dev/就能找到串口文件了。
得到文件描述符之后要设置串口的波特率,经过一番搜索 代码嘛就是这样,我从网上的代码改的。ヾ(^。^*)

//设置波特率为9600
struct termios serial;
if (tcgetattr(fd, &serial) ||
    cfsetispeed(&serial, B9600) ||
    cfsetospeed(&serial, B9600) ||
    tcsetattr(fd, TCSANOW, &serial) ||
    tcflush(fd, TCIFLUSH))
    return perror("Set serial baud rate fail"), -1;

然后还是把文件描述符转为文件指针来使用(因为后面想用fscanf函数)

FILE *file = fdopen(fd, "r+");

然后要定义一个函数读取数据

int read(FILE *file)
{
    char buff[512], cmd[4], data[512];
    int cs;//校验和

    //接收模块发来的一条数据
    fscanf(file, "%s", buff);

    if (buff[0] != '$')
        return -1; // not a frame
    if (sscanf(buff, "$GP%3s,%[^*]*%X", cmd, data, &cs) != 3)
        return -2; //not completed
    if (check_sum(buff) != cs)
        return -3; //check sum fail

    if (!strcmp(cmd, "RMC"))
        return cmd_rmc(data);

    return 1; //cmd not handle
}

校验和 用check_sum计算,它把$和*之间所有的字符进行异或运算。

int check_sum(char *data)
{
    int sum = 0;
    for (data += 1; *data != '*'; data++)
        sum ^= *data;
    return sum;
}

在这里我只读RMC指令,并用cmd_rmc函数解析。 Recommended Minimum Specific GPS/TRANSIT Data(RMC)也就是推荐定位信息, 包含了我需要的所有信息

//接收RMC数据
int cmd_rmc(char *data)
{
    printf("%s", data);
}

简便起见,这里先简单地输出数据。而实际上数据的格式是这样的:

$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>

  1. UTC时间,hhmmss(时分秒)格式
  2. 定位状态,A=有效定位,V=无效定位
  3. 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)
  4. 纬度半球N(北半球)或S(南半球)
  5. 经度dddmm.mmmm(度分)格式(前面的0也将被传输)
  6. 经度半球E(东经)或W(西经)
  7. 地面速率(000.0~999.9节,前面的0也将被传输)
  8. 地面航向(000.0~359.9度,以真北为参考基准,前面的0也将被传输)
  9. UTC日期,ddmmyy(日月年)格式
  10. 磁偏角(000.0~180.0度,前面的0也将被传输)
  11. 磁偏角方向,E(东)或W(西)
  12. 模式指示(仅NMEA0183 3.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)