文件读写以及NMEA码中GPS信息的提取
首先先了解下什么是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
文件读写以及NMEA码中GPS信息的提取的更多相关文章
- nodejs的tream(流)解析与模拟文件读写流源码实现
什么是流? 可读流于可写流 双工流于转换流 背压机制与文件流模拟实现 一.什么是流? 关于流的概念早在1964年就有记录被提出了,简单的说"流"就是控制数据传输过程的程序,比如在那 ...
- 用java实现输出英文小说飘中出现次数最多的前N个单词(附:使用文件读写)
本文参考于:https://blog.csdn.net/u014204432/article/details/40348839 一.题目 输出单个文件(<飘> 英文版)中的前 N 个最常出 ...
- java study文件读写
文件读写 如果在代码中写入大量的数据,会增加代码的冗余度,通过读取文件的方式,可以精简代码,便于数据的修改和代码的维护 IO流的分类:字节流和字符流 字符流 字符输出流:写文本文件的,抽象基类java ...
- PHP文件读写操作之文件写入代码
在PHP网站开发中,存储数据通常有两种方式,一种以文本文件方式存储,比如txt文件,一种是以数据库方式存储,比如Mysql,相对于数据库存储,文件存储并没有什么优势,但是文件读写操作在基本的PHP开发 ...
- Python程序设计7——文件读写
1 文件读写简介 文件读写是应用程序中的常用操作.下面介绍Python中进行文件读写.Python的文件读写是非常简单的. 1.1 open函数 open函数一般有了两个必须参数,一个是文件名参数,另 ...
- QT_8_Qt中的事件处理_定时器事件_定时器类_事件分发器_事件过滤器_绘图事件_高级绘图事件_绘图设备_QFile 文件读写_QFileInfo文件信息
Qt中的事件处理 1.1. 捕获QLabel中是鼠标事件 1.2. enterevent 鼠标进入 1.3. leaveevent 鼠标离开 1.4. 鼠标按下MyLabel::mousePressE ...
- f2fs源码分析之文件读写过程
本篇包括三个部分:1)f2fs 文件表示方法: 2)NAT详细介绍:3)f2fs文件读写过程:4) 下面详细阐述f2fs读写的过程. 管理数据位置关键的数据结构是node,node包括三种:inode ...
- ASP.NET MVC Filters 4种默认过滤器的使用【附示例】 数据库常见死锁原因及处理 .NET源码中的链表 多线程下C#如何保证线程安全? .net实现支付宝在线支付 彻头彻尾理解单例模式与多线程 App.Config详解及读写操作 判断客户端是iOS还是Android,判断是不是在微信浏览器打开
ASP.NET MVC Filters 4种默认过滤器的使用[附示例] 过滤器(Filters)的出现使得我们可以在ASP.NET MVC程序里更好的控制浏览器请求过来的URL,不是每个请求都会响 ...
- python中文件读写
读写文件是最常见的IO操作.Python内置了读写文件的函数,用法和C是兼容的. 读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘, ...
随机推荐
- /etc/hosts 详解
/etc/hosts:主机名查询静态表,是ip地址与域名快速解析的文件.ip地址与主机名之间的映射,包括主机的别名. 通常将常用的域名和ip地址映射加入到hosts文件中,实现快速方便的访问. 如果没 ...
- Python3使用request/urllib库重定向问题
禁止自动重定向 python3的urllib.request模块发http请求的时候,如果服务器响应30x会自动跟随重定向,返回的结果是重定向后的最终结果而不是30x的响应结果. request是靠H ...
- Mac下查看 Java 安装目录位置和安装数量
/usr/libexec/java_home -V 第一个红框是安装数量, 第二个红框是目前正在使用的 JDK 版本位置
- Redis | 第一部分:数据结构与对象 上篇《Redis设计与实现》
目录 前言 1. 简单动态字符串 1.1 SDS的定义 1.2 空间预分配与惰性空间释放 1.3 SDS的API 2. 链表 2.1 链表与节点的定义 2.2 链表的API 3. 字典 3.1 哈希表 ...
- JS和JQUERY常见函数封装方式
JS中常用的封装函数4种方法: 1. 函数封装法: function box(){ } 2. 封装成对象 : let Cookie = { get(){ }, set(){ } } 3. 封装成构造函 ...
- myeclipse自带tomcat
安装myeclipse自带的tomcat没有在myeclipse的安装目录下,是再myeclipse指定的工作空间下 的.metadata\.plugins\com.genuitec.eclipse. ...
- 微信公众号生成海报(uniapp)
前言 这几天接到一个需求,要在公众号内生成分享海报.之前有做过H5和小程序的,心想直接复制过来就行了.没想到踩了不少的坑,搞了好几天终于搞好了,特此分享一下,希望能对大家有所帮助. 效果图 代码实现 ...
- [luogu5537]系统设计
考虑哈希,令$h[x]$表示根到$x$路径的哈希值,那么有$h[x]+hash(l,r)=h[ans]$ 考虑用线段树维护$a_{i}$的区间哈希值,并用map去找到对应的$ans$ 但还有一个问题, ...
- 实用QPS和TPS高的高效分析方法
现在主库的MySQL的QPS一直在3K/s左右,想知道其到底执行了那些SQL,或者是那些SQL执行的次数比较多: 腾讯云的后台监控: 开启腾讯云的SQL审计后,下载几分钟SQL日志文件, 下列语句在M ...
- HarmonyOS 3.0.0开发者预览版全新发布
2021年10月22日在华为开发者大会HDC.Together 2021 主题演讲上,我们发布了HarmonyOS 3.0.0开发者预览版,主要内容包括:Harmony设计系统.ArkUI 3.0.A ...