Qwiic GPS Clock

Pages
Contributors: bboyho
Favorited Favorite 2

Ex 0: Arduino Serial Monitor

This Arduino example is for the minimalist. All you need is a microcontroller and a Qwiic-enabled GPS to view the date and time in your region via a computer. This will be a template for the subsequent examples.

For each serial output, you'll simply adjust the code as necessary for your preferred display. This can range from LCDs, OLEDs, LED RGB matrices, rows of addressable LED strips, 7-segment LEDs, and alphanumeric LEDs. Depending on your display, you'll need to be careful about the size of your code, how much RAM you are using, and power consumption. We will provide examples for a few displays in this tutorial.

Required Materials

To follow along with this example, you will need the following materials. You may not need everything though depending on what you have. Add it to your cart, read through the guide, and adjust the cart as necessary.

Hardware Hookup

Connecting the boards together is easy. Simply add a Qwiic cable between your Arduino and u-blox GPS module. In this case, we used the RedBoard Qwiic with ATmega328P and Qwiic GPS breakout with SAM-M8Q. Depending on your personal preference, you'll want to adjust the code to view on your display.

SAM-M8Q Connected to an Arduino

Arduino Code

Copy and paste the code in the Arduino IDE. Select the board (in this case the Arduino Uno) and COM port that it enumerated to. Hit the upload button.

language:c
/*
  Getting the time and date in your timezone using Ublox commands
  Originally Written By: davidallenmann
  Modified By: Ho Yun "Bobby" Chan
  SparkFun Electronics
  Date: April 16th, 2019
  License: MIT. See license file for more information but you can
  basically do whatever you want with this code.

  This is a modified example that shows how to query a Ublox module for the current time and date. We also
  turn off the NMEA output on the I2C port. This decreases the amount of I2C traffic
  dramatically.

  Leave NMEA parsing behind. Now you can simply ask the module for the datums you want!

  Additionally, this code has the option to adjust the UTC date and time. The time is adjusted by manually
  entering your time zone's offset. The Daylight Savings Time is automatically calculated with the help of
  Nathan Seidle's Daylight Savings Time example [ https://github.com/nseidle/Daylight_Savings_Time_Example ].
  However, if your country does not observe DST, you can override it with the `enableDST` variable.

  The output for this example is sent through a Serial UART port. Depending on personal preference, you can view
  the time in regular 12-hour format or miltary 24-hour format.

  Feel like supporting open source hardware?
  Buy a board from SparkFun!
  ZED-F9P RTK2: https://www.sparkfun.com/products/15136
  NEO-M8P RTK: https://www.sparkfun.com/products/15005
  SAM-M8Q: https://www.sparkfun.com/products/15106

  Hardware Connections:
  Plug a Qwiic cable into the u-Blox Qwiic-enabled GPS and the RedBoard Qwiic.
  If you don't have a platform with a Qwiic connection use the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
  Open the serial monitor at 115200 baud to see the output.
*/

#include <Wire.h> //Needed for I2C to GPS
#include "SparkFun_Ublox_Arduino_Library.h" //http://librarymanager/All#SparkFun_Ublox_GPS

SFE_UBLOX_GPS myGPS;

long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to Ublox module.
long latitude = 0;
long longitude = 0;
long altitude = 0;
byte SIV = 0;

boolean DST = false; //adjust for Daylight Savings Time, this is calculated automatically. fall back = FALSE, spring forward = TRUE
boolean enableDST = true; //option to disable DST if your country does not observe DST
int zoneOffsetHour = -7; //adjust according to your standard time zone
byte DoW = 0; //needed to adjust hour for DST, or if you want to know the Day of the Week
boolean military = false; //adjust for miltary or AM/PM
boolean AM = false; //AM or PM?

// Use these variables to set the initial time: 3:03:00
int hours = 3;
int minutes = 3;
int seconds = 0;

//Tid Bit: https://www.sparkfun.com/news/2571#yearOrigin
int years = 2003; //year that SparkFun was founded!
int months = 1;  //month that SparkFun was founded!
int days = 3;    //day that SparkFun was founded!

// How fast do you want the clock to update? Set this to 1 for fun.
// Set this to 1000 to get _about_ 1 second timing.
const int CLOCK_SPEED = 1000;
unsigned long lastDraw = 0;




void setup(){
  Serial.begin(115200);
  //while (!Serial)
  //  ; //Wait for user to open terminal
  Serial.println(F("SparkFun Ublox Example"));

  Wire.begin();
  Wire.setClock(400000);   // Set clock speed to be the fastest for better communication (fast mode)


  if (myGPS.begin() == false) //Connect to the Ublox module using Wire port
  {
    Serial.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing."));
    while (1)
      ;
  }

  myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
  myGPS.saveConfiguration();        //Save the current settings to flash and BBR

}//end setup()





void loop(){

  update_Time();   //adjust UTC date/time based on time zone and DST

  displayDigital_Date_Time();  //after calculating, display the date and time

} //end loop




// Simple function to increment seconds and then increment minutes
// and hours if necessary.
void update_Time() {

  //Query module only every second. Doing it more often will just cause I2C traffic.
  //The module only responds when a new position is available
  if (millis() - lastTime > 1000) {
    lastTime = millis(); //Update the timer

    latitude = myGPS.getLatitude();
    longitude = myGPS.getLongitude();
    altitude = myGPS.getAltitude();
    SIV = myGPS.getSIV();

    years = myGPS.getYear();
    months = myGPS.getMonth();
    days = myGPS.getDay();
    hours = myGPS.getHour();
    minutes = myGPS.getMinute();
    seconds = myGPS.getSecond();

    calcZone_DST(); //adjust zone and used to check if it is Daylight Savings Time

  }
  //Serial.print(F("Lat: "));
  //Serial.print(latitude);


  //Serial.print(F(" Long: "));
  //Serial.print(longitude);
  //Serial.print(F(" (degrees * 10^-7)"));


  //Serial.print(F(" Alt: "));
  //Serial.print(altitude);
  //Serial.print(F(" (mm)"));


  //Serial.print(F(" SIV: "));
  //Serial.print(SIV);

  //Serial.println();

}





