极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 28178|回复: 11

分享一个GPS时间的转换程序

[复制链接]
发表于 2014-9-11 01:35:16 | 显示全部楼层 |阅读模式
本帖最后由 李小英 于 2014-9-11 19:19 编辑

程序的核心部分来自一位叫严泽远的大神(就是做辉光管那位),再加上自己写的经度转换时区的部分就完成了这个程序。嗯,写得比较粗糙(我是小白,别见怪)。
程序根据经度计算出所在时区的时间,包括年月日的处理。测试结果没问题,不知还有没有BUG,如果有请告诉我,谢谢。

嗯,应该可以满足大部分做GPS时钟的需求了。
下面是程序。(库文件可以在论坛搜)

#include <SoftwareSerial.h>
#include <TinyGPS.h>
SoftwareSerial gpsSerial(5, 4);
TinyGPS gps;
int utc_year, C_L, GMT;
byte utc_month, utc_day, utc_hour, utc_minute, utc_second;
byte MM, DD, HH;
int YY;
float lat, lon, alt;
void setup() {
  Serial.begin(4800);
  gpsSerial.begin(9600);

}

void loop() {
  while (gpsSerial.available()) {
    if (gps.encode(gpsSerial.read())) {
      gps.crack_datetime(&utc_year, &utc_month, &utc_day, &utc_hour, &utc_minute, &utc_second);
      gps.f_get_position(&lat, &lon);

    }
  }
  
  
  YY= utc_year;
  MM= utc_month;
  DD= utc_day;
  HH= utc_hour;

  
  


if (utc_year > 0)
{
     if (YY % 400 == 0 || YY % 100 != 0 && YY % 4 == 0)
    {
      C_L = 0;
    } else {
      C_L = 1;
    }
    if ((int)(lon + 0.5) % 15 < 7.5)
    {
      GMT = (int)(lon + 0.5) / 15;
    }
    else
    {
      GMT = ((int)(lon + 0.5) / 15) + 1;
    }

  if ((HH + GMT) < 24)//如果与格林尼治时间处于同一天则仅加小时
  {
    HH += GMT;
  }
  else//如果已经晚于格林尼治时间1天则进行日期处理
  {
    HH = HH + GMT - 24;//先得出时间
    if (MM == 1 || MM == 3 || MM == 5 || MM == 7 || MM == 8 || MM == 10) //大月份(12月单独处理)
    {
      if (DD < 31) DD++;
      else
      {
        DD = 1;
        MM ++;
      }
    }
    else if (MM == 4 || MM == 6 || MM == 9 || MM == 11)//小月份2月单独处理)
    {
      if (DD < 30) DD++;
      else
      {
        DD = 1;
        MM ++;
      }
    }
    else if (MM == 2)//处理2月份
    {
      if ((DD == 29) || (DD == 28 && C_L == 0)) //本来是闰年且是2月29日 或者不是闰年且是2月28日
      {
        DD   = 1;
        MM   ++;
      }
      else   DD++;
    }
    else if (MM == 12)     //处理12月份
    {
      if (DD < 31)        DD++;
      else                //跨年最后一天
      {
        DD     =   1;
        MM     =   1;
        YY     ++;
      }
    }
  }
}
else
{
  if (HH >= GMT)  HH  -= GMT; //如果与格林尼治时间处于同一天则仅减小时即可
  else   //如果已经早于格林尼治时间1天则进行日期处理
  {
    HH    =   HH + 24 - GMT;            //先得出时间
    if (MM == 2 || MM == 4 || MM == 6 || MM == 8 || MM == 9 || MM == 11) //上月是大月份(1月单独处理)
    {
      if (DD > 1)   DD--;
      else
      {
        DD  =   31;
        MM  --;
      }
    }
    else if (MM == 5 || MM == 7 || MM == 10 || MM == 12)//上月是小月份2月单独处理)                       //上月是小月份2月单独处理)
    {
      if (DD > 1)   DD --;
      else
      {
        DD    =  30;
        MM    --;
      }
    }
    else if (MM == 3)     //处理上个月是2月份
    {
      if ((DD == 1)  && C_L == 0)//不是闰年
      {
        DD   =   28;
        MM  --  ;
      }
      else  DD--;
    }
    else if (MM == 1)     //处理1月份
    {
      if (DD > 1)  DD--;
      else                //新年第一天
      {
        DD   =   31;
        MM   =   12;
        YY   --;
      }
    }
  }
}



  Serial.print("UTC ");
  Serial.print(YY);
  Serial.print("/ ");
  Serial.print(MM);
  Serial.print("/ ");
  Serial.print(DD);
  Serial.print("   ");
  Serial.print(HH);
  Serial.print(':');
  Serial.print(utc_minute);
  Serial.print(':');
  Serial.print(utc_second);
  Serial.println(' ');


  
}



