首先先了解下什么是NMEA码,这里有很好的解释,就不直接搬运了
http://www.gpsbaby.com/wz/nmea.html
首先要找到包含GPS信息的文本行,即字符串GPGGA所在行
$GPGGA,052551.00,3409.341502,N,10853.663318,E,1,05,1.2,459.4,M,-28.0,M,,*4E
在实际的工程应用中,可能由于各种原因(比如设备在室内时就无法获取GPS信息),GPS信息并不是实时都可以获取准确的完整的值,因此在GPS.log文件内,会存在一些不完整的GPS信息。
$GPGGA,,,,,,0,,,,,,,,*66 //这是我在室内定位的GPS信息
所以要确定一个文本行确实存在完整的GPS信息,必须确认GPGGA, N/S, W/E 三个字符串均存在。然后再定位纬度所在位置,提取数值即可。
实现代码如下
#include<sys/types.h> #include<sys/stat.h> #include<errno.h> #include<unistd.h> #include<fcntl.h> #include<stdio.h> #include<memory.h> #include<stdlib.h> #include<string.h> #define FILE_PATH "/home/mr_han/code/exp/GPS.log" #define READ_MAX 150 #define GPS_DATA 15 #define GPS_KEY "GPGGA" #define bool char #define true 1 #define false 0 void gps_cal(double p, char q, int *angle, float *min)//将原始GPS信息转换为度分形式 { *angle = p/100; *min = (p-*angle*100)/60; } int Search_comma(char *p, int L)//由GPGGA纬度字段前的逗号即可找到得到纬度GPS信息 { while(p[L-1]!=',') { --L; } return L; } /*从文件中c查找完整GPS信息,参数依次为, 文件路径(名),纬度值,经度值, 经度,纬度*/ bool get_gps_data(const char *file_name, double *p, double *q, char *longitude, char *latitude) { char *rw = NULL; int location = 0, i = 0, N=0,S=0,E=0,W=0; char read_line_buff[READ_MAX], gps[GPS_DATA]; memset(gps, 0, GPS_DATA); FILE *fd = fopen(FILE_PATH, "r"); if(fd == NULL) { printf("Open file error!\n"); return false; } while(!feof(fd)) { memset(read_line_buff, 0, READ_MAX); rw = fgets(read_line_buff, READ_MAX, fd);//每次从文件读取一行, if(rw == NULL) return false; if(strstr(read_line_buff, GPS_KEY)!=NULL) { N = (strchr(read_line_buff,'N')==NULL ? 0 : 1); S = (strchr(read_line_buff, 'S')==NULL ? 0 : 2); E = (strchr(read_line_buff, 'E')==NULL ? 0 : 4); W = (strchr(read_line_buff, 'W')==NULL ? 0 : 7);/ i = N+S+E+W; /*完整的GPS,信息只可能存在 NE东经北纬、NW西经北纬、SE东经南纬、SW西经南纬,分别给四种组合不同的权值,用以确定是那种情况*/ switch(i)//这里case可以调用函数用来代替goto语句 { case 5: *longitude = 'E'; *latitude = 'N'; i = 0; fclose(fd); goto NE; case 6: *longitude = 'E'; *latitude = 'S'; i = 0; fclose(fd); goto SE; case 8: *longitude = 'W'; *latitude = 'N'; i = 0; fclose(fd); goto NW; case 9: *longitude = 'W'; *latitude = 'S'; i = 0; fclose(fd); goto SW; default: continue; } } } NE: rw = strchr(read_line_buff, 'N');//strchr函数会在第一个参数字符串内找第二个参数字符,找到返回一个地址,找不到返回空 location = rw - read_line_buff - 1; //地址相减,得到数字,这一步主要是定位到纬度前的逗号,$GPGGA,052551.00,3409.341502,N location即N前的逗号 location = Search_comma(read_line_buff,location); //再向前定位上一个逗号即可找到GPS信息 while(read_line_buff[location+1] != 'N') gps[i++] = read_line_buff[location++]; *p = atof(gps); memset(gps, 0, GPS_DATA); i = 0; location = location+3;//3409.341502,N,10853.663318,E,纬度赋值完成后,location在N前逗号出,只需向后跳三位即可找到经度信息 while(read_line_buff[location+1] != 'E') gps[i++] = read_line_buff[location++]; *q = atof(gps); return true; SE: rw = strchr(read_line_buff, 'S'); location = rw - read_line_buff - 1; location = Search_comma(read_line_buff, location); while(read_line_buff[location+1] != 'S') gps[i++] = read_line_buff[location++]; *p = atof(gps); memset(gps, 0, GPS_DATA); i = 0; location = location + 3; while(read_line_buff[location+1] != 'E') gps[i++] = read_line_buff[location++]; *q = atof(gps); return true; NW: rw = strchr(read_line_buff, 'N'); location = rw - read_line_buff - 1; location = Search_comma(read_line_buff, location); while(read_line_buff[location+1] != 'N') gps[i++] = read_line_buff[location++]; *p = atof(gps); memset(gps, 0, GPS_DATA); i = 0; location =location + 3; while(read_line_buff[location+1] != 'W') gps[i++] = read_line_buff[location++]; *q = atof(gps); return true; SW: rw = strchr(read_line_buff, 'S'); location = rw - read_line_buff - 1; location = Search_comma(read_line_buff, location); while(read_line_buff[location+1] != 'S') gps[i++] = read_line_buff[location++]; *p = atof(gps);//atof函数可将字符串转为double后返回,转换失败返回0 memset(gps, 0, GPS_DATA); i = 0; location =location + 3; while(read_line_buff[location+1] != 'W') gps[i++] = read_line_buff[location++]; *q = atof(gps); return true; } char *print(char p) { switch(p) { case 'S':return "南纬"; case 's':return "南纬"; case 'N':return "北纬"; case 'n':return "北纬"; case 'W':return "东经"; case 'w':return "东经"; case 'E':return "西经"; case 'e':return "西经"; default: return "经纬错误"; } } int main() { int angle=0; float min=0; char longitude=0, latitude=0; double gps_g=0, gps_i=0;//gps_g经度 gps_i纬度 get_gps_data(FILE_PATH, &gps_i, &gps_g, &longitude, &latitude); printf("gps: %lf %c, %lf %c\n",gps_i, latitude, gps_g, longitude); /*gps_cal(gps_g, longitude, &angle, &min); printf("%s %d度%f分", print(longitude), angle, min); gps_cal(gps_i, latitude, &angle, &min); printf(" %s %d度%f分\n", print(latitude), angle, min);*/ gps_cal(gps_i, latitude, &angle, &min); printf("%s %d度%f分", print(latitude), angle, min); gps_cal(gps_g, longitude, &angle, &min); printf(" %s %d度%f分\n", print(longitude), angle, min); return 0; }
效果如下
附测试用的GPS.log文件部分信息
$GPVTG,,T,,M,,N,,K,N*2C
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPGGA,,,,,,0,,,,,,,,*66
$GPRMC,,V,,,,,,,,,,N*53
$GPGSV,3,1,10,10,49,322,50,12,15,119,40,20,78,352,49,25,09,151,39*7F
$GPGSV,3,2,10,32,28,272,48,14,13,260,,15,25,063,,21,41,203,*7B
$GPGSV,3,3,10,24,51,053,,27,,,*49
$GPVTG,,T,,M,,N,,K,N*2C
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPGGA,,,,,,0,,,,,,,,*66
$GPRMC,,V,,,,,,,,,,N*53
$GPGSV,3,1,11,10,49,322,51,12,15,119,40,20,78,352,49,25,09,151,38*7E
$GPGSV,3,2,11,32,28,272,47,14,13,260,,15,25,063,,21,41,203,*75
$GPGSV,3,3,11,24,51,053,,27,,,,40,,,36*49
$GPGGA,052550.00,3409.338831,N,10853.658643,E,1,04,1.4,467.2,M,-28.0,M,,*43
$GPVTG,1.5,T,4.6,M,0.3,N,0.6,K,A*20
$GPRMC,052550.00,A,3409.338831,N,10853.658643,E,0.3,1.5,121218,3.1,W,A*25
$GPGSA,A,2,10,12,20,32,,,,,,,,,1.6,1.4,0.9*39
$GPGSV,3,1,11,10,49,322,51,12,15,119,40,14,13,260,29,15,25,063,30*77
$GPGSV,3,2,11,20,78,352,49,21,41,203,22,24,51,053,33,25,09,151,39*7E
$GPGSV,3,3,11,32,28,272,47,27,,,,40,,,38*4C
$GPGGA,052551.00,3409.341502,N,10853.663318,E,1,05,1.2,459.4,M,-28.0,M,,*4E
$GPVTG,1.5,T,4.6,M,0.0,N,0.0,K,A*25
$GPRMC,052551.00,A,3409.341502,N,10853.663318,E,0.0,1.5,121218,3.1,W,A*27
$GPGSA,A,2,10,12,20,24,32,,,,,,,,1.4,1.2,0.8*3A
$GPGSV,3,1,11,10,49,322,51,12,15,119,40,14,13,260,30,15,25,063,30*7F
$GPGSV,3,2,11,20,78,352,49,21,41,203,22,24,51,053,33,25,09,151,39*7E
$GPGSV,3,3,11,32,28,272,47,27,,,,40,,,38*4C
$GPGGA,052552.00,3409.340891,N,10853.662052,E,1,05,1.2,462.9,M,-28.0,M,,*42
$GPVTG,1.5,T,4.6,M,0.0,N,0.0,K,A*25
$GPRMC,052552.00,A,3409.340891,N,10853.662052,E,0.0,1.5,121218,3.1,W,A*2E
$GPGSA,A,2,10,12,20,24,32,,,,,,,,1.4,1.2,0.8*3A
$GPGSV,3,1,11,10,49,322,51,12,15,119,40,14,13,260,30,15,25,063,27*79
$GPGSV,3,2,11,20,78,352,49,21,41,203,20,24,51,053,31,25,09,151,39*7E
$GPGSV,3,3,11,32,28,272,47,27,,,,40,,,38*4C
$GPGGA,052553.00,3409.340173,N,10853.661041,E,1,05,1.2,465.3,M,-28.0,M,,*4A
$GPVTG,1.5,T,4.6,M,0.0,N,0.0,K,A*25
$GPRMC,052553.00,A,3409.340173,N,10853.661041,E,0.0,1.5,121218,3.1,W,A*2B
$GPGSA,A,2,10,12,20,24,32,,,,,,,,1.4,1.2,0.8*3A
$GPGSV,3,1,11,10,49,322,50,12,15,119,41,14,13,260,30,15,25,063,27*79
$GPGSV,3,2,11,20,78,352,49,21,41,203,20,24,51,053,32,25,09,151,39*7D
$GPGSV,3,3,11,32,28,272,46,27,,,,40,,,39*4C
$GPGGA,052554.00,3409.339925,N,10853.660214,E,1,05,1.2,466.6,M,-28.0,M,,*4D
$GPVTG,1.5,T,4.6,M,0.0,N,0.0,K,A*25
$GPRMC,052554.00,A,3409.339925,N,10853.660214,E,0.0,1.5,121218,3.1,W,A*2A
$GPGSA,A,2,10,12,20,24,32,,,,,,,,1.4,1.2,0.8*3A
$GPGSV,3,1,11,10,49,322,51,12,15,119,40,14,13,260,31,15,25,063,28*77
$GPGSV,3,2,11,20,78,352,49,21,41,203,21,24,51,053,32,25,09,151,39*7C
$GPGSV,3,3,11,32,28,272,46,27,,,,40,,,39*4C
$GPGGA,052555.00,3409.340026,N,10853.659458,E,1,05,1.2,466.2,M,-28.0,M,,*48
$GPVTG,1.5,T,4.6,M,0.0,N,0.0,K,A*25
$GPRMC,052555.00,A,3409.340026,N,10853.659458,E,0.0,1.5,121218,3.1,W,A*2B
$GPGSA,A,2,10,12,20,24,32,,,,,,,,1.4,1.2,0.8*3A
$GPGSV,3,1,11,10,49,322,51,12,15,119,40,14,13,260,30,15,25,063,28*76
$GPGSV,3,2,11,20,78,352,49,21,41,203,22,24,51,053,32,25,09,151,39*7F
$GPGSV,3,3,11,32,28,272,46,27,,,,40,,,39*4C
$GPGGA,052556.00,3409.339490,N,10853.658951,E,1,05,1.2,465.8,M,-28.0,M,,*40
$GPVTG,1.5,T,4.6,M,0.0,N,0.0,K,A*25