Project showcase

Satellite Clock with a Back to the Future Look © GPL3+

A clock that gets the date-time from multiple satellites and calculate the time zone dynamically.

  • 8,219 views
  • 21 comments
  • 46 respects

Components and supplies

Apps and online services

About this project

I really like clocks and it's been a long time since I decided to build my own clock based on satellite calculations.

This clock takes the time from satellites above, calculate the time zone and display several information such as year, month, day, the number of satellites that are in use, and the time, I had to make many research to find the code that would work with that project.

I had a couple of MAX7219 8 digits and a GPS module laying around and decided that it was time to use them.

First, you have to download and install the library: TinyGPS++ from GitHub from this site: https://github.com/mikalhart/TinyGPSPlus/blob/master/src/TinyGPS%2B%2B.h

Once the library is installed, you can upload the code to Arduino. In this project, an Arduino Nano was use but an Arduino Mini pro could be best but, I did not have one on hand.

The circuit is quite simple as you can see in the image below

And this gives the following circuit board

The following image contains an overview of all the modules connected together

The G-Code required to cut the PCB was produced using Flatcam and the final result is shown the following image.

To see all the details, go to my YouTube video:

also on Arduino.cc

Note: If you decide to build this project, you must know this:

  • It can require up to 5 minutes to get the correct time (other than 00:00:00) or date
  • The information displayed may be wrong until enough satellite are detected such as the hour which may display wrong information like 35:00:00
  • You must wait to get at least 4-5 satellite before to confirm that the time is OK

Code

Satellite ClockArduino
updated code 2020-04-20 14h14
/*
  -- horloge satellite
*/

#include <TinyGPS++.h> // uses library TinyGPSPlus-master.zip
#include <SoftwareSerial.h>

#include "LedControl.h" //  need the library
//   Pin 12 is connected to the DOUT (SPI-MISO) of the first MAX7221
//   Pin 11 is connected to the CLK  (SPI-MOSI) of the first MAX7221
//   Pin 10 is connected to the LOAD (SPI-SS)(/CS)  of the first MAX7221
// 1 as we are only using 1 MAX7219
// pin 2 connected to ds18b20
LedControl lc = LedControl(12, 11, 10, 2); // lc is our object

