Linux C 用GPS时间更新系统时间的方法。
思路:
1、GPS模块会自动收到带时间信息的消息。
GPS模块会收到很多的协议消息带时间信息的。我们选择"$GPRMC"这条协议。其中的时间格式有的是hhmmss(时分秒)
有的是的精确到秒后两位hmmss.ss(时分秒),有的是的精确到秒后三位hmmss.ss(时分秒),具体估计需要看实际模块输出。
2、从消息中解析出GPS收到的时间
3、如系统时间和GPS时间差异大时,用GPS时间更新系统时间
GPS协议介绍:
GPS遵循一下NMEA 0183 协议
NMEA 0183 协议
NMEA 0183 是美国国家海洋电子协会(National Marine Electronics Association)为海用电子设备制定的标准格式。目前业已成了 GPS 导航设备统一的 RTCM(Radio Technical Commission for Maritime services)标准协议。NMEA0183 协议采用 ASCII 码来传递 GPS 定位信息,我们称之为帧。帧格式形如:
$aaccc,ddd,ddd,„,ddd*hh(CR)(LF)
1. “$”:帧命令起始位
2. “aaccc”:地址域,前两位为识别符(aa),后三位为语句名(ccc)
3. “ddd,ddd”:数据内容
4. “*”:校验和前缀(也可以作为语句数据结束的标志)
5. “hh”:校验和(check sum),$与*之间所有字符 ASCII 码的校验和(各字 节做异或运算,得到校验和后,再转换 16 进制格式的 ASCII 字符)
6. “(CR)(LF)”:帧结束,回车和换行符
主要命令:
序号 命令 说明 最大帧长(Byte)
1 $GPRMC 推荐定位信息 70
2 $GPGGA GPS 定位信息 72
3 $GPVTG 地面速度信息 34
4 $RHXZ 地磁信息 24
5 $GPGSA 当前卫星信息 65
6 $GPGSV 可见卫星数 210
7 $GPGLL 大地坐标信息
指令解析:
1.$GPRMC(推荐定位信息,Recommended Minimum Specific GPS/Transit Data) $GPRMC 语句的基本格式如下: $GPRMC,(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)*hh(CR)(LF)
(1)UTC 时间,hhmmss(时分秒)
(2)定位状态,A=有效定位,V=无效定位
(3)纬度 ddmm.mmmmm 度分)
(4)纬度半球 N(北半球)或 S(南半球)
(5)经度 dddmm.mmmmm 度分)
(6)经度半球 E(东经)或 W(西经)
(7)地面速率(000.0~999.9 节)
(8)地面航向(000.0~359.9 度,以真北方为参考基准)
(9)UTC 日期,ddmmyy(日月年)
(10)磁偏角(000.0~180.0 度,前导位数不足则补 0)
(11)磁偏角方向,E(东)或 W(西) (12)模式指示(A=自主定位,D=差分,R=RTK,E=估算,N=数据无效) 举例如下: $GPRMC,084103.00,A,2233.395441,N,11356.556656,E,0.035,,220618,,,A*7A
2.$GPGGA(GPS 定位信息,Global Positioning System Fix Data) $GPGGA 语句的基本格式如下(其中 M 指单位 M,下同): $GPGGA,(1),(2),(3),(4),(5),(6),(7),(8),(9),M,(10),M,(11),(12)*hh(CR)( LF)
(1)UTC 时间,格式为 hhmmss.ss;
(2)纬度,格式为 ddmm.mmmmmm 度分格式);
(3)纬度半球,N 或 S(北纬或南纬);
(4)经度,格式为 dddmm.mmmmmm 度分格式);
(5)经度半球,E 或 W(东经或西经);
(6)GPS 状态,0=未定位,1=非差分定位,2=差分定位;
(7)正在使用的用于定位的卫星数量(00~12)
(8)HDOP 水平精确度因子(0.5~99.9)
(9)海拔高度(-9999.9 到 9999.9 米)
(10)大地水准面高度(-9999.9 到 9999.9 米)
(11)差分时间(从最近一次接收到差分信号开始的秒数,非差分定位,此项为 空)
(12)差分参考基站标号(0000 到 1023,首位 0 也将传送,非差分定位,此项为 空) 举例如下: $GPGGA,070343.90,2236.360900,N,11352.021690,E,1,04,68.82,-72.83,M,- 1.00,M,,*68
3.$GPVTG(地面速度信息,Track Made Good and Ground Speed) $GPVTG 语句的基本格式如下: $GPVTG,(1),T,(2),M,(3),N,(4),K,(5)*hh(CR)(LF)
(1)以真北为参考基准的地面航向(000~359 度,前面的 0 也将被传输)
(2)以磁北为参考基准的地面航向(000~359 度,前面的 0 也将被传输)
(3)地面速率(000.0~999.9 节,前面的 0 也将被传输)
(4)地面速率(0000.0~1851.8 公里/小时,前面的 0 也将被传输)
(5)模式指示(A=自主定位,D=差分,E=估算,N=数据无效) 举例如下: $GPVTG,,T,,M,0.106,N,0.196,K,A*2A
4.$RHXZ(地磁传感器信息) $RHXZ 语句的基本格式如下: $RHXZ,(1),(2),(3) *hh(CR)(LF)
(1)地磁传感器 X 轴的 16 进制值(高位在前,如 0057 表示 0x0057,范围 0000~FFFF,前面的 0 也将被传输)
(2)地磁传感器 Y 轴的 16 进制值(高位在前,如 FE6E 表示 0xFE6E,范围 0000~FFFF,前面的 0 也将被传输)
(3)地磁传感器 Z 轴的 16 进制值(高位在前,如 0210 表示 0x0210,范围 0000~FFFF,前面的 0 也将被传输) 举例如下: $RHXZ,0057,FE6E,0210*45
5.$GPGSA(当前卫星信息) $GPGSA 语句的基本格式如下: $GPGSA,(1),(2),(3),(3),(3),(3),(3),(3),(3),(3),(3),(3),(3),(3),(4),(5 ),(6)*hh(CR)(LF)
(1)模式,M = 手动,A = 自动。
(2)定位类型,1=未定位,2=2D 定位,3=3D 定位。
(3)正在用于定位的卫星号(01~32)
(4)PDOP 综合位置精度因子(0.5-99.9)
(5)HDOP 水平精度因子 1(0.5-99.9)
(6)VDOP 垂直精度因子(0.5-99.9) 举例如下: $GPGSA,A,3,26,02,05,29,15,21,,,,,,,2.45,1.49,1.94*0E
6.$GPGSV(可见卫星数,GPS Satellites in View) $GPGSV 语句的基本格式如下: $GPGSV,(1),(2),(3),(4),(5),(6),(7),...,(4),(5),(6),(7)*hh(CR)(LF)
(1)GSV 语句总数。
(2)本句 GSV 的编号。
(3)可见卫星的总数(00~12,前面的 0 也将被传输)。
(4)卫星编号(01~32,前面的 0 也将被传输)。
(5)卫星仰角(00~90 度,前面的 0 也将被传输)。
(6)卫星方位角(000~359 度,前面的 0 也将被传输)
(7)信噪比(00~99dB,没有跟踪到卫星时为空)。
注:每条 GSV 语句最多包括四颗卫星的信息,其他卫星的信息将在下一条 $GPGSV 语句中输出。
举例如下: $GPGSV,3,1,12,02,39,117,25,04,02,127,,05,40,036,24,08,10,052,*7E $GPGSV,3,2,12,09,35,133,,10,01,073,,15,72,240,22,18,05,274,*7B $GPGSV,3,3,12,21,10,316,31,24,16,176,,26,65,035,42,29,46,277,18*7A
7.$GPGLL(定位地理信息,Geographic Position) $GPGLL 语句的基本格式如下: $GPGLL,(1),(2),(3),(4),(5),(6),(7)*hh(CR)(LF)
(1)纬度 ddmm.mmmmm(度分)
(2)纬度半球 N(北半球)或 S(南半球)
(3)经度 dddmm.mmmmm(度分)
(4)经度半球 E(东经)或 W(西经)
(5)UTC 时间:hhmmss(时分秒
(6)定位状态,A=有效定位,V=无效定位
(7)模式指示(A=自主定位,D=差分,E=估算,N=数据无效)
代码:
因项目后续调整,代码写完,一直没有实际调试。参考时,请知悉。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/time.h>
#include "uart_oper.h"
#include "gps_oper.h"
#include "play.h" #define GPS_DEV_NAME "/dev/ttyS0" /*需根据实际端口修改*/
#define GPS_LEN 1024
#define TIME_VAL (10*1000) static int gps_analyse(char * buff, GPRMC *gps_data);
static int print_gps(GPRMC * gps_data);
static void set_ensync_deal(SyncStateEnum sync_val);
static int update_time_fromgps(GPRMC * gps_data); /**
*@brief 解析收到的gps信息
*@param buff:收到的gps信息.
gps_data:返回解析到的结构体
*@return 失败返回-1;成功返回0;
*/
static int gps_analyse(char * buff, GPRMC *gps_data)
{
char *ptr = NULL;
if(gps_data == NULL)
{
return - 1;
}
if(strlen(buff) < 0)
{
return - 1;
} ptr = strstr(buff, "$GPRMC"); /*找到GPRMC的位置*/
if(ptr == NULL)
{
return - 1;
} sscanf(ptr, "$GPRMC,%d.%d,%c,%f,N,%f,E,%f,%f,%d,,,%c*",
&(gps_data->time), &(gps_data->ptime), &(gps_data->pos_state),
&(gps_data->latitude), &(gps_data->longitude), &(gps_data->speed),
&(gps_data->direction), &(gps_data->date), &(gps_data->mode)); return 0;
}
/**
*@brief 打印解析后的gps信息
*@param gps_data:解析到的结构体
*@return 失败返回-1;成功返回0;
*/
static int print_gps(GPRMC * gps_data)
{
if(gps_data == NULL)
{
return - 1;
}
printf("GPS state bit : %c [A:有效状态] V:无效状态]\n", gps_data->pos_state);
printf("GPS mode bit :%c [A:自主定位 D:查分定位]\n", gps_data->mode);
printf("Data: 20%02d-%02d-%02d \n", (gps_data->date % 100), /*GPRMC的日期格式为:ddmmyy*/
((gps_data->date % 1000) / 100), (gps_data->date / 10000)); printf("Time: %02d:%02d%02d.%03d\n", ((gps_data->time / 10000 + 8) % 24),
((gps_data->time % 10000) / 100), (gps_data->time % 100), gps_data->ptime); printf("纬度:%d度%d分%d秒\n", (int)(gps_data->latitude / 100), (int)(gps_data->latitude - ((int)(gps_data->latitude / 100 * 100))),
(int)(((gps_data->latitude - ((int)gps_data->latitude / 100 * 100)) - ((int)gps_data->latitude - ((int)gps_data->latitude / 100 * 100))) * 60.0));
printf("经度 :%d度%d分%d秒 \n", ((int)gps_data->longitude) / 100, (int)(gps_data->longitude - ((int)gps_data->longitude / 100 * 100)),
(int)(((gps_data->longitude - ((int)gps_data->longitude / 100 * 100)) - ((int)gps_data->longitude - ((int)gps_data->longitude / 100 * 100)))* 60.0)); printf("速度:%.3f m/s \n", gps_data->speed);
return 0;
} /*
*@brief 用gps时间更新系统时间.相差10ms时进行更新时间
*@param none.
*@return 不更新返回-1,更新返回0.
*/
static int update_time_fromgps(GPRMC * gps_data)
{
struct timeval cur_tv;
struct timeval gps_tv;
struct tm gps_tm;
int ret = -1; gps_tm.tm_year = (gps_data->date % 100) + 2000 - 1900; /*年*/
gps_tm.tm_mon = (gps_data->date % 1000) / 100 - 1; /*月*/
gps_tm.tm_mday = (gps_data->date / 10000); /*日*/
gps_tm.tm_hour = gps_data->time / 10000; /*时*/
gps_tm.tm_min = (gps_data->time % 10000) / 100;/*分*/
gps_tm.tm_sec = gps_data->time % 100; /*秒*/
gps_tm.tm_isdst = - 1; gps_tv.tv_sec = mktime(&gps_tm); /*tm 转换为秒*/
gps_tv.tv_usec = gps_data->ptime *1000;
gettimeofday(&cur_tv, NULL); if(gps_tv.tv_sec != cur_tv.tv_sec)
{
settimeofday(&gps_tv, NULL);
tim->set_timzone(0);
system("hwclock -w");/*软件时间更新硬件时间*/
tim->set_timzone(8);
ret = 0;
}
else if(((gps_tv.tv_usec - cur_tv.tv_usec) > TIME_VAL) || ((cur_tv.tv_usec - gps_tv.tv_usec) > TIME_VAL))
{
/*相差10ms*/
settimeofday(&gps_tv, NULL);
tim->set_timzone(0);
system("hwclock -w");/*软件时间更新硬件时间*/
tim->set_timzone(8);
ret = 0;
}
return ret;
}
/*
*@brief set sync 枚举值(设置系统同步标识)
*@param sync_val 设置的枚举值
*@return none.
*/
static void set_ensync_deal(SyncStateEnum sync_val)
{
if(SetInfo.euSync != sync_val)
{
pthread_rwlock_wrlock(&rwlock_sys);
SetInfo.euSync = sync_val;
pthread_rwlock_wrlock(&rwlock_sys);
}
}
/*
*@brief Gps 处理线程函数
*@param none.
*@return none.
*/
void * Gps_proc_thread(void *arg)
{
int fd;
int ret;
int n = 0;
GPRMC gprmc;
char buff[GPS_LEN];
fd_set Rdfet;
struct timeval timeout;
struct timeval vaild_tv;
struct timeval invaild_tv; pthread_detach(pthread_self()); fd = open(GPS_DEV_NAME, O_RDWR | O_NOCTTY | O_NDELAY);
if(fd < 0)
{
perror("Can't open gps uart port");
set_ensync_deal(SYNC_STATE_NO);
return(void *)"gps dev error";
}
ret = set_serial(fd, 9600, 8, 'N', 1); /*可能需要根据情况调整*/
{
printf("set_serial error\n");
goto endline;
} FD_ZERO(&Rdfet);
printf("Gps proc thread start......\n"); for(;;) /*循环读取gps信息*/
{ timeout.tv_sec = 3;
timeout.tv_usec = 0;
FD_SET(fd, &Rdfet);
ret = select(fd + 1, &Rdfet, NULL, NULL, &timeout); /*监控fd*/
if(ret < 0) /*出错*/
{
perror("select error");
msleep(50);
}
else if(ret > 0) /*有数据可读*/
{
if((n = read(fd, buff, sizeof(buff))) < 0)
{
perror("gps read error");
}
memset(&gprmc, 0 , sizeof(gprmc));
gps_analyse(buff, &gprmc);
#if DEBUG_SWITCH
printf("buff = %s\n", buff);
print_gps(&gprmc);
#endif
if(gprmc.pos_state == 'A') /*有效*/
{
gettimeofday(&vaild_tv, NULL);
// set_ensync_deal(SYNC_STATE_OK);
/*时间相差10ms时,更新系统时间*/
update_time_fromgps(&gprmc);
}
else /*无有效数据*/
{
gettimeofday(&invaild_tv, NULL);
if((invaild_tv.tv_sec - vaild_tv.tv_sec) > 3) /*距离有效GPS时间过去3秒,判断GPS无信号*/
{
set_ensync_deal(SYNC_STATE_NO);
}
}
}
else if(ret == 0) /*timeout*/
{
set_ensync_deal(SYNC_STATE_NO);
}
} /*end for(;;) */ endline:
set_ensync_deal(SYNC_STATE_NO);
close(fd);
return NULL;
}
Linux C 用GPS时间更新系统时间的方法。的更多相关文章
- Linux命令-更新系统时间和硬件时间
查看系统时间和时区: date 查看系统时间date -R 查看时区 修改时区: tzselect 修改时区 或 cp /usr/share/zoneinfo/Asia/Shanghai /etc/l ...
- linux 系统文件类型、系统安装时间、系统启动时间、系统运行时间、设置及显示时间、系统时间和硬件时间
系统文件类型: 1) $mout 2) df -l:仅列出本地文件系统:-h (--human-readable):-T:文件系统类型 $df -lhf 3) file -s (--special-f ...
- Linux的硬件时间、校正Linux系统时间及系统时间调用流程
第一部分: 一)概述: 事实上在Linux中有两个时钟系统,分别是系统时间和硬件时间 UTC是协调世界时(Universal Time Coordinated)英文缩写,它比北京时间早8个小时. ...
- 5 个在 Linux 中管理文件类型和系统时间的有用命令
对于想学习 Linux 的初学者来说要适应使用命令行或者终端可能非常困难.由于终端比图形用户界面程序更能帮助用户控制 Linux 系统,我们必须习惯在终端中运行命令.因此为了有效记忆 Linux 不同 ...
- C# 同步更新系统时间
前言 在定位用户问题时,发现有些电脑,会出现系统时间不是最新的问题. 可能原因: 取消了勾选服务器时间同步 当前安装的系统,是一个未知来源系统,导致系统时间更新失败 而系统时间不正确,会导致IE选项- ...
- QT在linux环境下读取和设置系统时间(通过system来直接调用Linux命令,注意权限问题)
QT在Linux环境下读取和设置系统时间 本文博客链接:http://blog.csdn.NET/jdh99,作者:jdh,转载请注明. 环境: 主机:Fedora12 开发软件:QT 读取系统时间 ...
- ntpdate更新系统时间时报错Can't find host ntp1.aliyun.com: Servname not supported for ai_socktype (-8)
ntpdate更新系统时间时报错Can't find host ntp1.aliyun.com: Servname not supported for ai_socktype (-8) 所报错误: [ ...
- ubuntu下的时间设定(硬件时间,系统时间,本地时间)
问题的来由是在这里: 在cron里设定任务是在凌晨6点执行,检查日志时发现时间总是不对,是在22点左右的时间执行的.研究发现,任务是在本地时间的6点执行了,但不知为什么syslog中的时间都是为utc ...
- java new Date()得到的时间和系统时间不一样
造成这种问题的原因是:操作系统时区跟JVM的时区不一致. [root@paas244 ~]# timedatectl Local time: Thu 2016-12-29 15:35:44 CST U ...
- Log4j 输出的日志中时间比系统时间少了8小时的解决方法,log4j日志文件重复输出
1. 第一个问题:时间少了8小时 Log4j 输出的日志中,时间比系统时间少了8小时,但是 eclipse 控制台输出的日志的时间却是对的. log4j配置如下: #all logger output ...
随机推荐
- 微服务系列之分布式日志 ELK
1.ELK简介 ELK是ElasticSearch+LogStash+Kibana的缩写,是现代微服务架构流行的分布式日志解决方案,旨在大规模服务的日志集中管理查看,极大的为微服务开发人员提供了排查生 ...
- 知识图谱顶会论文(ACL-2022) CAKE:用于多视图KGC的可扩展常识感知框架
CAKE:用于多视图KGC的可扩展常识感知框架.pdf 论文地址:CAKE:Scalable Commonsense-Aware Framework For Multi-View Knowledge ...
- JS逆向实战6-- x轴 y轴 过点触验证码
点触验证码是一种常见的反爬手段 解决方案有两种:一种是直接解决,这需要深度学习机器学习等图像处理技术,以大量的数据训练识别模型,最终达到模型足矣识别图片中的文字提示和应该点击的区域之间的对应关系. 这 ...
- day11-Servlet01
Servlet01 官方api文档:https://tomcat.apache.org/tomcat-8.0-doc/servletapi/index.html Servlet和Tomcat的关系:一 ...
- C#实践炸飞机socket通信
一.前言 最近老师要求做课设,实现一个 "炸飞机" 游戏,我是负责UI界面实现和Socket通信实现的,在这里想总结一下我实现Socket的具体过程,对其中的产生的问题和实现的方法 ...
- EasyExcel对大数据量表格操作导入导出
前言 最近有个项目里面中有大量的Excel文档导入导出需求,数据量最多的文档有上百万条数据,之前的导入导出都是用apache的POI,于是这次也决定使用POI,结果导入一个四十多万的文档就GG了,内存 ...
- django启动报错:DisallowedHost at /
学习django第一天,第一次启动服务就报错,报错内容如下: DisallowedHost at / Invalid HTTP_HOST header: '192.168.116.22:8000'. ...
- 图文并茂解释开源许可证GPL、BSD、MIT、Mozilla、Apache和LGPL的区别
世界上的开源许可证(Open Source License)大概有上百种,而我们常用的开源软件协议大致有GPL.BSD.MIT.Mozilla.Apache和LGPL. 从下图中可以看出几种开源软件协 ...
- TreeUtils工具类一行代码实现列表转树【第三版优化】 三级菜单 三级分类 附视频
一.序言 在日常一线开发过程中,总有列表转树的需求,几乎是项目的标配,比方说做多级菜单.多级目录.多级分类等,有没有一种通用且跨项目的解决方式呢?帮助广大技术朋友给业务瘦身,提高开发效率. 本文将基于 ...
- win11如何双屏幕(1台主机2块显示器)
1.买两块大小相宜.刷新率相同的屏幕(如诺刷新率不一样可能后期造成卡顿现象) 2.用数据线将两块屏幕都接主机上(现在买新款屏幕基本上都会送双头HDMI线,老旧款式可能是VGA) HDMI款 VGA款 ...