Linux下接收处理GPS数据

来源:互联网 发布:淘宝微淘视频怎么发布 编辑:程序博客网 时间:2024/05/01 23:50

Linux下接收处理GPS数据

开发板平台:FL2440

Linux内核版本: 3.0

 

话不多少,开始干活,对于linux下接收并处理gps数据,那么对于新手的我来讲,一开始把这个项目分成两块,这个也是这个项目的整体方向,第一,接收数据;第二处理数据,下面咱们一块一块的进行。

1接收数据

这个名字有点笼统,确切讲是串口接收gps模块的原始数据,在fl2440开发板左侧大家可以看到有两个母头串口(如图1

 

在开发板上 ls /dev 你会发现

 

ttyS0(这个是连接到电脑的串口,也是图一中上面的那个串口)

ttyS1(这个就是图一中下面的串口,也是连接gps模块,我们需要监听的串口)

由于gps模块也是母头,所以需要自己制作一个公头线,首先进行硬件上的联通,下面看一下RS_232db9线每一个引脚的作用

 

--------------下图为引脚顺序图------------

 

Db9中有效的通信引脚2(RXD),3(TXD),5(GND)。在公头和母头进行连接时,公头2连接母头3,公头3连接母头2。5接5。这样硬件实现了连接。如下,

 

gps模块接上电,此时可以监听串口了,

监听串口命令 microcom -s 4800 /dev/ttyS1

 

有了上述结果。说明接收数据是可以实现的。看到这里不知道有没有人有疑问,这样就可以直接收到数据么,gps,串口都是设备,不需要对gps和串口进行驱动使能么?是这样的,在一开始内核中就已经对串口驱动进行了使能,而gps模块中有gps模块的驱动,这个模块通过自身的串口不断的发送数据开发板需要做的就是读取然后处理就够了,

以上步骤成功,说明硬件上的连通性没的问题,可以说只是准备工作,接下来的才是重点,

 

 

串口编程!!!

数据分析!!!

重要的事情要说三个感叹号

其实编写GPS数据解析程序就是ARM+linux串口编程,串口编程是嵌入式应用程序开发中最基础也是最重要的部分,如何从一个串口设备获取数据并将这些数据做一定的解析呢?OK,串口编程大致可以分为以下几个步骤:

 

至于串口编程的详细介绍,如何设置波特率,如何设置停止位等等,以下给出两个linux串口编程的博客链接,讲的很详细

http://www.cnblogs.com/wblyuyang/archive/2011/11/21/2257544.html

http://blog.csdn.net/mtv0312/article/details/6599162

其中串口设置其实就相当于串口通信的协议,

波特率:是为了两者信号流能同步,

数据位:是指又几位数据封装成一帧

结束位:是指以帧传输数据时,协定好结束位,便于提取有效数据

奇偶校验:检验数据的一种手段

四者的设置又通信双方协定。

数据分析!!!

 

$GPRMC,最常用的字符串,包含了时间,日期,定位,和航速航向信息。一般应用,只要有这些信息就可以了。

$GPGGA,包含了定位信息相关的详细信息。如定位时用到的星数,定位的方式,天线的海拔高度,精度等等。

$GPGSA,包含了定位,水平,海拔三种DOP信息,即精度信息,包含了定位所用到的卫星ID。

$GPGSV,包含了GPS模块可以看到的星数(注意,只是能看到的星数,实际使用到的星数在GPGGA中),以及这些卫星的ID号,仰角,方位角,信噪比。关于这种字符串要特别说明的是,它可能会由几条GPGSV字符串组成,因此,每个字符串都包含了共几条字符串,本字串是第几条这样的信息。一般的GPS最多是三条。也有的GPS模块会超过3条。

$GPVTG,包含了更详细的航向航速的信息,航向信息分为以真北为参考和以地磁北为参考(真北和地磁北是不一样的,两者相差几度),航速信息则给出了以节为单位和以公里/时为单位的数据。

以上信息,一般GPS模块都会默认输出,也有的模块只输出其中几个。

 

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

<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=数据无效)

例如

$GPRMC,074030.00,A,3941.10576,N,11810.52559,E,0.879,136.15,020210,,,A*64

UTC时间 定位状态 纬度 经度 航速 航向 UTC时间/年  

$GPGGA,074030.00,3941.10576,N,11810.52559,E,1,06,11.32,46.6,M,-2.7,M,,*4A   

UTC时间 纬度 经度 GPS状态 正在使用卫星数 水平精度 海拔高度码

 