/*
   This sample sketch demonstrates the normal use of a TinyGPS++ (TinyGPSPlus) object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);

// The TinyGPS++ object
TinyGPSPlus gps;

int HHH = 00;
int MMM = 00;
int SSS = 00;
int YR;
int MT;
int DY;

int Second_PIN = 5; // PWM
int Minute_PIN = 6; // PWM
int Hour_PIN = 9; // PWM
int Light_PIN = 13; // PWM

int PWM_Min = 10;
int PWM_Max = 245;

int GetTimeState = LOW;             // GetTimeState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated
const long GetTimeInterval = 1000;           // GetTimeInterval at which to blink (milliseconds)
int Time_Zone;

#include <EEPROM.h>
int EEPROM_addr = 0;

int FirstBoot = 1;

//// SWITCH B1 ////
static const int B1_buttonPin = 7;                    // sw pull upp w resistor to GND
int B1_buttonStatePrevious = LOW;                      // previousstate of the switch
unsigned long minB1_buttonLongPressDuration = 3000;    // Time we wait before we see the press as a long press
unsigned long B1_buttonLongPressMillis;                // Time in ms when we the B1_button was pressed
bool B1_buttonStateLongPress = false;                  // True if it is a long press
const int intervalB1_button = 50;                      // Time between two readings of the B1_button state
unsigned long previousB1_buttonMillis;                 // Timestamp of the latest reading
unsigned long B1_buttonPressDuration;                  // Time the B1_button is pressed in ms
unsigned long currentMillis;          // Variabele to store the number of milleseconds since the Arduino has started
int Daylight_saving_time = 0;

int Calibration_time = 2000;

int LED_PIN = 13;

long randNumber;


void setup()
{
  pinMode(LED_PIN, OUTPUT);  // sets the pin as output
  pinMode(Light_PIN, OUTPUT);  // sets the pin as output

  randomSeed(analogRead(0)); // nothing connected to 0 so read sees noise

  Serial.begin(GPSBaud);
  ss.begin(GPSBaud);
  pinMode(Hour_PIN, OUTPUT);  // sets the pin as output
  pinMode(Minute_PIN, OUTPUT);  // sets the pin as output
  pinMode(Second_PIN, OUTPUT);  // sets the pin as output

  analogWrite(Light_PIN, 125);

  Daylight_saving_time = EEPROM.read(EEPROM_addr);
  Serial.print("EEPROM Daylight_saving_time = ");
  Serial.println(Daylight_saving_time);

  //// SWITCH B1 ////
  pinMode(B1_buttonPin, INPUT_PULLUP);          // set B1_buttonPin as input


  //// DISPLAY
  // the zero refers to the MAX7219 number, it is zero for 1 chip
  lc.shutdown(0, false); // turn off power saving, enables display
  lc.setIntensity(0, 2); // sets brightness (0~15 possible values)
  lc.clearDisplay(0);// clear screen
  lc.shutdown(1, false); // turn off power saving, enables display
  lc.setIntensity(1, 2); // sets brightness (0~15 possible values)
  lc.clearDisplay(0);// clear screen


  Serial.println(F("Satellite clock"));
  Serial.print(F("TinyGPS++ library v: ")); Serial.println(TinyGPSPlus::libraryVersion());

  Serial.println("Boot Complete");

}

void loop()
{
  /* -- ref : https://forum.arduino.cc/index.php?topic=166099.0
    la planete = 360 degre divise par 24 fuseaux
    chaque fuseau est de 15 degre de LONGITUDE
    on estime le calcul a partir du centre du premier fuseau (7.5 degre)
  */
  Time_Zone = ((gps.location.lng() - 7.5) / 15);

  currentMillis = millis();    // store the current time
  //// SWITCH B1 ////
  readB1_buttonState();           // read the B1_button state

  if (Daylight_saving_time == 1)
  {
    digitalWrite(LED_PIN, HIGH);
  }
  else
  {
    digitalWrite(LED_PIN, LOW);
  }

  // This sketch displays information every time a new sentence is correctly encoded.
  while (ss.available() > 0)
    if (gps.encode(ss.read()))
      getTime(Time_Zone);

  if (millis() > 5000 && gps.charsProcessed() < 10)
  {
    Serial.println(F("No GPS detected: check wiring."));
    while (true);
  }

  if (currentMillis - previousMillis >= GetTimeInterval)
  {
    previousMillis = currentMillis;
    if (HHH < 10) // add a zero if minute is under 10
      Serial.print("0");
    Serial.print(HHH);
    Serial.print(F(":"));
    
    if (MMM < 10) // add a zero if minute is under 10
      Serial.print("0");
    Serial.print(MMM);
    Serial.print(F(":"));
    
    if (SSS < 10) // add a zero if minute is under 10
      Serial.print("0");
    Serial.print(SSS);

    Serial.print(" --- GPS: ");
    Serial.print(gps.satellites.value());

    Serial.print(" - Time Zone: ");
    Serial.print(Time_Zone);

    Serial.println();
  }

  displayTime(HHH, MMM, SSS);
  displayZone(gps.satellites.value());
  displayDate(YR, MT, DY);


  //fin LOOP
}

void getTime(int TimeZone)
{
  if (gps.time.isValid())
  {
    HHH = gps.time.hour();
    MMM = gps.time.minute();
    SSS = gps.time.second();
  }
  //  else
  //    Serial.print(F("INVALID"));

  if (gps.date.isValid())
  {
    YR = gps.date.year();
    MT = gps.date.month();
    DY = gps.date.day();
  }

  if (HHH <= abs(TimeZone))
    HHH = 24 + TimeZone + HHH;
  else
    HHH = TimeZone + HHH;

  // heure avancee dete
  HHH = HHH + Daylight_saving_time;

  //  if (HHH > 12)
  //    HHH = HHH - 12;


}




