Linux下接收處理GPS數(shù)據(jù)教程
Linux下接收處理GPS數(shù)據(jù)教程
Linux的性能、可靠性、靈活性、和開放性,與其支持多微處理器體系結(jié)構(gòu)、硬件設(shè)備、圖形支持和通信協(xié)議相結(jié)合,把Linux建成了一個日益發(fā)展的操作系統(tǒng)平臺。接下來是小編為大家收集的Linux下接收處理GPS數(shù)據(jù)教程,希望能幫到大家。
Linux下接收處理GPS數(shù)據(jù)教程
1,接收數(shù)據(jù)
這個名字有點(diǎn)籠統(tǒng),確切講是串口接收gps模塊的原始數(shù)據(jù),在fl2440開發(fā)板左側(cè)大家可以看到有兩個母頭串口(如圖1)
在開發(fā)板上 ls /dev 你會發(fā)現(xiàn)
ttyS0(這個是連接到電腦的串口,也是圖一中上面的那個串口),
ttyS1(這個就是圖一中下面的串口,也是連接gps模塊,我們需要監(jiān)聽的串口)
由于gps模塊也是母頭,所以需要自己制作一個公頭線,首先進(jìn)行硬件上的聯(lián)通,下面看一下RS_232的db9線每一個引腳的作用
--------------下圖為引腳順序圖------------
Db9中有效的通信引腳2(RXD),3(TXD),5(GND)。在公頭和母頭進(jìn)行連接時,公頭2連接母頭3,公頭3連接母頭2。5接5。這樣硬件實(shí)現(xiàn)了連接。如下,
gps模塊接上電,此時可以監(jiān)聽串口了,
監(jiān)聽串口命令 microcom -s 4800 /dev/ttyS1
有了上述結(jié)果。說明接收數(shù)據(jù)是可以實(shí)現(xiàn)的??吹竭@里不知道有沒有人有疑問,這樣就可以直接收到數(shù)據(jù)么,gps,串口都是設(shè)備,不需要對gps和串口進(jìn)行驅(qū)動使能么?是這樣的,在一開始內(nèi)核中就已經(jīng)對串口驅(qū)動進(jìn)行了使能,而gps模塊中有g(shù)ps模塊的驅(qū)動,這個模塊通過自身的串口不斷的發(fā)送數(shù)據(jù)開發(fā)板需要做的就是讀取然后處理就夠了,
以上步驟成功,說明硬件上的連通性沒的問題,可以說只是準(zhǔn)備工作,接下來的才是重點(diǎn),
串口編程!!!
數(shù)據(jù)分析!!!
重要的事情要說三個感嘆號
其實(shí)編寫GPS數(shù)據(jù)解析程序就是ARM+linux串口編程,串口編程是嵌入式應(yīng)用程序開發(fā)中最基礎(chǔ)也是最重要的部分,如何從一個串口設(shè)備獲取數(shù)據(jù)并將這些數(shù)據(jù)做一定的解析呢?OK,串口編程大致可以分為以下幾個步驟:
至于串口編程的詳細(xì)介紹,如何設(shè)置波特率,如何設(shè)置停止位等等,以下給出兩個linux串口編程的博客鏈接,講的很詳細(xì)
http://www.cnblogs.com/wblyuyang/archive/2011/11/21/2257544.html
http://blog.csdn.net/mtv0312/article/details/6599162
其中串口設(shè)置其實(shí)就相當(dāng)于串口通信的協(xié)議,
波特率:是為了兩者信號流能同步,
數(shù)據(jù)位:是指又幾位數(shù)據(jù)封裝成一幀
結(jié)束位:是指以幀傳輸數(shù)據(jù)時,協(xié)定好結(jié)束位,便于提取有效數(shù)據(jù)
奇偶校驗(yàn):檢驗(yàn)數(shù)據(jù)的一種手段
四者的設(shè)置又通信雙方協(xié)定。
數(shù)據(jù)分析!!!
$GPRMC,最常用的字符串,包含了時間,日期,定位,和航速航向信息。一般應(yīng)用,只要有這些信息就可以了。
$GPGGA,包含了定位信息相關(guān)的詳細(xì)信息。如定位時用到的星數(shù),定位的方式,天線的海拔高度,精度等等。
$GPGSA,包含了定位,水平,海拔三種DOP信息,即精度信息,包含了定位所用到的衛(wèi)星ID。
$GPGSV,包含了GPS模塊可以看到的星數(shù)(注意,只是能看到的星數(shù),實(shí)際使用到的星數(shù)在GPGGA中),以及這些衛(wèi)星的ID號,仰角,方位角,信噪比。關(guān)于這種字符串要特別說明的是,它可能會由幾條GPGSV字符串組成,因此,每個字符串都包含了共幾條字符串,本字串是第幾條這樣的信息。一般的GPS最多是三條。也有的GPS模塊會超過3條。
$GPVTG,包含了更詳細(xì)的航向航速的信息,航向信息分為以真北為參考和以地磁北為參考(真北和地磁北是不一樣的,兩者相差幾度),航速信息則給出了以節(jié)為單位和以公里/時為單位的數(shù)據(jù)。
以上信息,一般GPS模塊都會默認(rèn)輸出,也有的模塊只輸出其中幾個。
$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
<1> UTC時間,hhmmss(時分秒)格式
<2> 定位狀態(tài),A=有效定位,V=無效定位
<3> 緯度ddmm.mmmm(度分)格式(前面的0也將被傳輸)
<4> 緯度半球N(北半球)或S(南半球)
<5> 經(jīng)度dddmm.mmmm(度分)格式(前面的0也將被傳輸)
<6> 經(jīng)度半球E(東經(jīng))或W(西經(jīng))
<7> 地面速率(000.0~999.9節(jié),前面的0也將被傳輸)
<8> 地面航向(000.0~359.9度,以真北為參考基準(zhǔn),前面的0也將被傳輸)
<9> UTC日期,ddmmyy(日月年)格式
<10> 磁偏角(000.0~180.0度,前面的0也將被傳輸)
<11> 磁偏角方向,E(東)或W(西)
<12> 模式指示(僅NMEA0183 3.00版本輸出,A=自主定位,D=差分,E=估算,N=數(shù)據(jù)無效)
例如
$GPRMC,074030.00,A,3941.10576,N,11810.52559,E,0.879,136.15,020210,,,A*64
UTC時間 定位狀態(tài) 緯度 經(jīng)度 航速 航向 UTC時間/年
$GPGGA,074030.00,3941.10576,N,11810.52559,E,1,06,11.32,46.6,M,-2.7,M,,*4A
UTC時間 緯度 經(jīng)度 GPS狀態(tài) 正在使用衛(wèi)星數(shù) 水平精度 海拔高度碼
基本思路:
open /dev/ttyS1
read()讀串口一的數(shù)據(jù)存入到緩存里
Strstr()在緩存里進(jìn)行字符串“$GPRMC”的匹配,然后返回匹配的字符串的位置處
Sscanf()將$GPRMC的有用數(shù)據(jù)另存起來,
具體代碼如下
設(shè)置串口
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': //奇校驗(yàn)
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
newtio.c_iflag |= (INPCK | ISTRIP);
break;
case 'E': //偶校驗(yàn)
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數(shù)據(jù)函數(shù)
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() ----- */
測試函數(shù)
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);
//注意這個時間的設(shè)置,設(shè)置不恰好的話,會導(dǎo)致GPS數(shù)據(jù)讀取不完成,數(shù)據(jù)解析出錯誤
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狀態(tài)位 : %c [A:有效狀態(tài) V:無效狀態(tài)]==\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("=經(jīng)度 : 東經(jīng):%.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; //定位狀態(tài)
float latitude; //緯度
float longitude; //經(jīng)度
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可執(zhí)行文件,下載到開發(fā)板上,運(yùn)行,ok
看了“Linux下接收處理GPS數(shù)據(jù)教程”還想看: