Science 3D
Published © GPL3+

Satellite Clock with a Back to the Future Look

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

IntermediateShowcase (no instructions)15 hours14,295

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
MAX7219 8 digits
×1
GY-GPS6MV1 NEO-6M GPS Module
×1
MP2307 Pro Mini 3A DC-DC Converter Step Down Buck Power Module
×1

Software apps and online services

EasyEDA
JLCPCB EasyEDA

Story

Read more

Custom parts and enclosures

Face

Back

Button

Casing

Schematics

Circuit board

TOP PCB

BOTTOM PCB

Code

Satellite Clock

Arduino
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);
}

Credits

Science 3D

Science 3D

11 projects • 25 followers
I have a background in electronics, since 1984. I used to work as a programmer for a couple of years. Now, I am working as a DBA.

Comments