// Function for reading the B1_button state
void readB1_buttonState()
{
  /*
     Bas on Tech - LONG PRESS B1_button
     This course is part of the courses on https://arduino-tutorials.net

     (c) Copyright 2019 - Bas van Dijk / Bas on Tech
     This code and course is copyrighted. It is not allowed to use these courses commercially
     without explicit written approval

     YouTube:    https://www.youtube.com/c/BasOnTech
     Facebook:   https://www.facebook.com/BasOnTechChannel
     Instagram:  https://www.instagram.com/BasOnTech
     Twitter:    https://twitter.com/BasOnTech

  */

  // If the difference in time between the previous reading is larger than intervalB1_button
  if (currentMillis - previousB1_buttonMillis > intervalB1_button) {

    // Read the digital value of the B1_button (LOW/HIGH)
    int B1_buttonState = digitalRead(B1_buttonPin);

    // If the B1_button has been pushed AND
    // If the B1_button wasn't pressed before AND
    // IF there was not already a measurement running to determine how long the B1_button has been pressed
    if (B1_buttonState == HIGH && B1_buttonStatePrevious == LOW && !B1_buttonStateLongPress)
    {
      B1_buttonLongPressMillis = currentMillis;
      B1_buttonStatePrevious = HIGH;
      Serial.println("B1_button pressed");
    }

    // Calculate how long the B1_button has been pressed
    B1_buttonPressDuration = currentMillis - B1_buttonLongPressMillis;

    // If the B1_button is pressed AND
    // If there is no measurement running to determine how long the B1_button is pressed AND
    // If the time the B1_button has been pressed is larger or equal to the time needed for a long press
    if (B1_buttonState == HIGH && !B1_buttonStateLongPress && B1_buttonPressDuration >= minB1_buttonLongPressDuration)
    {
      B1_buttonStateLongPress = true;
      Daylight_saving_time = !Daylight_saving_time;

      if (Daylight_saving_time == 1)
      {
        EEPROM.write(EEPROM_addr, 1);
      }
      else
      {
        EEPROM.write(EEPROM_addr, 0);
      }

      Serial.println("B1_button long pressed");
    }

    // If the B1_button is released AND
    // If the B1_button was pressed before
    if (B1_buttonState == LOW && B1_buttonStatePrevious == HIGH) {
      B1_buttonStatePrevious = LOW;
      B1_buttonStateLongPress = false;
      Serial.println("B1_button released");

      // If there is no measurement running to determine how long the B1_button was pressed AND
      // If the time the B1_button has been pressed is smaller than the minimal time needed for a long press
      if (!B1_buttonStateLongPress && B1_buttonPressDuration < minB1_buttonLongPressDuration) {
        Serial.println("B1_button pressed shortly");
      }
    }

    // store the current timestamp in previousB1_buttonMillis
    previousB1_buttonMillis = currentMillis;

  }

}



void displayDate(int y, int m, int d)
{
  int input_number = y;
  int thousands = (input_number / 1000);
  int hundreds = ((input_number / 100) % 10);
  int tens = ((input_number / 10) % 10);
  int ones = (input_number % 10);

  lc.setDigit(0, 7, thousands, false);
  lc.setDigit(0, 6, hundreds, false);
  lc.setDigit(0, 5, tens, false);
  lc.setDigit(0, 4, ones, true);
  lc.setDigit(0, 3, m / 10, false);
  lc.setDigit(0, 2, m % 10, true);
  lc.setDigit(0, 1, d / 10, false);
  lc.setDigit(0, 0, d % 10, false);
}


void displayTime(int h, int m, int s)
{
  lc.setDigit(1, 5, h / 10, false);
  lc.setDigit(1, 4, h % 10, true);
  lc.setDigit(1, 3, m / 10, false);
  lc.setDigit(1, 2, m % 10, true);
  lc.setDigit(1, 1, s / 10, false);
  lc.setDigit(1, 0, s % 10, false);
}


void displayZone(int z)
{
  int timeZone;
  timeZone = true;

  z = abs(z);

  lc.setDigit(1, 7, z / 10, false);
  lc.setDigit(1, 6, z % 10, timeZone);
}

Custom parts and enclosures

Schematics

Circuit board
Circuit board wwkv0ymalo
TOP PCB
BOTTOM PCB

Comments

Similar projects you might like

Arduino Cheap Minimal Parts Digital Clock

Project showcase by garysat

  • 17,890 views
  • 38 comments
  • 33 respects

eDOT - Arduino Based Precision Clock and Weather Station

Project tutorial by antiElectron

  • 14,975 views
  • 6 comments
  • 36 respects

Weather Forecast Clock Using Old Alarm and Arduino

Project showcase by LenkaDesign

  • 9,479 views
  • 19 comments
  • 43 respects

Italian Word Clock

Project tutorial by Tittiamo

  • 6,723 views
  • 5 comments
  • 15 respects

Arduino OLED Word Clock

Project showcase by garysat

  • 6,514 views
  • 1 comment
  • 12 respects

Arduino Analog/Digital Clock with Nokia 5110

Project showcase by garysat

  • 5,212 views
  • 5 comments
  • 10 respects
Add projectSign up / Login