//Nate's snazzy code!
//Given a year/month/day/current UTC/local offset give me local time
void calcZone_DST() {
  //Since 2007 DST starts on the second Sunday in March and ends the first Sunday of November
  //Let's just assume it's going to be this way for awhile (silly US government!)
  //Example from: http://stackoverflow.com/questions/5590429/calculating-daylight-savings-time-from-only-date

  DoW = day_of_week(); //Get the day of the week. 0 = Sunday, 6 = Saturday
  int previousSunday = days - DoW;

  //DST = false; //Assume we're not in DST
  if (enableDST == true) {
    if (months > 3 && months < 11) DST = true; //DST is happening!

    //In March, we are DST if our previous Sunday was on or after the 8th.
    if (months == 3)
    {
      if (previousSunday >= 8) DST = true;
    }
    //In November we must be before the first Sunday to be DST.
    //That means the previous Sunday must be before the 1st.
    if (months == 11)
    {
      if (previousSunday <= 0) DST = true;
    }
  }




  //adjust time for DST here if it applies to your region
  if (DST == true) {//adjust time Daylight Savings Time
    hours = hours + 1;
  }
  else { //leave time as is for Daylight Time
  }




  //adjust time based on Time Zone
  hours = hours + zoneOffsetHour;

  //adjust for offset zones when hour is negative value
  if (hours < 0) {
    days = days - 1;

    hours = hours + 24;
  }
  else if ( hours > 23)    {
    days = days + 1;

    hours = hours - 24;
  }



  //adjust for AM/PM mode
  if (military == false) {
    if (hours >= 0 && hours <= 11) {// we are in AM
      if (hours == 0) {
        hours = 12;
      }
      AM = true;
    }
    else { // hours >= 12 && hours <= 23, therefore we are in PM!!!
      if (hours > 12  && hours <= 23) {
        hours = hours - 12;
      }
      AM = false;
    }

  }



  /*
    Serial.print("Hour: ");
    Serial.println(hour);
    Serial.print("Day of week: ");
    if(DoW == 0) Serial.println("Sunday");
    if(DoW == 1) Serial.println("Monday");
    if(DoW == 2) Serial.println("Tuesday");
    if(DoW == 3) Serial.println("Wednesday");
    if(DoW == 4) Serial.println("Thursday");
    if(DoW == 5) Serial.println("Friday!");
    if(DoW == 6) Serial.println("Saturday");
  */

}




//Given the current year/month/day
//Returns 0 (Sunday) through 6 (Saturday) for the day of the week
//From: http://en.wikipedia.org/wiki/Calculating_the_day_of_the_week
//This function assumes the month from the caller is 1-12
char day_of_week() {
  //Devised by Tomohiko Sakamoto in 1993, it is accurate for any Gregorian date:
  static int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4  };
  years -= months < 3;
  return (years + years / 4 - years / 100 + years / 400 + t[months - 1] + days) % 7;
}




void displayDigital_Date_Time() {
  if (lastDraw + CLOCK_SPEED < millis())
  {
    lastDraw = millis();

    Serial.print(F("Date: "));

    if (months <= 9) {
      Serial.print(F(" "));
    }
    Serial.print(String(months) + '-');


    if (days <= 9) {
      Serial.print(F("0"));
    }
    Serial.println(String(days) + '-' + String(years));





    Serial.print(F("Time: "));


    if (hours <= 9) {
      Serial.print(' ');

    }
    Serial.print(String(hours) + ':' );


    if (minutes <= 9) {
      Serial.print(F("0"));
    }
    Serial.print(String(minutes) + ':');


    if (seconds <= 9) {
      Serial.print(F("0"));

    }
    Serial.print(String(seconds));


    if (military == false) {
      if (AM == true) {

        Serial.println(F(" AM"));
      }
      else {
        if (AM == false) {
          Serial.println(F(" PM"));
        }
      }
    }
    else {
      Serial.println(); //space between military time for Serial Monitor
    }

    if (myGPS.getDateValid() == false) {
      Serial.println(F("Date is invalid, not enough satellites in view!"));
    }
    if (myGPS.getTimeValid() == false) {
      Serial.println(F("Time is invalid, not enough satellites in view!"));
    }

    Serial.println();
  }

}

Open the Arduino Serial Monitor and set it to 115200 baud. You should start seeing the date and time. By default, the code will display the digital time in Mountain Time in 12-hour mode. Note that the date and time might not be current until enough satellites are in view. Depending on the day of the year, it will adjust the hour as necessary based on the day.

Arduino Serial Monitor with Qwiic GPS Clock

If you live in a different time zone, simply adjust the offset for your region (e.g. zoneOffsetHour) at the top of the code. If you don't live in a region which follows daylight savings time (DST), just adjust the boolean variable to override the calculation by setting the variable enableDST to false. You will also need to adjust the condition statements at the beginning of the calcZone_DST() function since the DST starts/ends on different days of the month. If you are interested in viewing the time in 24-hour, military format, just adjust the boolean variable military to true.