loading

GPS time (UTC) to local time conversion using Arduino

Picture of GPS time (UTC) to local time conversion using Arduino
I have a GPS receiver, Holux M-1000, which you can use it with a laptop, a PDA, or a cellphone through Bluetooth.  I had used it for navigation with Palm TX and Treo700p (yes, I have long been a big fan of Palm PDA series) and Geocaching until I bought an Android smartphone which has a built-in GPS module. So Holux M-1000 has been in my drawer collecting dust for more than a year.

Recently, I wanted to make a small GPS device for measuring distance between two locations, for example, while you are playing golf you can measure how good your driver shot is. There are a lot of commercial product that can do this and much more, but buying is far less fun than making one by yourself (I'm sure Instructables visitor and author will strongly agree with me, right?) There are Android applications as well, but none of them attracts me.

My idea is to add a small LCD, similar size as the size of the GPS, and a microprocessor to acquire data from the GPS, calculate distance, and show it on the LCD along with time and date. I have ordered one of the popular LCD, Nokia 5110, and started doing research on how to get the GPS data, how to interprete the data, and what kind of data I can get.

Well, calculating distance seemed to be easy.  I could find a couple of ways to calculate the distance between two locations. However, converting GPS time(UTC) into local time seemed to be a little tricky, but it was fun to figure out the way to convert time to local time including daylight saving time and date.  I have already posted this part in my blog page and decided to share my Arduino program here. Once I get the LCDand finish assembling the device, I will post another Instructable with full program and pictures, too.  This Instructable includes only how to get the data from the GPS (Holux M-1000) through serial bus and how to convert the GPS time to local time.
 
Remove these adsRemove these ads by Signing Up

Step 1: Connection between the GPS and Arduino

Picture of Connection between the GPS and Arduino
USB pinout.jpg
Holux-Jeonlab connection.jpg
Holux M-1000 has a bluetooth which means it should have serial output somewhere between the GPS module and the bluetooth module.  I opened up the Holux M-1000 and found RX… TX… on the PCB. YES!!  But I needed to know what voltage requirements for these pins. So I searched on internet for a datasheet or instruction manual of Holux M-1000 and found there were already some people tried to read GPS signal from the Holux M-1000 using either Arduino or PIC microcontrollers. Maybe I was not very lucky to find good articles but none of them were quite useful to give me answers what I wanted clearly.  I found the User’s Manual (1371865.pdf) from Holux homepage and I got very important information as below.
  • Pin 4 and 3 on the USB mini B connector on Holux M-1000 are TX and RX (so I don’t have to add wires from the PCB. That’s good news to make my life easier. In fact, I had thought the USB jack is only for charging the battery!)
  • Pins 5 and 1 of the USB connector are Vcharge (5V) and GND, respectively as standard USB pinouts.
  • Those two RX and TX pins’ voltage range is 3.3 – 5V
  • Data format: NMEA0183 V3.01, GGA, RMC, VTG, GSA, GSV
  • Power consumption: 40 – 50mA in normal mode, 35mA in power saving mode
In order to read serial data from the GPS, I used Jeonlab mini (minimal Arduino I made), but any Arduino compatible board will work. The GPS (Holux M-1000) and the Jeonlab mini v1.3 with an FTDI breakout board are shown in the picture. I have USB A to mini-B cable but I didn’t want to cut the cable, so I used a female USB-A connector as shown in another picture. Note that only 3 pins (V+, GND, and TX from GPS) are used since I only need to read serial data from the GPS, not sending any command or data to it. For this testing, I connected the TX pin from the GPS to one of digital pins on JeonLab mini, 10, and set this pin as software serial port.  Since I don't have an LCD yet, I needed to save the hardware serial port for the FTDI breakout board to communicate with PC. That's why I set up the software serial port for the GPS. For more detail, see attached Arduino sketch.

And another picture shows how they are connected each other. The FTDI breakout board is connected to my computer through USB cable.

Step 2: GPS data structure and Arduino parsing functions

Now, I’m not familiar with NMEA data format, so I searched on internet again and found some good sites here and there. There are bunch of GPS information you can get from sentences that Holux M-1000 generates periodically as GGA, RMC, VTG, GSA, and GSV, but I don’t need all of them. All I need is latitude and longitude actually, but additional information such as time and date, bearing, speed will be good to know as well.  The sentence, RMC has all of these. In the first link above, the RMC sentence is described as below with an example.

RMC - NMEA has its own version of essential gps pvt (position, velocity, time) data. It is called RMC, The Recommended Minimum, which will look similar to:

$GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A

Where:
     RMC          Recommended Minimum sentence C
     123519       Fix taken at 12:35:19 UTC
     A            Status A=active or V=Void.
     4807.038,N   Latitude 48 deg 07.038' N
     01131.000,E  Longitude 11 deg 31.000' E
     022.4        Speed over the ground in knots
     084.4        Track angle in degrees True
     230394       Date - 23rd of March 1994
     003.1,W      Magnetic Variation
     *6A          The checksum data, always begins with *


Each parameter is separated by a comma.  From Arduino version 1.0, serial library includes parsing function which makes serial data reading much easier than before. Below is a part of my program to read these data from RMC sentence.


      gpsTime(gps.parseInt());
      gps.parseFloat(); //discard unnecessary part
      gpsLatLong(gps.parseInt(), gps.parseInt(), gps.parseInt(), gps.parseInt());
      gpsSpeed = gps.parseFloat()*1.852; //knot to km/h
      gpsBearing = gps.parseFloat();
      gpsDate(gps.parseInt());

gpdTime(), gpsLatLong() and gpsDate() are functions I made, which I will explain in the next step, and .parseInt(), .parseFloat() are the Arduino functions to parse integer and float values from serial bus. The 'gps' in front of those parsing functions is just the name of my serial port which is defined in the beginning of the program. The entire program will be attached to the last step.

 

Step 3: Functions to interpret GPS data

Below are the functions I made to interpret GPS data.

gpsTime() extracts hour, minute and second which is UTC.
gpsLatLong() extracts latitude and longitude.
gpsDate() extracts date.

void gpsTime(long UTC)
{
  gpsHour = int(UTC/10000);
  gpsMin = int(UTC%10000/100);
  gpsSec = UTC%100;
}

void gpsLatLong(int lat1, int lat2, int long1, int long2)
{
  gpsLat = int(lat1/100) + (lat1%100)/60.0 + float(lat2)/10000.0/60.0;
  gpsLong = int(long1/100) + (long1%100)/60.0 + float(long2)/10000.0/60.0;
}

void gpsDate(long dateRead)
{
  gpsDay = int(dateRead/10000);
  gpsMonth = int(dateRead%10000/100);
  gpsYear = dateRead%100; //last 2 digits, e.g. 2013-> 13

}

The calculation used in these functions are quite straightforward so I won't elaborate to explain the detail, but if you have any questions, let me know.

Step 4: GPS time (UTC) to local time conversion

The entire Arduino sketch is attached.  Let me explain how I programmed to convert the UTC to local time below that is a part of the main loop.

      if (gpsYear%4 == 0) DaysAMonth[1] = 29; //leap year check

If it is leap year, add one day to the number of days of February.  Actually the leap year is not simply every 4 years but there are more conditions but for the next 10-20 years it won't happen and we can simply calculate it every 4 years.

      //Time zone adjustment
      gpsHour += TimeZone;

TimeZone is a constant defined at the beginning of the program.  You need to change this number according to where you live.

      //DST adjustment
      if (gpsMonth*100+gpsDay >= DSTbegin[gpsYear-13] &&
        gpsMonth*100+gpsDay < DSTend[gpsYear-13]) gpsHour += 1;

I added a DST (daylight saving time) table in an array, the starting date and ending date. If current date is withing this range, add 1 hour.

The section below is to correct time and date after the timezone adjustment.  For example, if the adjusted hour is less than 0 or greater than 24, you need to adjust the day as well. As such, you need to adjust Month and Year, too.

      if (gpsHour < 0)
      {
        gpsHour += 24;
        gpsDay -= 1;
        if (gpsDay < 1)
        {
          if (gpsMonth == 1)
          {
            gpsMonth = 12;
            gpsYear -= 1;
          }
          else
          {
            gpsMonth -= 1;
          }
          gpsDay = DaysAMonth[gpsMonth-1];
        }
      }
      if (gpsHour >= 24)
      {
        gpsHour -= 24;
        gpsDay += 1;
        if (gpsDay > DaysAMonth[gpsMonth-1])
        {
          gpsDay = 1;
          gpsMonth += 1;
          if (gpsMonth > 12) gpsYear += 1;
        }
      }

 

That's all for this instructable. Hope this helps someone who wants to convert GPS time to local time.

Thanks for reading.
philip4211 months ago

Actually GPS time currently differs from UTC by 16 seconds, primarily because GPS doesn't add Leap Seconds. So you'll need to make that adjustment in your code.

I've got an excellent UTC app on my phone which shows GPS time vs. actual UTC and local time.