基本思路:

open /dev/ttyS1

read()读串口一的数据存入到缓存里

Strstr()在缓存里进行字符串“$GPRMC”的匹配,然后返回匹配的字符串的位置处

Sscanf()将$GPRMC的有用数据另存起来,

 

具体代码如下

设置串口

set_ttyS1.c

#include <stdio.h>

#include <string.h>

#include <errno.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <termios.h>

#include <sys/types.h>

#include <stdlib.h>

 

#include "gpsd.h"

 

int 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)

    {

        perror("com set error");

        return -1;

    }

    return 0;

}

 

 

分析gps数据函数

analysis.c

 

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <sys/types.h>

#include <errno.h>

#include <sys/stat.h>

#include <fcntl.h>

 

#include "gpsd.h"

 

int gprmc_analysis (char *buff,GPRMC *gprmc)

{

char *ptr = NULL;

 

if(gprmc == NULL)

        return -1;

    if(strlen(buff) < 10)

        return -1;

    if(NULL == (ptr = strstr(buff,"$GPRMC")))

        return -1;

sscanf(ptr,"$GPRMC,%d.000,%c,%f,N,%f,E,%f,%f,%d,,,%c*",\

            &(gprmc->time),&(gprmc->pos_state),&(gprmc->latitude),&(gprmc->latitude),&(gprmc->speed),&(gprmc-

>direction),&(gprmc->date),&(gprmc->mode));

 

return 0;

} /*  ----- End of gprmc_analysis()  ----- */

 

 

 

测试函数

test.c

#include <stdio.h>

#include <string.h>

#include <sys/types.h>

#include <errno.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <termios.h>

#include <stdlib.h>

 

#include "gpsd.h"

 

#define GPS_LEN 512 

 

int gprmc_analysis (char *buff,GPRMC *gprmc);

int open_com(char *device_name);

int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop);

 

int main (int argc, char **argv)

{

    int fd = 0;

    int nread = 0;

 

    GPRMC gprmc;

    //GPRMC *gprmc;

 

        char gps_buff[GPS_LEN];

        char *dev_name = "/dev/ttyS1";

 

        fd = open_com(dev_name);

 

        set_opt(fd,4800,8,'N',1);

        while(1)

        {

          sleep(2);

 //注意这个时间的设置,设置不恰好的话,会导致GPS数据读取不完成,数据解析出错误

        nread = read(fd,gps_buff,sizeof(gps_buff));

        printf("gps_buff: %s", gps_buff);

        memset(&gprmc, 0 , sizeof(gprmc));

        gprmc_analysis(gps_buff, &gprmc);

 

        if(nread > 0)

        {

 

 

 printf("===========================================\n");

        printf("= GPS状态位 : %c  [A:有效状态 V:无效状态]==\n" ,gprmc.pos_state);

        printf("= GPS模式位 : %c  [A:自主定位 D:差分定位]==\n" , gprmc.mode);

        printf("=日期 : 20%02d-%02d-%02d=\n",gprmc.date%100, (gprmc.date%10000)/100,gprmc.date/10000);

        printf("=时间 : %02d:%02d:%02d=\n",(gprmc.time/10000+8)%24,(gprmc.time%10000)/100,gprmc.time%100);

        printf("=纬度 : 北纬:%.3f=\n",(gprmc.latitude/100));

        printf("=经度 : 东经:%.3f=\n",(gprmc.longitude/100));

        printf("=速度 : %.3f =\n",gprmc.speed);

        printf("===========================================\n");

        }

}

        close(fd);

        return 0;

} /* ----- End of main() ----- */

 

 

头文件

gpsd.h

#ifndef __GPSD_H__

#define __GPSD_H__

 

typedef unsigned int UINT;    

typedef int BYTE;              

typedef long int WORD;        

 

typedef struct __gprmc__

 

{

    UINT time;                  //时间

    char pos_state;             //定位状态

    float latitude;             //纬度

    float longitude;            //经度

    float speed;                //移动速度

    float direction;            //方向

    UINT date;                  //日期

    float declination;          //磁偏角

    char dd;                    //磁偏角方向

    char mode;

} GPRMC;

 

extern int open_com(char *device_name);

extern int gprmc_analysis(char *buff,GPRMC *gprmc);

extern int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop);

#endif

 

代码写好后如下

 

 

 

Makefile

 

 

 生成的gps可执行文件,下载到开发板上,运行,ok

 

1 0
原创粉丝点击