回复

使用道具 举报

发表于 2014-9-11 09:22:07 | 显示全部楼层
本帖最后由 eddiewwm 于 2014-9-11 09:24 编辑

/ ...如果运行多次,结果就会累加..../

所述的程序確是這樣要求的啊, 就是每次加 8 小時(float lon = 112.96;//经度,int HH = 16;):
===================================
    if ((int)(lon + 0.5) % 15 < 7.5)
    {
      GMT = (int)(lon + 0.5) / 15;
    }
    else
    {
      GMT = ((int)(lon + 0.5) / 15) + 1;
    }

  if ((HH + GMT) < 24)//如果与格林尼治时间处于同一天则仅加小时
  {
    HH += GMT;
  }
==================================
回复 支持 反对

使用道具 举报

发表于 2014-9-11 09:38:01 | 显示全部楼层
我觉得是不是不需要这么复杂的算法,每个时区是15度,只要做一个24行的表,根据精度查表就可以知道该加几还是减几了。每次都用gps时间做加减法就行了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-9-11 11:51:11 | 显示全部楼层
eddiewwm 发表于 2014-9-11 09:22
/ ...如果运行多次,结果就会累加..../

所述的程序確是這樣要求的啊, 就是每次加 8 小時(float lon = ...

如果只运行一次计算,结果是正确的。如果循环的话,程序会把上一次的计算结果再次代入计算。显示的结果就会有很多个…………………………
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-9-11 11:53:36 | 显示全部楼层
老胖熊 发表于 2014-9-11 09:38
我觉得是不是不需要这么复杂的算法,每个时区是15度,只要做一个24行的表,根据精度查表就可以知道该加几还 ...

我一开始也是这样打算,但是如果考虑到年月日的话,程序的复杂程度也是差不多的……
回复 支持 反对

使用道具 举报

发表于 2014-9-11 14:30:55 | 显示全部楼层
我没仔细看程序,斗胆说一句,这种运行多次结果累加的情况,应该是没有在每次运行的时候对时间赋初值。按说,应该用每次读到的gps数据赋初值,然后在这个初值的基础上处理时区。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-9-11 19:02:31 | 显示全部楼层
老胖熊 发表于 2014-9-11 14:30
我没仔细看程序,斗胆说一句,这种运行多次结果累加的情况,应该是没有在每次运行的时候对时间赋初值。按说 ...

话说已经搞定的……要重新赋值还要把转换程序放到下一个花括号……………………
回复 支持 反对

使用道具 举报

发表于 2014-9-24 12:15:57 | 显示全部楼层
我来把它改到OLED上来实验下,正在找这样的程序,谢谢先!!
回复 支持 反对

使用道具 举报

发表于 2014-9-24 18:45:30 | 显示全部楼层
本帖最后由 504835618 于 2014-9-24 18:47 编辑

按照上面程序下载到ARDUINO里用串口检测,怎么没UTC时间呢?GPS模块在室外,用蓝牙传输的,GPS信号用的是硬串口Serial1,监视串口是Serial
下面是修改了的代码
//#include <SoftwareSerial.h>
#include <TinyGPS.h>
//SoftwareSerial gpsSerial(5, 4);// RX, TX
TinyGPS gps;
int utc_year, C_L, GMT;
byte utc_month, utc_day, utc_hour, utc_minute, utc_second;
byte MM, DD, HH;
int YY;
float lat, lon, alt;
void setup() {
  Serial.begin(9600);
  //gpsSerial.begin(9600);
  Serial1.begin(9600);

}
/*void loop() {
  while (gpsSerial.available()) {
    if (gps.encode(gpsSerial.read())) {
      gps.crack_datetime(&utc_year, &utc_month, &utc_day, &utc_hour, &utc_minute, &utc_second);
      gps.f_get_position(&lat, &lon);*/
  void loop() {
  while (Serial1.available()) {
    if (gps.encode(Serial1.read())) {
      gps.crack_datetime(&utc_year, &utc_month, &utc_day, &utc_hour, &utc_minute, &utc_second);
      gps.f_get_position(&lat, &lon);   
      
      

    }
  }
  YY= utc_year;
  MM= utc_month;
  DD= utc_day;
  HH= utc_hour;
if (utc_year > 0)
  {
    if (YY % 400 == 0 || YY % 100 != 0 && YY % 4 == 0)
    {
      C_L = 0;
    }
    else {
      C_L = 1;
    }
    if ((int)(lon + 0.5) % 15 < 7.5)
    {
      GMT = (int)(lon + 0.5) / 15;
    }
    else
    {
      GMT = ((int)(lon + 0.5) / 15) + 1;
    }

    if ((HH + GMT) < 24)//如果与格林尼治时间处于同一天则仅加小时
    {
      HH += GMT;
    }
    else//如果已经晚于格林尼治时间1天则进行日期处理
    {
      HH = HH + GMT - 24;//先得出时间
      if (MM == 1 || MM == 3 || MM == 5 || MM == 7 || MM == 8 || MM == 10) //大月份(12月单独处理)
      {
        if (DD < 31) DD++;
        else
        {
          DD = 1;
          MM ++;
        }
      }
      else if (MM == 4 || MM == 6 || MM == 9 || MM == 11)//小月份2月单独处理)
      {
        if (DD < 30) DD++;
        else
        {
          DD = 1;
          MM ++;
        }
      }
      else if (MM == 2)//处理2月份
      {
        if ((DD == 29) || (DD == 28 && C_L == 0)) //本来是闰年且是2月29日 或者不是闰年且是2月28日
        {
          DD   = 1;
          MM   ++;
        }
        else   DD++;
      }
      else if (MM == 12)     //处理12月份
      {
        if (DD < 31)        DD++;
        else                //跨年最后一天
        {
          DD     =   1;
          MM     =   1;
          YY     ++;
        }
      }
    }
  }
  else
  {
    if (HH >= GMT)  HH  -= GMT; //如果与格林尼治时间处于同一天则仅减小时即可
    else   //如果已经早于格林尼治时间1天则进行日期处理
    {
      HH    =   HH + 24 - GMT;            //先得出时间
      if (MM == 2 || MM == 4 || MM == 6 || MM == 8 || MM == 9 || MM == 11) //上月是大月份(1月单独处理)
      {
        if (DD > 1)   DD--;
        else
        {
          DD  =   31;
          MM  --;
        }
      }
      else if (MM == 5 || MM == 7 || MM == 10 || MM == 12)//上月是小月份2月单独处理)                       //上月是小月份2月单独处理)
      {
        if (DD > 1)   DD --;
        else
        {
          DD    =  30;
          MM    --;
        }
      }
      else if (MM == 3)     //处理上个月是2月份
      {
        if ((DD == 1)  && C_L == 0)//不是闰年
        {
          DD   =   28;
          MM  --  ;
        }
        else  DD--;
      }
      else if (MM == 1)     //处理1月份
      {
        if (DD > 1)  DD--;
        else                //新年第一天
        {
          DD   =   31;
          MM   =   12;
          YY   --;
        }
      }
    }
  }

  Serial.print("UTC ");
  Serial.print(YY);
  Serial.print("/ ");
  Serial.print(MM);
  Serial.print("/ ");
  Serial.print(DD);
  Serial.print("   ");
  Serial.print(HH);
  Serial.print(':');
  Serial.print(utc_minute);//分
  Serial.print(':');
  Serial.print(utc_second);//秒
  Serial.println(' ');
}
回复 支持 反对

使用道具 举报

发表于 2014-9-24 19:11:29 | 显示全部楼层
写的太复杂了,没必要啊
回复 支持 反对

使用道具 举报

发表于 2014-10-20 21:24:43 | 显示全部楼层
还是不懂,能否详细讲解?
回复 支持 反对

使用道具 举报

发表于 2014-12-25 19:34:23 | 显示全部楼层
谢谢分享,学习一下
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-17 01:54 , Processed in 0.041166 second(s), 24 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表