zoukankan      html  css  js  c++  java
  • 嵌入式Linux中GPS信息读取与处理

    GPS协议概要

    GPS模块使用的是NMEA-0183 协议,NMEA-0183 是美国国家海洋电子协会(National MarineElectronics Association)所指定的标准规格,这一标准制订所有航海电子仪器间的通讯标准,其中包含传输资料的格式以及传输资料的通讯协议。所以通常情况下,只需要通过串口读取信息,通过字符串解析的方式把需要的数据分离出来就可以得到GPS数据。

    具体的协议内容可以参见本文附录的参考资料,在具体的的字符串解析中,实际只需要解析$GPGGA、$GPRMC两个语句即可获得我们所需要的全部内容,包括经纬度,时间,搜星状态,卫星数量,高度,速度以及其他信号等,不同数据之间在获取的字符串中是使用逗号隔开的,而相对位置固定,因此整体的思路就是读取字符串,通过逗号位置判别对应数据,实现读取分析。

    http://emouse.cnblogs.com/ 博客文章,转载注明出处。

    嵌入式Linux串口编程

    作为数据读取分析的基本,嵌入式linux的串口编程就是基础中的基础了,串口的设置主要是设置struct termios结构体的各成员值。termios是在POSIX规范中定义的标准接口,表示终端设备(包括虚拟终端串口等)口是一种终端设备,一般通过终端编程接口对其进行配置和控制。在具体讲解串口相关编程之前,先了解一下终端相关知识
          终端有3种工作模式,分别为规范模式(canonical mode)、非规范模式(non-canonical mode)和原始模式(raw mode)通过在termios结构的c_lflag中设置ICANNON标志来定义终端是以规范模式(设置ICANNON标志)还是以非规范模式(清除ICANNON标志)工作,默认情况为规范模式

    在规范模式下,所有的输入是基于行进行处理在用户输入一个行结束符(回车符、EOF等)之前,系统调用read()函数读不到用户输入的任何字符。除了EOF之外的行结束符(回车符等)与普通字符一样会被read()函数读取到缓冲区之中。在规范模式中,行编辑是可行的,而且一次调用read()函数最多只能读取一行数据如果在read()函数中被请求读取的数据字节数小于当前行可读取的字节数,则read()函数只会读取被请求的字节数,剩下的字节下次再被读取 

    在非规范模式下,所有的输入是即时有效的,不需要用户另外输入行结束符,而且不可进行行编辑在非规范模式下,对参数MIN(c_cc[VMIN])和TIME(c_cc[VTIME])的设置决定read()函数的调用方式设置可以有4种不同的情况

    1. MIN = 0和TIME = 0:read()函数立即返回。若有可读数据,则读取数据并返回被读取的字节数,否则读取失败并返回0
    2. MIN > 0和TIME = 0:read()函数会被阻塞直到MIN个字节数据可被读取
    3. MIN = 0和TIME > 0:只要有数据可读或者经过TIME个十分之一秒的时间,read()函数则立即返回,返回值为被读取的字节数如果超时并且未读到数据,则read()函数返回0。
    4. MIN > 0和TIME > 0:当有MIN个字节可读或者两个输入字符之间的时间间隔超过TIME个十分之一秒时,read()函数才返回因为在输入第一个字符之后系统才会启动定时器,所以在这种情况下,read()函数至少读取一个字节之后才返回

    按照严格意义来讲,原始模式是一种特殊的非规范模式在原始模式下,所有的输入数据以字节为单位被处理。在这个模式下,终端是不可回显的,而且所有特定的终端输入/输出控制处理不可用通过调用cfmakeraw()函数可以将终端设置为原始模式,而且该函数通过以下代码可以得到实现。

    编程实现

    实现环境Qt

    这段程序为自行修改,实际测试通过,完成了串口配置和数据处理功能,可以直接解析获得GPS相关参数。

    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/signal.h>
    #include "string.h"
    #include "gps.h"
    #include <termios.h>
    #include <QtCore/QDebug>
    
    gps::gps()
    {
        baud=4800;
        GpsName=NULL;
        Gpsfd=0;
        for(int i=0;i<1024;i++)
        {
            GPS_BUF[i]=0;
        }
    
        GPS = new GPS_INFO;
        memset(GPS,0,sizeof(GPS_INFO));
    }
    
    gps::~gps()
    {
        delete GPS;
        closeGpsDev();
        tcsetattr(Gpsfd,TCSANOW,&oldtio); /* restore old modem setings */
        tcsetattr(0,TCSANOW,&oldstdtio); /* restore old tty setings */
    }
    
    
    ////////////////////////////////////////////////////////////////////////////////
    //解释gps发出的数据
    //0      7  0   4 6   0     6 8 0        90         0  3      0        9
    //$GPRMC,091400,A,3958.9870,N,11620.3278,E,000.0,000.0,120302,005.6,W*62
    //$GPGGA,091400,3958.9870,N,11620.3278,E,1,03,1.9,114.2,M,-8.3,M,,*5E
    void gps::gps_parse()
    ////////////////////////////////////////////////////////////////////////////////
    {
        int tmp;
        char c;
    
    
        c = GPS_BUF[5];
        if(c=='C')
        {
            //"GPRMC"
            GPS->D.hour   =(GPS_BUF[ 7]-'0')*10+(GPS_BUF[ 8]-'0');
            GPS->D.minute =(GPS_BUF[ 9]-'0')*10+(GPS_BUF[10]-'0');
            GPS->D.second =(GPS_BUF[11]-'0')*10+(GPS_BUF[12]-'0');
            tmp = GetComma(9,GPS_BUF);
            GPS->D.day    =(GPS_BUF[tmp+0]-'0')*10+(GPS_BUF[tmp+1]-'0');
            GPS->D.month  =(GPS_BUF[tmp+2]-'0')*10+(GPS_BUF[tmp+3]-'0');
            GPS->D.year   =(GPS_BUF[tmp+4]-'0')*10+(GPS_BUF[tmp+5]-'0')+2000;
    
            GPS->status      = GPS_BUF[GetComma(2,GPS_BUF)];
            GPS->latitude = get_locate(get_double_number(&GPS_BUF[GetComma(3,GPS_BUF)]));
            GPS->NS       = GPS_BUF[GetComma(4,GPS_BUF)];
            GPS->longitude= get_locate(get_double_number(&GPS_BUF[GetComma(5,GPS_BUF)]));
            GPS->EW       = GPS_BUF[GetComma(6,GPS_BUF)];
            GPS->speed    = get_double_number(&GPS_BUF[GetComma(7,GPS_BUF)]);
            UTC2BTC(&GPS->D);
    
        }
    
        if(c=='A')
        {
            //"$GPGGA"
            GPS->high     = get_double_number(&GPS_BUF[GetComma(9,GPS_BUF)]);
        }
    
    
    
     }
    
    
    //将获取文本信息转换为double型
    
    double gps::get_double_number(char *s)
    {
        char buf[128];
        int i;
        double rev;
        i=GetComma(1,s);
        strncpy(buf,s,i);
        buf[i]=0;
        rev=atof(buf);
    
        return rev;
    }
    
    double gps::get_locate(double temp)
    {
        int m;
        double  n;
        m=(int)temp/100;
        n=(temp-m*100)/60;
        n=n+m;
        return n;
    
    }
    
    ////////////////////////////////////////////////////////////////////////////////
    //得到指定序号的逗号位置
    int gps::GetComma(int num,char *str)
    {
        int i,j=0;
        int len=strlen(str);
        for(i=0;i<len;i++)
        {
            if(str[i]==',')
            {
                 j++;
            }
    
            if(j==num)
                return i+1;
        }
        return 0;
    }
    
    
    ////////////////////////////////////////////////////////////////////////////////
    //将世界时转换为北京时
    void gps::UTC2BTC(date_time *GPS)
    {
    
    //***************************************************
    //如果秒号先出,再出时间数据,则将时间数据+1秒
            GPS->second++; //加一秒
            if(GPS->second>59){
                GPS->second=0;
                GPS->minute++;
                if(GPS->minute>59){
                    GPS->minute=0;
                    GPS->hour++;
                }
            }
    
    //***************************************************
            GPS->hour+=8;
            if(GPS->hour>23)
            {
                GPS->hour-=24;
                GPS->day+=1;
                if(GPS->month==2 ||
                        GPS->month==4 ||
                        GPS->month==6 ||
                        GPS->month==9 ||
                        GPS->month==11 ){
                    if(GPS->day>30){
                        GPS->day=1;
                        GPS->month++;
                    }
                }
                else{
                    if(GPS->day>31){
                        GPS->day=1;
                        GPS->month++;
                    }
                }
                if(GPS->year % 4 == 0 ){//
                    if(GPS->day > 29 && GPS->month ==2){
                        GPS->day=1;
                        GPS->month++;
                    }
                }
                else{
                    if(GPS->day>28 && GPS->month ==2){
                        GPS->day=1;
                        GPS->month++;
                    }
                }
                if(GPS->month>12){
                    GPS->month-=12;
                    GPS->year++;
                }
            }
    }
    
    
    void gps::receive(void)
    {
        int i=0;
        char c;
        char buf[1024];
        volatile bool t=true;
    
        for(int i=0;i<1024;i++)
        {
            GPS_BUF[i]='\0';
        }
    
        while (t)
        {
            if(read(Gpsfd,&c,1) < 0 )
            {
                qDebug()<<"read Gpsdev error!";
                return ;
            }
    
            buf[i++] = c;
            if(c == '\n')
            {
                strncpy(GPS_BUF,buf,i);
                i=0;
                t=false;
            }
    
         }
    }
    
    int gps::openGpsDev()
    {
    
        Gpsfd = open("/dev/ttySAC1",O_RDWR);
    
        if (Gpsfd < 0)
        {
            qDebug()<<"Cannot open gps device"<<endl;
            close(Gpsfd);
            return -1;
        }
        qDebug()<<"open gps device OK!"<<endl;
        return Gpsfd;
    }
    int gps::closeGpsDev()
    {
        close(Gpsfd);
        qDebug()<<"close gps device OK!"<<endl;
        return 0;
    }
    
    int gps::initGpsDev()
    {
    
        set_opt(Gpsfd,4800,8,'N',1);
        return 0;
    
    }
    void gps::readGpsDev(void)
    {
        receive();
        gps_parse();
        int lat=(int)(GPS->latitude*10000);
        int lon=(int)(GPS->longitude*10000);
    
    //    qDebug()<<"gps"<<"lat="<<lat<<endl;
    //    qDebug()<<"gps"<<"lon="<<lon<<endl;
    }
    int gps::set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
    {
        struct termios newtio,oldtio;
        if  ( tcgetattr( fd,&oldtio)  !=  0)
        {
            perror("SetupSerial 1");
            return -1;
        }
        bzero( &newtio, sizeof( newtio ) );
        newtio.c_cflag  |=  CLOCAL | CREAD;
        newtio.c_cflag &= ~CSIZE;
    
        switch( nBits )
        {
        case 7:
            newtio.c_cflag |= CS7;
            break;
        case 8:
            newtio.c_cflag |= CS8;
            break;
        }
    
        switch( nEvent )
        {
        case 'O':                     //奇校验
            newtio.c_cflag |= PARENB;
            newtio.c_cflag |= PARODD;
            newtio.c_iflag |= (INPCK | ISTRIP);
            break;
        case 'E':                     //偶校验
            newtio.c_iflag |= (INPCK | ISTRIP);
            newtio.c_cflag |= PARENB;
            newtio.c_cflag &= ~PARODD;
            break;
        case 'N':                    //无校验
            newtio.c_cflag &= ~PARENB;
            break;
        }
    
    switch( nSpeed )
        {
        case 2400:
            cfsetispeed(&newtio, B2400);
            cfsetospeed(&newtio, B2400);
            break;
        case 4800:
            cfsetispeed(&newtio, B4800);
            cfsetospeed(&newtio, B4800);
            break;
        case 9600:
            cfsetispeed(&newtio, B9600);
            cfsetospeed(&newtio, B9600);
            break;
        case 115200:
            cfsetispeed(&newtio, B115200);
            cfsetospeed(&newtio, B115200);
            break;
        default:
            cfsetispeed(&newtio, B9600);
            cfsetospeed(&newtio, B9600);
            break;
        }
        if( nStop == 1 )
        {
            newtio.c_cflag &=  ~CSTOPB;
        }
        else if ( nStop == 2 )
        {
            newtio.c_cflag |=  CSTOPB;
        }
        newtio.c_cc[VTIME]  = 0;
        newtio.c_cc[VMIN] = 0;
        tcflush(fd,TCIFLUSH);
        if((tcsetattr(fd,TCSANOW,&newtio))!=0)
        {
            qDebug()<<"com set error"<<endl;
            return -1;
        }
        qDebug()<<"set done!"<<endl;
        return 0;
    }

    参考资料

  • 相关阅读:
    Lesson 43-44 Vacation Season is Approaching?
    Lesson 41-42 How would you respond?
    Lesson 37-38 Do you want to be a millionaire?
    Lesson 35-36 What did you forget?
    Lesson 33-34 Dieting
    保送
    陈老师搬书
    水题(原 USACO Mother's Milk)
    最大公约数和最小公倍数问题(luogu 1029)
    最大子矩阵(OJ 1768)
  • 原文地址:https://www.cnblogs.com/emouse/p/3058905.html
Copyright © 2011-2022 走看看