/**********************************************************************
* File Name: gps_info.c
* Description: GPS数据接收与解析
* Date: 2014/05/21
* By: WZP
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
**********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/select.h>
/************************************************************************/
/*推荐定位信息(GPRMC)
$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
<1> UTC时间,hhmmss.sss(时分秒.毫秒)格式
<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=数据无效)*/
/************************************************************************/
#define max_buffer_size 150 /*定义缓冲区最大长度*/
char hd[max_buffer_size];
char sbuf[max_buffer_size];
char s_temp[17][10],*gps_s[17];
typedef struct Date_s{ //时间数据结构
int hour,minute,second,day,month,year;
}Date;
typedef struct GPS_Data_s{ //GPS解析数据结构
Date D;
double latitude,longitude;
int latitude_Degree,latitude_Cent,latitude_Second;
int longitude_Degree,longitude_Cent,longitude_Second;
char status,NS,EW;
double speed,direction;
}GPS_Data;
GPS_Data gps,*GPS=&gps;
Date d;
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;
case 460800:
cfsetispeed(&newtio, B460800);
cfsetospeed(&newtio, B460800);
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;
}
int IS_start(int fp)//判断GPS字符串头
{
int i;
int status=0;
read(fp,hd,1);
if(hd[0]=='$')
{
status=1;
}
return status;
}
void split(char *str)//逗号分割字符串
{
char last=0,i,j;
for(i=0;i<15;i++)
{
gps_s[i]=&s_temp[i][0];
}
for(i=0,j=0;str[i];i++)
{
if(str[i]==',')
{//从 str+last 拷贝 i-last 个字符到 gps_s[j++]
memmove(gps_s[j++],str+last,i-last);
last=i+1;
}
}
memmove(gps_s[j],str+last,i-last);
return;
}
//UTC时间换算到本地时间,暂时忽略时间换算的各种没考虑情况
void UTC2BTC(Date* d)
{
if((d->hour>=24)&&(d->hour%=24))
{
if(++d->day>28)
{
if((d->month==2)&&(d->year%4!=0)&&(d->day=1))
{
d->month++;//2月非闰年:28天
}
else if((d->month==2)&&(d->year%4==0)&&(d->day==30)&&(d->day=1))
{
d->month++;//2月闰年:29天
}
else if((d->day==31)&&((d->month==4)||(d->month==6)||(d->month==9)
||(d->month==11))&&(d->day=1))
{
d->month++; //一个月30天
}
else if((d->day==32)&&(d->day=1)&&(++d->month>12)&&(d->month=1))
{
d->year++; //一个月31天,12月后年数加1
}
}
}
}
void gps_analysis(GPS_Data* GPS)//解析GPS信息
{
float lati_cent_tmp,longi_cent_tmp;
d.hour=(gps_s[1][0]-'0')*10+(gps_s[1][1]-'0')+8;
d.minute=(gps_s[1][2]-'0')*10+(gps_s[1][3]-'0');
d.second=(gps_s[1][4]-'0')*10+(gps_s[1][5]-'0');
d.day=(gps_s[9][0]-'0')*10+(gps_s[9][1]-'0');
d.month=(gps_s[9][2]-'0')*10+(gps_s[9][3]-'0');
d.year=(gps_s[9][4]-'0')*10+(gps_s[9][5]-'0')+2000;
UTC2BTC(&d); //UTC时间转化为北京时间
gps.D=d;
GPS->status=gps_s[2][0];
sscanf(gps_s[3],"%lf",&GPS->latitude);
sscanf(gps_s[5],"%lf",&GPS->longitude);
GPS->NS=gps_s[4][0];
GPS->EW=gps_s[6][0];
GPS->latitude_Degree=(int)GPS->latitude /100;
lati_cent_tmp=(GPS->latitude-GPS->latitude_Degree*100);
GPS->latitude_Cent=(int)lati_cent_tmp;
GPS->latitude_Second=(int)((lati_cent_tmp-GPS->latitude_Cent)*60);
GPS->longitude_Degree=(int)GPS->longitude /100;
longi_cent_tmp=(GPS->longitude-GPS->longitude_Degree*100);
GPS->longitude_Cent=(int)longi_cent_tmp;
GPS->longitude_Second=(int)((longi_cent_tmp-GPS->longitude_Cent)*60);
sscanf(gps_s[7],"%lf",&GPS->speed);
GPS->speed*=1.85; ////海里转化为公里
sscanf(gps_s[8],"%lf",&GPS->direction);
}
void show_gps(GPS_Data* GPS)//显示GPS解析结果
{
printf("UTC Time: %d/%02d/%02d %02d:%02d:%02d\n",d.year,d.month,d.day,
d.hour-8,d.minute,d.second);
printf("Beijing Time: %d/%02d/%02d %02d:%02d:%02d\n",GPS->D.year,
GPS->D.month,GPS->D.day,GPS->D.hour,GPS->D.minute,GPS->D.second);
if (GPS->NS=='N')
{
printf("Latitude: North ");
}
else if(GPS->NS=='S')
{
printf("Latiude: South ");
}
printf("%ddegree %02d'%02d\"\n", GPS->latitude_Degree,GPS->latitude_Cent,
GPS->latitude_Second);
if (GPS->EW=='E')
{
printf("Longitude: East ");
}
else if(GPS->EW=='W')
{
printf("Longitude: West ");
}
printf("%ddegree %02d'%02d\"\n",GPS->longitude_Degree,GPS->longitude_Cent,
GPS->longitude_Second );
printf("Speed:%.3lfkm/h\n",GPS->speed );
printf("Direction: %.1lf Degree\n", GPS->direction);//以正北为基准
printf("\n");
}
int main(int argc, char *argv[ ] )
{
int len;
int rfd,retv,i;
printf("/*****************************************************/\n");
rfd=open("/dev/ttySAC3",O_RDWR|O_NOCTTY); //打开串口UART3
set_opt(rfd,9600,8,'N',1); //波特率9600,数据位8,检验位无,停止位1
while(1)
{
while(!IS_start(rfd)); //若无字头'$',则循环;若有,则跳出
for ( i = 1; i < max_buffer_size; i++)
{
read(rfd,&hd[i],1); //存储字符串
if (hd[i]=='\n') //遇到结束符则存储完成
{
break;
}
}
if(strncmp(hd,"$GPRMC",6)==0) //判断是不是"$GPRMC"格式
{
//接收到的$GPRMC格式数据
printf("$GPRMC in GPS:\n\n%s\n\nAnalysis of $GPRMC:\n\n",hd);
split(hd); //分割字符串
if (gps_s[2][0]=='A') //判