李小英 发表于 2014-9-11 01:35:16

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

本帖最后由 李小英 于 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--;
      }
      elseDD--;
    }
    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(' ');



}



eddiewwm 发表于 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 static/image/common/back.gif
/ ...如果运行多次,结果就会累加..../

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

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

李小英 发表于 2014-9-11 11:53:36

老胖熊 发表于 2014-9-11 09:38 static/image/common/back.gif
我觉得是不是不需要这么复杂的算法,每个时区是15度,只要做一个24行的表,根据精度查表就可以知道该加几还 ...

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

老胖熊 发表于 2014-9-11 14:30:55

我没仔细看程序,斗胆说一句,这种运行多次结果累加的情况,应该是没有在每次运行的时候对时间赋初值。按说,应该用每次读到的gps数据赋初值,然后在这个初值的基础上处理时区。

李小英 发表于 2014-9-11 19:02:31

老胖熊 发表于 2014-9-11 14:30 static/image/common/back.gif
我没仔细看程序,斗胆说一句,这种运行多次结果累加的情况,应该是没有在每次运行的时候对时间赋初值。按说 ...

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

504835618 发表于 2014-9-24 12:15:57

我来把它改到OLED上来实验下,正在找这样的程序,谢谢先!!

504835618 发表于 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--;
      }
      elseDD--;
      }
      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(' ');
}

duanliangcong 发表于 2014-9-24 19:11:29

写的太复杂了,没必要啊

huangshan78 发表于 2014-10-20 21:24:43

还是不懂,能否详细讲解?

suoma 发表于 2014-12-25 19:34:23

谢谢分享,学习一下
页: [1]
查看完整版本: 分享一个GPS时间的转换程序