Section   Top   Arduino   Clock Pics  Displays  Uno Quartz Mod  Pulse Monitor  Case Mod  Video  Schematic  PCB  Code

 

 

 

   Home   Master Clock MK2  Binary Clock    Atomic Time Sync Circuit     Slave Clocks     Calendar Clock      Master Clock       Voltmeter Clock      Guestbook

LCD Master Bracket Clock

 

This clock is designed to backup my Master Clock should it fail or need maintenance and is portable with battery backup.

This clock uses an Arduino 328 Microprocessor to decode Time from the DCF77 "Atomic" Clock in Mainflingen near Frankfurt Germany.

Time is displayed on a skeleton clock and a Blue 4x20 LCD display. Clock pulses to drive slave dials are monitored on an LED panel.

3 x 1.5volt AA cells provide battery backup when disconnected from the mains.

The main board has a USB to UART connector so the clock software can be updated from a PC or even a Mac.

Serial code is included for monitoring over the USB but is commented out.

 

New - updated code included to run Udo Klein's DCF77 library.

Udo Klein's DCF77 library   keeps the clock in sync and keeps perfect time even with a massive amount of noise on the received DCF77 signal.

The DCF77 library also continually "Auto Tunes" the quartz crystal so in the rare event the signal can't be decoded the clock remains accurate within 1 sec over many days.

This is crucial for a Master clock that drives 1 second slaves as seconds drift will cause the slave clocks to lose sync with the Master Clock time.

 

 

 

Arduino

The open-source Arduino environment makes it easy to write or edit the code and upload it to the USB board on the back of the clock.

It runs on Windows, Mac OS X, and Linux.

The environment is written in Java and based on Processing, avr-gcc, and other open source software.

The code for this clock can be downloaded at the bottom of this page and can be edited using the Arduino software.

There are 2 versions of the code included depending on which DCF77 library you want to use.

Arduino hardware (board, Microprocessor and all components) can purchased prebuilt ready to work from the Arduino Store or you can purchase the microprocessor

and components separately and build them into your own boards as I have done here.

 

 

Code editing in Windows

 

 

 

 

 

The Clock

 

This clock chimes on the quarter hour only with hour chimes sounding from the main Master Clock and Voltmeter Clock. As all the clocks are in sync the hour chime

will start after the quarter chime is completed.

 

 

 

 

Cutaway showing 3x AA standby batteries in the roof of the case.

 

 

 

 

The LCD display is from a company called 4tronix

 

The LCD display has the following specs.

  Operating voltage: 5V
  Alphanumeric character set
  4 lines of 20 characters
  Blue Backlight
  Module size: 98 x 60 x12mm
  Display size: 75 x 25mm
  I2C 2-wire connection
  Built-in Contrast Adjustment

 

 

LCD Display using Standard DCF77 Library

The display varies depending on which library and code version has been used.

The standard DCF77 library and code display is shown below.

This code also switches the LCD display off overnight.

 

On start-up the clock attempts to decode the DCF77 signal and will show the "Waiting DCF77 Sync" screen below.

 

 

Once the signal is decoded the display switches to full time, date and data display.

 

  

 

 

             

The LCD display shows;

Time and Date

Last time the clock sync'd to the DCF77 signal

The sync status

Last time the clock missed a pulse ( and was corrected by adding a pulse)

Number of pulses missed in last 24hrs

Pulse length 100ms = 1, 200ms = 2

Cycle length 1000ms and EOF (end of field) indicator

 

The clock will shutdown the LCD after midnight and will turn back on at 06:00hrs. This can be easily changed if required by editing the code.

 

 

 

LCD Display using Udo Klein's DCF77 Library

The code uses a PIR movement detector to turn the LCD display on and off.

This Library is able to decode the DCF77 signal even if it contains a massive amount of noise.

The library also "auto tunes" the Arduino Quartz crystal in the rare event the DCF77 signal is lost (no backup RTC required).

For this Library to work your Arduino must use a Quartz crystal as a timebase not a problem if you build your own Arduino as I have.

If you are using an Arduino Uno a Quartz crystal can be added my modding the UNO board. See how to do it below.

 

Below LCD info display using Udo Klein's DFC77 Library showing full 1 minute cycle

 

 

 

The Display is very similar to the standard DCF77 library display but there are a few differences.

 

Row 1 always shows the current time and date

Row 2 Clock Name

Row 3 DCF77 decoder state

Row 4 Sig Match - Once locked into the DCF77 signal Udo Klein's library can predict what the next signal pulse should be.

The Signal Match displayed as a percentage shows the quality of the received signal. 100% being a perfect match to the predicted signal.

Row 4 also shows Winter/Summer time.

 

 

Row 2 also shows the makers name and software version number

 

 

Row 2 then switches to show Slow and Fast 1 second pulses.

As this clock drives other slave clocks as well as the built in analogue display this row monitors the main decoded

display and it detects a jump in the seconds backwards or forwards. These will be shown as fast or slow seconds on Row 2 along with the date and time they were detected.

On initial power up there are no fast or slow pulses so Row 2 Slow Pulse will be "0" and the  date and time indicates when the clock was first power up and synchronized.

The Fast Pulse will also show "0" but the  date and time will show as "Never"

The only time you would expect to see a Slow or Fast pulse detected is if the DCF77 signal was removed for several days then reconnected or if a leap second is injected (fast pulse)

 

 

Row 2 showing number of Slow & Fast 1 second pulses

Row 4 shows the "auto tuned " quartz frequency.

When receiving the normal DCF77 signal Udo Klein's library uses this to work out how well the internal quartz crystal is running.

It will then tune the quartz frequency up or down to allow it to keep almost perfect time if the DCF77 signal is lost.

This tuned frequency is then displayed on Row 4.

 

 

Row 4 showing the tuned accuracy of the quartz crystal. Once the clock has run for a number of days the accuracy of the quartz crystal is tuned until it reaches a max accuracy of 1Hz.

The attained accuracy is displayed.

This is fully dynamic so the quartz crystal is continually tuned no matter the temperature or age drift of the crystal.

Remember this is not the accuracy of the clock but the accuracy of the quartz crystal if the DCF77 signal was to fail.

 

 

 

How to mod a standard Arduino Uno board to use Udo Klein's library

The only small down side to this library is that it needs an accurate time base on the Arduino to lock into the DCF77 frequency.

Modern Arduino boards don't use a quartz crystal ( the one you see on the board is for the serial port) but an inferior 16MHz ceramic resonator.

Udo has written a test program to check if your Arduino boards resonator/crystal are up to the job of running his library and can be found here DCF77 Scope .

If your board is not up to the job it is very easy to remove the resonator and replace it with a quartz crystal and a couple of capacitors. I have modified my Arduino UNO and it works perfectly with the library.

 

Modified Uno board

 

 

 

 

Above standard Uno Board

Below modified Uno Board

 

 

 

 

 

 

Pulse Monitor Panel

LED panel shows the slave clock and chime pulses output from the clock.

 

 

 

 

Clock at night

 

I removed the SMD LED from the I2C module and connected a large blue LED to light the inside of the case at night.

 

The skeletal clock is an old quartz unit with the quartz circuit board cut out and wires soldered to the motor terminals.

An alternating 1 second pulse from the Arduino drives the clock.

The skeletal clock seconds including mins and hours hands can be stopped and then stepped on second by second by 2 switches at the back.

The hour and minute hands are set by the standard knob on the rear of the clock.

 

 

Original Latern

The case is a modified BORRBY candle lantern from Ikea.

 

Clock Case Mod

 

 

How to modify the lamp (drawings not to scale)

                                                                       

1

Drill out the welds holding the top to the main frame

2

Remove the top

 

3

Cut out the ventilation grill on the front to make space for the LCD display

4

Cut wood or metal sheet to fill the ventilation grills that remain

 

5

Fill gaps between base and frame with wooden strips.

The base circuit board sits on this wood.

Remove candle spike from base and add four feet.

6

Add a new plywood top and fix with hindges a the back.

A recess will need to be cut in the top to take the top of the

LCD circuit board that protrudes from the base.

 

 

 

7

Add a handle and cut a hole in the base for the cables.

 

 

 

 

 

8

Fix LCD display in cutout

 

 

 

 

 

 

9

Fix Skeleton Clock movement by suspending from top

 

10

Slide in PCB and LED display panel

 

     
     

 

 

 

 

 

Short Video clip showing the clock operating and chiming from 23:59:55 to 00:00:32

View in You Tube

 

 

 

 

Schematic

The 2 x ULN2803A ICs are remote from the clock and are connected as required depending on slaves. The clock software is updated via the USB to UART

The DCF77 is wired remote from the clock and is powered by a 3.3v DC to Dc converter mounted on the main clock board

 

Table below shows pin usage depending on which library is used

    DCF77 Library by Udo Klein DCF77 Library by Thijs Elenb
IC Pin IDE Pin Sketch Name Function Sketch Name Function
1 Reset   Reset   Reset
2 0   Serial Read/Write   Serial Read/Write
3 1   Serial Read/Write   Serial Read/Write
4 2 uint8_t dcf77_sample_pin DCF77 I/P Signal DCF77PIN DCF77 I/P Signal
5 3 uint8_t dcf77_monitor_pin DCF77 Monitor led15 15 second pulse
6 4 ledQchime Qtr Chime pulse ledQchime Qtr Chime pulse
7 NA   4.4v   4.4v
8 NA   Gnd   Gnd
9 NA   Xtal1   Xtal1
10 NA   Xtal2   Xtal2
11 5 ledd 1 day pulse ledd 1 day pulse
12 6 ledh 1 hour pulse ledh 1 hour pulse
13 7 led 1 min pulse led 1 min pulse
14 8 led30 30 second pulse led30 30 second pulse
15 9 led20 20 second pulse led20 20 second pulse
16 10 led10 10 second pulse led10 10 second pulse
17 11 led05 5 second pulse led05 5 second pulse
18 12 led01 1 sec alternating pulse led01 25mS  pulse every second
19 13 infraredSw PIR detect pin   Not used
20 NA   4.4v   4.4v
21 NA   AREF   AREF
22 NA   Gnd   Gnd
23 A0 trigQchime triggers qtr chime board trigQchime triggers qtr chime board
24 A1 ledchime hour chime pulse ledchime hour chime pulse
25 A2 quartz02 Quartz clock motor drive quartz02 Quartz clock motor drive
26 A3 quartz01 Quartz clock motor drive quartz01 Quartz clock motor drive
27 A4 SDA I2C SDA pin for LCD SDA I2C SDA pin for LCD
28 A5 SCL I2C SCL pin for LCD SCL I2C SCL pin for LCD

 

 

 

 

Vero Board layout

The cut out on the right of the board goes to the back of the case and allows cable access

Sockets to all pins and outputs are included to enable feeds to other clocks via transistor drivers in my Master Clock system

 

Sure Electronics Digital record and playback board for sounding the quarter chime.

Hour chime is via my Voltmeter Clock and Longcase clock

 

 

Clock case dimensions

Arduino Site

 

 

 

Arduino Code

 

The code for the clock is shown below.

You can choose the Standard DCF77 library or Udo Klein's DCF77 Library

 

 

DCF77 master Clock using the DCF77 library from https://github.com/thijse/Arduino-Libraries/downloads

Download the code

Code is set for GMT England see Timezone library for details of how to change zone

Version 5.1 Updated 08/02/2014

// X:\My Documents\Arduino\DCF77 test Brett\DCF77testGMTserialLCD LED sec01
// Moved backliht on off to after "prevdisplay" to it is checked once per sec
// Resets Miss count at 06:10:01 not 23:59:59
// Mod to cycle length
// Version number added on flash screen
// Misscount Tot has leading zero and max count of 99 added
// ***** ALL Serial commands commented out ******************
// Blinkpin 13 for DCF77 pulse monitor on LED 13 commented out
// DCF77 Pulse Master Clock with Chime Brett Oliver 2013
// Note DCF77 time correction will cause pulses to miss if seconds are corrected when they are
// due to pulse. If variable prevDisplay1=1 seconds have stepped on correctly if prevDisplay1=2 seconds
// will have missed 1 second. Example if prevDisplay1 = 2 @ 22:59:59 then 23:00:00 will be missed out and
// any pulses or chimes triggered at this time will be missed. Code below has been corrected for "quartz"
// motor pulse, 30sec pulse and qtr chime only. If pulses or other chimes are critical for other slaves these
// must have code added to take account of DCF77 time correction.
// Note the variable prevDisplay1 will show a value corresponding to the DCF77 correction eg prevDisplay1=3 
// will indicate a 2 second correction. This is quite rare unless DCF77 reception is missing for long periods.
// Added LCD 4-Line 20x4 Alphanumeric LCD Module 2-Wire I2C Interface
// from http://4tronix.co.uk/arduino/I2C_LCD_Module.php
#include <Wire.h>
// I2C library from http://www.4tronix.co.uk/arduino/sketches/LiquidCrystal_V1.2.1.zip
#include <FastIO.h>
#include <I2CIO.h>
#include <LCD.h>
#include <LiquidCrystal.h>
#include <LiquidCrystal_I2C.h>
#include <LiquidCrystal_SR.h>
#include <LiquidCrystal_SR2W.h>
#include <LiquidCrystal_SR3W.h>
#include <DCF77.h>       //https://github.com/thijse/Arduino-Libraries/downloads
#include <Time.h>        //http://www.arduino.cc/playground/Code/Time
#include <Timezone.h>    //https://github.com/JChristensen/Timezone

#define DCF_PIN 2	         // Connection pin to DCF 77 device
#define DCF_INTERRUPT 0		 // Interrupt number associated with pin
//read cycle and pulse length
//#define BLINKPIN 13 // can be used to drive LED D10 instead of IC5 4049b 
#define DCF77PIN 2
//read cycle and pulse length


//**********************
// set the LCD address to 0x27 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address


//**********************
//United Kingdom (London, Belfast)
TimeChangeRule rBST = {
  "BST", Last, Sun, Mar, 1, 60};        //British Summer Time
TimeChangeRule rGMT = {
  "GMT", Last, Sun, Oct, 2, 0};         //Standard Time
Timezone UK(rBST, rGMT);
// read cycle and pulse length
int flankUp = 0;
int flankDown = 0;
int PreviousflankUp;
int cycle = 0;
int length = 0;
int lcdTot = 0;
bool Up = false;
// read cycle and pulse length
int misscount = 0;
int hourmiss = 00; // hour last extra pulse variable
int minutemiss = 00; // minute last extra pulse variable
int secondmiss = 00; // second last extra pulse variable
int hoursync = 00; // hour last sync variable
int minutesync = 00; // minute last sync variable
int secondsync = 00; // second last sync variable
int ledStateOdd = HIGH;             // ledState used to set the 1 second LED initial state
int ledStateEven = HIGH;              // ledState used to set the 2nd 1 second LED initial state
int quartzmotor1 = HIGH;              // ledState used to set the quartz motor pin A2 initial state
int quartzmotor2 = LOW;              //  ledState used to set the quartz motor pin A3 initial state

int led = 7; // min pulse
int led30 = 8; // 30 sec pulse
int led05 = 11; // 05 sec pulse
int led10 = 10; // 10 sec pulse
int led15 = 3; // 15 sec pulse
int led20 = 9; // 20 sec pulse
int led01 = 12; // 1 sec pulse
int ledh = 6; // 1 hour pulse
int ledd = 5; // 1 day pulse
int ledQchime = 4; // qtr hour chime pulse
int trigQchime = A0; // qtr hour chime trig pulse
int ledchime =A1;  //  hour chime pulse
int quartz01 =A2;  //  Quartz clock motor pulse 01
int quartz02 =A3;  //  Quartz clock motor pulse 02
time_t prevDisplay = 0;          // when the digital clock was displayed
time_t prevDisplay1 = 0;
time_t time;
DCF77 DCF = DCF77(DCF_PIN,DCF_INTERRUPT);

void setup() {
  //read cycle and pulse length
  pinMode(DCF77PIN, INPUT);
 // pinMode(BLINKPIN, OUTPUT);
  //read cycle and pulse length
  // initialize the digital pin as an output.
  lcd.begin(20,4);   // initialize the lcd for 20 chars 4 lines, turn on backlight
  pinMode(led, OUTPUT);
  pinMode(led30, OUTPUT);
  pinMode(led05, OUTPUT);
  pinMode(led10, OUTPUT);
  pinMode(led15, OUTPUT);
  pinMode(led20, OUTPUT);
  pinMode(led01, OUTPUT);
  pinMode(ledh, OUTPUT);
  pinMode(ledd, OUTPUT);
  pinMode(ledQchime, OUTPUT);
  pinMode(trigQchime, OUTPUT);
  pinMode(ledchime, OUTPUT);
  pinMode(quartz01, OUTPUT);
  pinMode(quartz02, OUTPUT);

  Serial.begin(9600); 
  DCF.Start();
  setSyncInterval(30);
  setSyncProvider(getDCFTime);
  // It is also possible to directly use DCF.getTime, but this function gives a bit of feedback
  //setSyncProvider(DCF.getTime);
  digitalWrite(ledQchime, HIGH);
  digitalWrite(trigQchime, HIGH); //Stops chime continualy sounding until DCF77 sync
  //Serial.print(misstot);
  //Serial.println("Waiting for DCF77 UK local time ... ");
  //Serial.println("It will take at least 2 minutes until a first update can be processed.");
  while(timeStatus()== timeNotSet) { 
    // wait until the time is set by the sync provider     
    //Serial.print(".");

    lcd.backlight(); // backlight on
    lcd.setCursor(0,0); //Start at character 0 on line 0
    lcd.print(" DCF77 Master Clock");
    delay(500);
    lcd.setCursor(0,2);
    lcd.print(" Waiting DCF77 Sync "); //Print 20 characters on 3rd line
    delay(200);
    lcd.setCursor(0,1);
    lcd.print("    Brett Oliver    "); //Print 20 characters on 2nd line
    //################# VERSION NUKMBER ######################################################################################
    delay(500);
    lcd.setCursor(0,3);
    lcd.print(" Ver. 51 08/02/2014"); // Print text on 4th Line
       
   //#########################################################################################################################



    delay(500);
    //lcd.setCursor(0,3);
    //lcd.print("Time Status ");
    // lcd.print(timeStatus());
    delay(500);
    lcd.setCursor(0,2);
    lcd.print("                    "); //Print 20 characters on 3rd line
    delay(500);
    lcd.setCursor(0,1);
    lcd.print("    Brett Oliver    "); //Print 20 characters on 2nd line
    delay(500);
    lcd.setCursor(0,3);
    lcd.print("                    "); //Print 20 characters on 4th line

    //******************************* 

    delay(300);

  }
}

void loop()
{  

  //read cycle and pulse length and display on bottom line of LCD
  //as Pulse Length and Cycle
  int sensorValue = digitalRead(DCF77PIN);
  if (sensorValue) {
    if (!Up) {
      flankUp=millis();
      Up = true;
      //digitalWrite(BLINKPIN, HIGH); // can be used to drive LED D10 instead of IC5 4049b
    }
  } 
  else {
    if (Up) {
      flankDown=millis();
      cycle = (flankUp-PreviousflankUp); // cycle length around 1000mSeconds
      lcd.setCursor(0,3);
      lcd.print("Lgth ");
      length = (flankDown - flankUp); // Pulse length 100m Seconds "0" 200m Seconds "1"
      PreviousflankUp = flankUp;
      Up = false;
      //digitalWrite(BLINKPIN, LOW); // can be used to drive LED D10 instead of IC5 4049b

    }              
  } 
  // add leading zero if below 1000 and add EOF indicator
  if (cycle > 1899 && cycle < 2200)
  {
    lcd.setCursor(9,3);
    lcd.print("Cycle ");
    lcd.setCursor(15,3);     
    lcd.print("EOF "); 
  }
  else if (cycle > 999 && cycle < 1900)
  {
    lcd.setCursor(9,3);
    lcd.print("Cycle ");
    lcd.setCursor(15,3);     
    lcd.print(cycle);
  }
  
  else if (cycle > 99 && cycle < 1000)
  {
    lcd.setCursor(9,3);
    lcd.print("Cycle ");
    lcd.setCursor(15,3);
    lcd.print("0");
    lcd.setCursor(16,3);
    lcd.print(cycle);
  }
  
   else if (cycle < 99 && cycle >9)
  {
    lcd.setCursor(9,3);
    lcd.print("Cycle ");
    lcd.setCursor(15,3);
    lcd.print("00");
    lcd.setCursor(17,3);
    lcd.print(cycle);
  }
  
   else if (cycle < 10 && cycle >0)
  {
    lcd.setCursor(9,3);
    lcd.print("Cycle ");
    lcd.setCursor(15,3);
    lcd.print("000");
    lcd.setCursor(18,3);
    lcd.print(cycle);
  }
     else if (cycle > 2199)
  {
    lcd.setCursor(9,3);
    lcd.print("Cycle ");
    lcd.setCursor(15,3);
    lcd.print("XXXX");
   
  }
  // add leading zero if Pulse length if below 99 and greater than 9
  //or add leadng zeroes if pulse below below 10 if over 999 then XXX is printed
  if (length > 99 && length <1000)
  {
    lcd.setCursor(0,3);
    lcd.print("Lgth ");
    lcd.setCursor(5,3);     
    lcd.print(length);
  }
  else if (length < 100 && length > 9 )
  {
    lcd.setCursor(0,3);
    lcd.print("Lgth ");
    lcd.setCursor(5,3);
    lcd.print("0");
    lcd.setCursor(6,3);
    lcd.print(length);

  }
  else if (length < 10 && length > 0)
  {
    lcd.setCursor(0,3);
    lcd.print("Lgth ");
    lcd.setCursor(5,3);
    lcd.print("00");
    lcd.setCursor(7,3);
    lcd.print(length);
  }
  else if (length == 0)
  {
    lcd.setCursor(0,3);
    lcd.print("Lgth ");
    lcd.setCursor(5,3);
    lcd.print("000");
  }
  else if (length > 999)
  {
    lcd.setCursor(0,3);
    lcd.print("Lgth ");
    lcd.setCursor(5,3);
    lcd.print("XXX");
  }

  //end of read cycle and pulse length
  
 

  //***************************
  if( now() != prevDisplay) //update the display only if the time has changed
  {
    prevDisplay1 = now()-prevDisplay; // should =1 if not then extra pulse is required
    prevDisplay = now();
    digitalClockDisplay();
   // Serial.print(" ");
   // Serial.print(prevDisplay1);
   // Serial.print(" ");


  }
}

void digitalClockDisplay(){
   //*************************** LCD backlight and display off after midnight and on from 06:00 hrs

  if (hour() >= 00 && hour() < 06) 

  {
    lcd.noBacklight(); // backlight off
    lcd.noDisplay(); //display off
  }
  else

      lcd.backlight(); // backlight on
  lcd.display(); //display on
  {
  }

  // Quartz clock driver
  // toggle Quartz drive A2 & A3 evey second
  if (quartzmotor1 == LOW)
  { 
    quartzmotor1 = HIGH;
  }
  else
    quartzmotor1 = LOW;
  {
    digitalWrite(quartz01, quartzmotor1); // set the quartz motor drive A2 pin
  }
  if (quartzmotor2 == HIGH)
  { 
    quartzmotor2 = LOW;
  }
  else
    quartzmotor2 = HIGH;
  {
    digitalWrite(quartz02, quartzmotor2); // set the quartz motor drive A3 pin     

  }

  //add extra quartz pulse

  if (prevDisplay1 > 1) // if >1 pulse has been missed so extra quartz pulse is added here
  {

    delay(100);

    if (quartzmotor1 == LOW)
    { 
      quartzmotor1 = HIGH;
    }
    else
      quartzmotor1 = LOW;
    {
      digitalWrite(quartz01, quartzmotor1); // set the quartz motor drive A2 pin
    }
    if (quartzmotor2 == HIGH)
    { 
      quartzmotor2 = LOW;
    }
    else
      quartzmotor2 = HIGH;
    {
      digitalWrite(quartz02, quartzmotor2); // set the quartz motor drive A3 pin     

    }
  }


  // end of add extra quartz pulse

  //#############################
  if (hour()== 6 && minute() == 10 && second() == 01) // resets miss second counter to 0 at 6:10:01
  {
    misscount = 0;
  }

  if (prevDisplay1 > 1) //records time of miss second
  {
    misscount = misscount + 1; //increment Miss count total
    hourmiss = hour();
    minutemiss = minute();
    secondmiss = second();

  }
  // Enable below to analize missed pulses on serial monitor
  //Serial.print(" ");
  //Serial.print("MC");
  //Serial.print(misscount);
  //############################# 
  
 
  // Quarter Chime

  if ((minute() == 15 || minute() == 30 || minute() == 45) && second() == 0)
  {
    digitalWrite(ledQchime, LOW);
  }

  else if ((minute() == 15 || minute() == 30 || minute() == 45) && second() == 59 && prevDisplay1 ==2)
  {
    digitalWrite(ledQchime, LOW);
  }

  else if
    (minute() == 59 && second() == 57) 
  {
    digitalWrite(ledQchime, LOW);
  }

  else if (minute() == 59 && second() == 56 && prevDisplay1 ==2 )
  {
    digitalWrite(ledQchime, LOW);
  }
  else
    digitalWrite(ledQchime, HIGH);





  if ((minute() == 15 || minute() == 30 || minute() == 45) && second() == 0)
  {
    digitalWrite(trigQchime, LOW);
  }

  else if ((minute() == 15 || minute() == 30 || minute() == 45) && second() == 59 && prevDisplay1 ==2)
  {
    digitalWrite(trigQchime, LOW);
  }

  else if
    (minute() == 59 && second() == 57) 
  {
    digitalWrite(trigQchime, LOW);
  }

  else if (minute() == 59 && second() == 56 && prevDisplay1 ==2 )
  {
    digitalWrite(trigQchime, LOW);
  }
  else
    digitalWrite(trigQchime, HIGH);

  //End of Quarter Chime


  // hour Chime
  if (minute() == 0 && (hour() == 1 || hour() == 13) && second() == 0 )
  {
    digitalWrite(ledchime, HIGH);
  }
  else
    if (minute() == 0 && (hour() == 2 || hour() == 14) && (second() == 0 || second() ==2 ))
    {
      digitalWrite(ledchime, HIGH); 
    } 
    else
      if (minute() == 0 && (hour() == 3 || hour() == 15) && (second() == 0 || second() ==2 || second() ==4 ))
      {
        digitalWrite(ledchime, HIGH); 
      } 
      else
        if (minute() == 0 && (hour() == 4 || hour() == 16) && (second() == 0 || second() ==2 || second() ==4 || second() ==6 ))
        {
          digitalWrite(ledchime, HIGH); 
        } 
        else
          if (minute() == 0 && (hour() == 5 || hour() == 17) && (second() == 0 || second() ==2 || second() ==4 || second() ==6 || second() ==8 ))
          {
            digitalWrite(ledchime, HIGH);  
          }
          else
            if (minute() == 0 && (hour() == 6 || hour() == 18) && (second() == 0 || second() ==2 || second() ==4 || second() ==6 || second() ==8 || second() ==10 ))
            {
              digitalWrite(ledchime, HIGH);
            }
            else
              if (minute() == 0 && (hour() == 7 || hour() == 19) && (second() == 0 || second() ==2 || second() ==4 || second() ==6 || second() ==8 || second() ==10 || second() ==12 ))
              {
                digitalWrite(ledchime, HIGH);
              }  
              else
                if (minute() == 0 && (hour() == 8 || hour() == 20) && (second() == 0 || second() ==2 || second() ==4 || second() ==6 || second() ==8 || second() ==10 || second() ==12 || second() ==14))
                {
                  digitalWrite(ledchime, HIGH); 
                } 
                else
                  if (minute() == 0 && (hour() == 9 || hour() == 21) && (second() == 0 || second() ==2 || second() ==4 || second() ==6 || second() ==8 || second() ==10 || second() ==12 || second() ==14 || second() ==16))
                  {
                    digitalWrite(ledchime, HIGH);
                  }  
                  else
                    if (minute() == 0 && (hour() == 10 || hour() == 22) && (second() == 0 || second() ==2 || second() ==4 || second() ==6 || second() ==8 || second() ==10 || second() ==12 || second() ==14 || second() ==16 || second() ==18))
                    {
                      digitalWrite(ledchime, HIGH); 
                    } 
                    else
                      if (minute() == 0 && (hour() == 11 || hour() == 23) && (second() == 0 || second() ==2 || second() ==4 || second() ==6 || second() ==8 || second() ==10 || second() ==12 || second() ==14 || second() ==16 || second() ==18 || second() ==20))
                      {
                        digitalWrite(ledchime, HIGH); 
                      } 
                      else
                        if (minute() == 0 && (hour() == 12 || hour() == 0) && (second() == 0 || second() ==2 || second() ==4 || second() ==6 || second() ==8 || second() ==10 || second() ==12 || second() ==14 || second() ==16 || second() ==18 || second() ==20 || second() ==22))
                        {
                          digitalWrite(ledchime, HIGH); 
                        } 
                        else      
                          digitalWrite(ledchime, LOW);
  // end of Hour Chime
  digitalWrite(led01, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(25);
  digitalWrite(led01, LOW);   // turn the LED off (LOW is the voltage level) 

  // digital clock display of the time
  //Serial.println("");
  //Serial.print(hour()); add leading 0 on hour and prob :

  lcd.setCursor(0,0); // set LCD to row 1 pos 1
  //************
 // printDigitsH(hour());
 // printDigits(minute());
 // printDigits(second());
  //Serial.print(" ");
  //Serial.print(day());
  //Serial.print(" ");
  //Serial.print(month());
  //Serial.print(" ");
  //Serial.print(year());
  //Serial.print("      "); // adds space before following


  //~~~~~~~~~~~~~~~~~~
  // printP01(second()); // prints every second
  printPTen(second()); // prints secs ie 0 every 60 secs
  printP30(second()); //  prints 0 or 30  on 0 or 30 secs
  printP05(second()); //  prints every 5 secs
  printP10(second()); //  prints every 10 secs
  printP15(second()); //  prints every 15 secs
  printP20(second()); //  prints every 20 secs
  printPhour(minute()); // print every hour eg when ever mins at 00
  printPday(hour()); // print when hour is 0 eg every 24 hour

   // Serial.println();
  printLCDH(hour()); //adds leadng zero if hour is less than 10
  printLCD(minute()); //adds leadng zero and colon if minute is less than 10
  printLCD(second()); //adds leadng zero and colon if seond is less than 10
  lcd.print(" ");
  printLCDH(day()); // adds leadng zero if day is less than 10
  lcd.print("/");
  printLCDH(month()); // adds leadng zero if month is less than 10
  lcd.print("/");
  lcd.print(year());

  // display last sync time
  lcd.setCursor(0,1);
  lcd.print("Sync ");

  // show last sync time on LCD
  printLCDH(hoursync);
  lcd.print(":");
  printLCDH(minutesync);
  lcd.print(":");
  printLCDH(secondsync);
  lcd.print(" Sta ");
  lcd.print(timeStatus());

  lcd.setCursor(0,2);
  lcd.print("Miss ");
  printLCDH(hourmiss);
  lcd.print(":");
  printLCDH(minutemiss);
  lcd.print(":");
  printLCDH(secondmiss);
  lcd.print(" Tot ");
 // lcd.print(misscount);
  //**********************
   // add leading zero if Misscount Tot below 10 and XX if over 99

  if (misscount > 99)
  {
    lcd.setCursor(18,2);
    lcd.print("XX");
    
  }
  else if (misscount > 9 && misscount < 100)
  {
    lcd.setCursor(18,2);
    lcd.print(misscount);
  
  }
  else if (misscount < 9)
  {
    lcd.setCursor(18,2);
    lcd.print("0");
    lcd.setCursor(19,2);
    lcd.print(misscount);

  }
  
  
  //*********************

//}

//void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0 on mins and secs
  //Serial.print(":");
 // if(digits < 10)
    //Serial.print('0');
  //Serial.print(digits);

}


void printLCD(int LCDdigits){
  // utility function for digital clock display: prints preceding colon and leading 0 on mins and secs
  lcd.print(":");
  if(LCDdigits < 10)
    lcd.print('0');
  lcd.print(LCDdigits); 

}
void printLCDH(int LCDdigitH){
  // utility function for digital clock display: prints leading 0 on hours
  //Serial.print(":");  colon not needed for hours
  if(LCDdigitH < 10)  
    lcd.print("0"); // Print hour on first line
  lcd.print(LCDdigitH);

//}
//void printDigitsH(int digitH){
  // utility function for digital clock display: prints leading 0 on hours
//  if(digitH < 10)
   // Serial.print('0');
 // Serial.print(digitH);

}

void printPTen(int PTen){ // light LED every min on 00

  if(PTen == 00)
  {
   // Serial.print(PTen);
    digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)

  }
  else if(PTen != 00)

    digitalWrite(led, LOW);   // turn the LED off (LOW is the voltage level)

}


void printP30(int P30){ // light LED every 30 seconds

  if(P30 == 00 || P30 == 30)
  {
   // Serial.print(P30);
    digitalWrite(led30, HIGH);   // turn the LED on (HIGH is the voltage level)

  }
  else if(P30 != 00 || P30 !=30)

    digitalWrite(led30, LOW);   // turn the LED off (LOW is the voltage level)

  else if(P30 == 59 || P30 == 29 && prevDisplay1==2)// makes sure clock pulses 30 sec pulse if DCF77 time corrects @ 59 or 29 sec

  {

    //Serial.print(P30);
    digitalWrite(led30, HIGH);   // turn the LED on (HIGH is the voltage level)
  }
  else if(P30 != 59 || P30 !=29 && prevDisplay1==2) //// makes sure clock pulses turn off 30 sec pulse if DCF77 time corrects @ 59 or 29 sec

    digitalWrite(led30, LOW);   // turn the LED off (LOW is the voltage level)




}
void printP05(int P05){ // light LED 10 every 5 seconds

  if(P05 == 00 || P05 == 05 || P05 == 10 || P05 == 15 || P05 == 20 || P05 == 25 || P05 == 30 || P05 == 35 || P05 == 40 || P05 == 45 || P05 == 50 || P05 == 55)
  {
    //Serial.print(P05);
    digitalWrite(led05, HIGH);   // turn the LED on (HIGH is the voltage level)

  }
  else if(P05 != 00 || P05 !=05 || P05 !=10 || P05 !=15 || P05 !=20 || P05 !=25 || P05 !=30 || P05 !=35 || P05 !=40 || P05 !=45 || P05 !=50 || P05 !=55)

    digitalWrite(led05, LOW);   // turn the LED off (LOW is the voltage level)


}

void printP10(int P10){ // light LED 09 every 10 seconds

  if(P10 == 00 || P10 == 10 || P10 == 20 || P10 == 30 || P10 == 40 || P10 == 50)
  {
    //Serial.print(P10);
    digitalWrite(led10, HIGH);   // turn the LED on (HIGH is the voltage level)
     }
  else if(P10 != 00 || P10 !=10 || P10 !=20 || P10 !=30 || P10 !=40 || P10 !=50)

    digitalWrite(led10, LOW);   // turn the LED off (LOW is the voltage level)

}

void printP15(int P15){ // light LED 03 every 15 seconds

  if(P15 == 00 || P15 == 15 || P15 == 30 || P15 == 45)
  {
   // Serial.print(P15);
    digitalWrite(led15, HIGH);   // turn the LED on (HIGH is the voltage level)
  }
  else if(P15 != 00 || P15 !=15 || P15 !=30 || P15 !=45)

    digitalWrite(led15, LOW);   // turn the LED off (LOW is the voltage level)

}

void printP20(int P20){ // light LED 08 every 20 seconds

  if(P20 == 00 || P20 == 20 || P20 == 40)
  {
   // Serial.print(P20);
    digitalWrite(led20, HIGH);   // turn the LED on (HIGH is the voltage level)
  }
  else if(P20 != 00 || P20 !=20 || P20 !=40)

    digitalWrite(led20, LOW);   // turn the LED off (LOW is the voltage level)
}


void printPhour(int Phour){ // light LED every hour on 00

  if(Phour == 00 && second() == 00)
  {
   // Serial.print(Phour);
    digitalWrite(ledh, HIGH);   // turn the LED on (HIGH is the voltage level)
  }
  else if(second() != 00) // turn off hour pulse when secs are not 00

      digitalWrite(ledh, LOW);   // turn the LED off (LOW is the voltage level)

}
void printPday(int Pday){ // light LED every day on 00

  if(Pday == 00 && second() == 00)
  {
    //Serial.print(Pday);
    digitalWrite(ledd, HIGH);   // turn the LED on (HIGH is the voltage level)
  }
  else if(second() != 00) //turn off day pulse when secs are not 00

      digitalWrite(ledd, LOW);   // turn the LED off (LOW is the voltage level)


}



unsigned long getDCFTime()
{ 
  time_t DCFtime = DCF.getUTCTime(); // Get  UTC time

    if (DCFtime!=0) 
  {
    time_t LocalTime = UK.toLocal(DCFtime); // Convert to UK time
   // Serial.print("Syncronized  ");
    // when sycn'd show this time as time synch'd
    hoursync = hour();
    minutesync = minute();
    secondsync = second();


    return LocalTime;

  }
  return 0;
}
 
 










 

LCD Master Clock using Udo Klein's DCF77 library

Download





//  LCD Master Clock using Udo Klein's DCF77 library
//  http://www.brettoliver.org.uk
//
//  Copyright 2014 Brett Oliver
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program. If not, see http://www.gnu.org/licenses/
//
// 
// Based on the DCF77 library by Udo Klein
// http://blog.blinkenlight.net/experiments/dcf77/dcf77-library/
// http://blog.blinkenlight.net/experiments/dcf77/simple-clock/
// v 3 LedControl removed and Pin 13 used for dcf77 monitor as spare
// v 4 LED30 removed as conflicting with DCF77 input pin  pin2
// v 5 stripped data from loop
// v6 int and pinmode values  added Quartz motor driver and version number display added
// v7 add qtr chime
// v8 added hour chime
// v9 added flash 1 sec pulse pin
// v10 added void statements
// v11 added blink without delay
// v12 as above
// v13 added extra count and leap second
// v14 added accuracy stats
// v15 added seconds miss and slow pulse
// v16 date and time of missed pulse displayed
// v17 do not use
// v18 clock state added to row 02
// v19 leading zeroes added to date on miss & extra pulse
// v20 infrared switch added to pin 13
// v22 remove 15 sec pulse change DCF77 monitor pin to use this op instead
// v23 modified hour chime code
// v24 Qtr chime modified to stop it repeating 30 seconds later
//#include <LedControl.h>
#include <Wire.h>
#include <dcf77.h>
#include <LiquidCrystal_I2C.h>




//unsigned long delaytime=250;
//**********************
// set the LCD address to 0x27 for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address


//**********************

const uint8_t dcf77_analog_sample_pin = 5; // not used
const uint8_t dcf77_sample_pin = 2;  // DCF77 input signal
const uint8_t dcf77_inverted_samples = 0;
const uint8_t dcf77_analog_samples = 0;

const uint8_t dcf77_monitor_pin = 3;  

const int8_t timezone_offset = -1;  // GB is one hour behind CET/CEST




int infraredSwval = 0; // infrared value
int infraredSw = 13; // 

int extracount = 0; // where quartz seconds needs to miss a pulse
int hourextra = 00; // hour last miss pulse variable
int dayextra = 00; // day last miss pulse variable
int monthextra = 00; // month last miss pulse variable
int minuteextra = 00; // minute last miss pulse variable
int secondextra = 00; // second last miss pulse variable
int yearextra = 00;
int signalQual = 0; // computed once per minute and indicates how well 
// the received signal matches the locally synthesized reference signal max 50

int secondsnow = 0; // previous second
int yearmiss = 00;
int daymiss = 00; // day last extra pulse variable
int monthmiss = 00; // month last extra pulse variable
int secsmiss = 0; // works out is seconds need to an extra pulse or miss a pulse

int summertest = 0; // equals 1 for summertime and 0 for wintertime

int misscount = 99; // ensures miscount goes to 0 on startup
int hourmiss = 00; // hour last extra pulse variable
int minutemiss = 00; // minute last extra pulse variable
int secondmiss = 00; // second last extra pulse variable
int hoursync = 00; // hour last sync variable
int minutesync = 00; // minute last sync variable
int secondsync = 00; // second last sync variable
//int ledStateOdd = HIGH;             // ledState used to set the 1 second LED initial state
//int ledStateEven = HIGH;              // ledState used to set the 2nd 1 second LED initial state
int quartzmotor1 = HIGH;              // ledState used to set the quartz motor pin A2 initial state
int quartzmotor2 = LOW;              //  ledState used to set the quartz motor pin A3 initial state

int led = 7; // min pulse
int led30 = 8; // 30 sec pulse
int led05 = 11; // 05 sec pulse
int led10 = 10; // 10 sec pulse
//int led15 = 3; // 15 sec pulse
int led20 = 9; // 20 sec pulse
const int led01 = 12; // 1 sec pulse
int led01state = LOW; // ledState used to set led01
//long previousMillis = 0; //// will store last time led01 was updated
//long interval = 500;           // interval at which to blink (milliseconds)
int ledh = 6; // 1 hour pulse
int ledd = 5; // 1 day pulse
int ledQchime = 4; // qtr hour chime pulse
int trigQchime = A0; // qtr hour chime trig pulse
int ledchime =A1;  //  hour chime pulse
int quartz01 =A3;  //  Quartz clock motor pulse 01
int quartz02 =A2;  //  Quartz clock motor pulse 02
int monthval = 0;
int dayval = 0;
int hours = 0;
int minutes = 0;
int seconds = 0;
int years = 0;
int months = 0;
int days = 0;

//********************

namespace Timezone {
  uint8_t days_per_month(const DCF77_Clock::time_t &now) {
    switch (now.month.val) {
    case 0x02:
      // valid till 31.12.2399
      // notice year mod 4 == year & 0x03
      return 28 + ((now.year.val != 0) && ((bcd_to_int(now.year) & 0x03) == 0)? 1: 0);
    case 0x01: 
    case 0x03: 
    case 0x05: 
    case 0x07: 
    case 0x08: 
    case 0x10: 
    case 0x12: 
      return 31;
    case 0x04: 
    case 0x06: 
    case 0x09: 
    case 0x11:                                  
      return 30;
    default: 
      return 0;
    }
  }   

  void adjust(DCF77_Clock::time_t &time, const int8_t offset) {
    // attention: maximum supported offset is +/- 23h

    int8_t hour = BCD::bcd_to_int(time.hour) + offset;

    if (hour > 23) {
      hour -= 24;
      uint8_t day = BCD::bcd_to_int(time.day) + 1;
      if (day > days_per_month(time)) {
        day = 1;
        uint8_t month = BCD::bcd_to_int(time.month);
        ++month;
        if (month > 12) {
          month = 1;
          uint8_t year = BCD::bcd_to_int(time.year);                  
          ++year;
          if (year > 99) {
            year = 0;
          }
          time.year = BCD::int_to_bcd(year);
        }                
        time.month = BCD::int_to_bcd(month);
      }
      time.day = BCD::int_to_bcd(day);
    }

    if (hour < 0) {
      hour += 24;
      uint8_t day = BCD::bcd_to_int(time.day) - 1;
      if (day < 1) {
        uint8_t month = BCD::bcd_to_int(time.month);
        --month;
        if (month < 1) {
          month = 12;
          int8_t year = BCD::bcd_to_int(time.year);                  
          --year;
          if (year < 0) {
            year = 99;
          }
          time.year = BCD::int_to_bcd(year);
        }                
        time.month = BCD::int_to_bcd(month);
        day = days_per_month(time);
      }
      time.day = BCD::int_to_bcd(day);
    }

    time.hour = BCD::int_to_bcd(hour);
  }
}

uint8_t sample_input_pin() {
  const uint8_t sampled_data =
    dcf77_inverted_samples ^ (dcf77_analog_samples? (analogRead(dcf77_analog_sample_pin) > 200)
    : digitalRead(dcf77_sample_pin));

  digitalWrite(dcf77_monitor_pin, sampled_data);
  return sampled_data;
}

void setup() {
  digitalWrite(led30, LOW); // turn 30 sec clocks off at start
  digitalWrite(ledQchime, HIGH); // turn Qtr chime off at start
  digitalWrite(ledchime, LOW); // turn Hour chime off at start
  digitalWrite(trigQchime, HIGH); // turn Hour chime off at start
 

  lcd.begin(20,4);   // initialize the lcd for 20 chars 4 lines, turn on backlight 
  using namespace DCF77_Encoder;
  //*************
 // lcd.backlight(); // backlight on not needed as controlled by 7 MAX2719
  lcd.setCursor(0,0); //Start at character 0 on line 0
  lcd.print("DCF77 Master Clk v24");  





  //***************
  Serial.begin(9600);
  /*  Serial.println();
   Serial.println(F(" DCF77 Master Clock "));
   Serial.println(F("(c) Brett Oliver 2014"));
   Serial.println(F("http://www.brettoliver.org.uk"));
   Serial.println(F("Based on the DCF77 library by Udo Klein"));
   Serial.println(F("www.blinkenlight.net"));
   Serial.println();
   Serial.print(F("Sample Pin:     ")); 
   Serial.println(dcf77_sample_pin);
   Serial.print(F("Inverted Mode:  ")); 
   Serial.println(dcf77_inverted_samples);
   Serial.print(F("Analog Mode:    ")); 
   Serial.println(dcf77_analog_samples);
   Serial.print(F("Monitor Pin:    ")); 
   Serial.println(dcf77_monitor_pin);
   Serial.print(F("Timezone Offset:")); 
   Serial.println(timezone_offset);
   Serial.println();
   Serial.println();
   Serial.println(F("Initializing..."));
   */
  pinMode(dcf77_monitor_pin, OUTPUT);

  pinMode(dcf77_sample_pin, INPUT);
  digitalWrite(dcf77_sample_pin, HIGH);


  //*******************
  pinMode(led, OUTPUT);
  pinMode(led30, OUTPUT);
  pinMode(led05, OUTPUT);
  pinMode(led10, OUTPUT);
 // pinMode(led15, OUTPUT);
  pinMode(led20, OUTPUT);
  pinMode(led01, OUTPUT);
  pinMode(ledh, OUTPUT);
  pinMode(ledd, OUTPUT);
  pinMode(ledQchime, OUTPUT);
  pinMode(trigQchime, OUTPUT);
  pinMode(ledchime, OUTPUT);
  pinMode(quartz01, OUTPUT);
  pinMode(quartz02, OUTPUT);
 
  pinMode(infraredSw, INPUT); // infrared sensor output

  //*******************

  DCF77_Clock::setup();
  DCF77_Clock::set_input_provider(sample_input_pin);


  // Wait till clock is synced, depending on the signal quality this may take
  // rather long. About 5 minutes with a good signal, 30 minutes or longer
  // with a bad signal
  for (uint8_t state = DCF77::useless;
         state == DCF77::useless || state == DCF77::dirty;
         state = DCF77_Clock::get_clock_state()) {

    // wait for next sec
    DCF77_Clock::time_t now;
    DCF77_Clock::get_current_time(now);

    // render one dot per second while initializing
    static uint8_t count = 0;
    Serial.print('.');
    ++count;
    if (count == 60) {
      count = 0;
      Serial.println();
    }
  }
}

void paddedPrint(BCD::bcd_t n) {
  Serial.print(n.digit.hi);
  Serial.print(n.digit.lo);
}
void LCDpaddedPrint(BCD::bcd_t n) { 
  lcd.print(n.digit.hi); 
  lcd.print(n.digit.lo); 
}



void loop() {

  DCF77_Clock::time_t now;

  DCF77_Clock::get_current_time(now);
  Timezone::adjust(now, timezone_offset);

  if (now.month.val > 0) {


    //***********
    // get month & day values
    dayval = now.day.val, DEC;
    monthval = now.month.val, DEC;
    // Serial.print(" day ");
    // Serial.print(now.day.val, DEC);
    //  Serial.print(" month ");
    //  Serial.print(now.month.val, DEC);
    //   Serial.print(' ');
    // get month & day values
    // Quartz clock driver
    // toggle Quartz drive 7 & 8 evey second
  }  
    lcd.setCursor(0,2);
    lcd.print(" Clock State");
    lcd.setCursor(13,2);
    //lcd.print(" Wait  ");
    switch (DCF77_Clock::get_clock_state()) {
      // case DCF77::useless: Serial.print(F("useless ")); break;
      case DCF77::useless: 
      lcd.print(F(" Fail  ")); 
      break;
      // case DCF77::dirty:   Serial.print(F("dirty: ")); break;
      //  case DCF77::synced:  Serial.print(F("synced: ")); break;
      // case DCF77::locked:  Serial.print(F("locked: ")); break;
      case DCF77::dirty:   
      lcd.print(F(" Dirty ")); 
      break;
      case DCF77::synced:  
      lcd.print(F(" Sync'd")); 
      break;
      case DCF77::locked:  
      lcd.print(F(" Locked")); 
      break;
    }

    //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
    
    Serial.print("Quartz Frequency");
    Serial.println(16000000L - DCF77_1_Khz_Generator::read_adjustment());
    
    Serial.print("Quartz Accuracy");
    Serial.println(DCF77_Frequency_Control::get_confirmed_precision());
    // Get hours minutes and seconds variables
    hours = BCD::bcd_to_int(now.hour);


    minutes = BCD::bcd_to_int(now.minute);


    seconds = BCD::bcd_to_int(now.second);

    years = BCD::bcd_to_int(now.year);

    months = BCD::bcd_to_int(now.month);

    days = BCD::bcd_to_int(now.day);
    
    Serial.print(hours);
    Serial.print(":");
    Serial.print(minutes);
    Serial.print(":");
    Serial.print(seconds);
   
    
    Serial.print(" ");
    Serial.print(days);
    Serial.print(":");
    Serial.print(months);
    Serial.print(":");
    Serial.println(years);
    


    //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 

    // Start of miss pulse detect

secsmiss = seconds - secondsnow;

    if (secsmiss ==-59 || secsmiss ==-60 && seconds ==0) // takes account of seconds rollover -59 or leap second -60
    {
      secsmiss = 1;
    } 


    if (secsmiss >=1 && seconds !=60) // if zero or less seconds pulse need to be missed. Leap second missed if seconds = 60
    {
      secondsmotor (); // function steps quartz motor
    }

    /*
    if (secsmiss >1) // if extra second pulse required
     {
     delay(100); // add delay so seconds mtor can operate again in the same second
     secondsmotor (); // function steps quartz motor and adds extra pulse if secmiss is >1
     }
     
     */



    if (secsmiss < 1 || seconds == 60) //records time of extra sec second (quart motor needs to loose a second)

    {
      extracount = extracount + 1; //increment extra count total (1sec needs to miss pulse)
      hourextra = hours;
      minuteextra = minutes;
      secondextra = seconds;
      yearextra = years;
      monthextra = months;
      dayextra = days; 
     
    }


    if (secsmiss > 1) //records time of miss second (quart motor needs to add a second)
    {
      misscount = misscount + 1; //increment Miss count total (1sec has missed extra pulse)
      hourmiss = hours;
      minutemiss = minutes;
      secondmiss = seconds;
      yearmiss = years;
      monthmiss = months;
      daymiss = days;

    } 



    secondsnow = seconds; 



    if (misscount >99) // resets miss second counter to 0 after 99 pulses
    {
      misscount = 0;
      
    }
    if (extracount >99) // resets miss second counter to 0 after 99 pulses
    {
      extracount = 0;
      
    }


    // }
    // Enable below to analize missed pulses on serial monitor
    //Serial.print(" ");
    // Serial.print("secsmiss ");
    //  Serial.println(secsmiss);

/*
    Serial.print("Slow Seconds ");
    Serial.print(misscount);
    Serial.print(" ");
    Serial.print(hourmiss);
    Serial.print(":");
    Serial.print(minutemiss);
    Serial.print(":");
    Serial.print(secondmiss);
    Serial.print(" ");
    Serial.print(daymiss);
    Serial.print("/");
    Serial.print(monthmiss);
    Serial.print("/");
    Serial.println(yearmiss);


    Serial.print("Fast Seconds ");
    Serial.print(extracount);
    Serial.print(" ");
    Serial.print(hourextra);
    Serial.print(":");
    Serial.print(minuteextra);
    Serial.print(":");
    Serial.print(secondextra);
    Serial.print(" ");
    Serial.print(dayextra);
    Serial.print("/");
    Serial.print(monthextra);
    Serial.print("/");
    Serial.println(yearextra);
*/
    
    // End of miss pulse detect
    
    
   
    
    
    
    // Display time and date on top row of LCD display

    lcd.setCursor(0,0);

    LCDpaddedPrint(now.hour);
    lcd.print(":");
    LCDpaddedPrint(now.minute);
    lcd.print(":");
    LCDpaddedPrint(now.second);
    lcd.print("  ");

    LCDpaddedPrint(now.day);
    lcd.print("/");
    LCDpaddedPrint(now.month);
    lcd.print("/");
    lcd.print("20");
    LCDpaddedPrint(now.year);
    
    // End Display time and date on top row of LCD display
    



    // Star Summer/Winter display

    
    const int8_t offset_to_utc = timezone_offset + (now.uses_summertime? 2: 1);

    summertest = (abs(offset_to_utc)); // equals 1 if summertime and 2 if wintertime 

    if (summertest ==2) // if wintertime make summertest =0
    {
      summertest = 0;
    }

    //**************
    lcd.setCursor(15,3);
    lcd.print("GMT+");
    // UTCcheck= offset_to_utc;
    // lcd.print(UTCcheck);
    lcd.print(summertest);
    
    // End Summer/Winter display


 // Infrared Detect
 int infraredSw = digitalRead(13); // reads infrared detector output
    Serial.print ("Infrared ");
    Serial.println (infraredSw);
    Serial.println ("");
    if (infraredSw == 1)
    {
      lcd.backlight(); // backlight on
      lcd.display(); //display on  
    } 
      
      else if (infraredSw == 0)
    {  
      lcd.noBacklight(); // LCD backlight off
      lcd.noDisplay(); //LCD display off 
    }
    
 // End Infrared Detect




 // Quarter Chime

  if ((minutes == 15 || minutes == 30 || minutes == 45) && seconds == 0)
  {
    digitalWrite(ledQchime, LOW);
   //digitalWrite(trigQchime, LOW);
  }

  else if
    (minutes == 59 && seconds == 57) 
  {
    digitalWrite(ledQchime, LOW);
  // digitalWrite(trigQchime, LOW);
  }

  else
    digitalWrite(ledQchime, HIGH);
  //  digitalWrite(trigQchime, HIGH);
    
  if ((minutes == 15 || minutes == 30 || minutes == 45) && seconds == 0)
  {
   // digitalWrite(ledQchime, LOW);
   digitalWrite(trigQchime, LOW);
  }

  else if
    (minutes == 59 && seconds == 57) 
  {
   // digitalWrite(ledQchime, LOW);
   digitalWrite(trigQchime, LOW);
  }

  else
   // digitalWrite(ledQchime, HIGH);
    digitalWrite(trigQchime, HIGH);
    
   
  //End of Quarter Chime
  
  // start hour Chime
  // map hours to range 1-12
const uint8_t normalized_hours = hours > 12 ? hours-12 : hours > 0 ? hours : 12;
// compute chime instead of matching it
digitalWrite(ledchime,minutes == 0 && (seconds & 1) == 0 && seconds< 2 * normalized_hours);
  // end hour Chime
  
 
  // Flash 1 sec LED
  // digitalWrite(led01, HIGH);   // turn the LED on (HIGH is the voltage level)
 // delay(25);
//  digitalWrite(led01, LOW);   // turn the LED off (LOW is the voltage level) 

// check to see if it's time to blink the LED; that is, if the 
  // difference between the current time and last time you blinked 
  // the LED is bigger than the interval at which you want to 
  // blink the LED.

 
    

    // if the LED is off turn it on and vice-versa:
    if (led01state == LOW)
    {
      led01state = HIGH;
    }
    else
      led01state = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(led01, led01state);
    
  
  // End Flash 1 sec LED
  
  
  printPTen(seconds); // prints secs ie 0 every 60 secs
  printP30(seconds); //  prints 0 or 30  on 0 or 30 secs
  printP05(seconds); //  prints every 5 secs
  printP10(seconds); //  prints every 10 secs
 // printP15(seconds); //  prints every 15 secs
  printP20(seconds); //  prints every 20 secs
  printPhour(minutes); // print every hour eg when ever mins at 00
  printPday(hours); // print when hour is 0 eg every 24 hour
  
  
    // Quality display on LCD


   if (seconds >= 0 && seconds <= 14)
  { 
    signalmatch(); // Quality factor
  }

  else if (seconds == 15)
  {
    blankrow3(); //Blanks row 3
  }

  else if (seconds == 16)
  {
    lcd.setCursor(0,3);
  lcd.print("Quartz         ");
  }
  else if (seconds >= 17 && seconds <= 37)
  {
    precision(); //quartz confirmed and target precision
  }

  else if (seconds == 38)
  {
    blankrow3(); //Blanks row 3
  }

   else if (seconds >= 39 && seconds <= 40)
  {
      lcd.setCursor(0,3);
  lcd.print("Frequency      ");
  }

  else if (seconds >= 41 && seconds <= 58)
  {
    freqadj(); //frequency adjustment and actual frequency
  }

  else if (seconds == 59)
  {
    blankrow3(); //Blanks row 3
  }
 
  // End of Quality display on LCD
  
  
  
  
  
  // Display of Title and display of slow and fast pulses on row 01

/*
  if (retardcount > 0 || retardcount == 119 ) //Prints correction pulse number
  {
    lcd.setCursor(0,1); 
    lcd.print("Winter Retard  ");
    lcd.setCursor(15,1);



    retard(retardcount); // add leading 0 <99
    retardtens(retardcount); // add another leading 0 less than 10
    lcd.print(retardcount);
  }
  else if (retardcount == 120 )  //Prints blank when correction pulse is on last number
  {
    lcd.setCursor(0,1); 
    lcd.print("                    ");
    // lcd.print(retardcount);
  } 
*/

  if (seconds >= 0 && seconds <= 5) // Ignored while clock is correcting forward or retarding
  {

    lcd.setCursor(0,1); //Start at character 0 on line 0
    lcd.print(" DCF77 Master Clock ");      

  }
  
  else if(seconds > 05 && seconds <= 10) // Ignored while clock is correcting forward or retarding
  {
    lcd.setCursor(0,1); //Start at character 0 on line 0
    //lcd.print(" DCF77 Master Clock ");  
    lcd.print(" Brett Oliver  v23 ");
  }

  else if(seconds == 11) // Ignored while clock is correcting forward or retarding
  {
    lcd.setCursor(0,1); //Start at character 0 on line 0

    lcd.print("                    ");
  }

  else if(seconds > 11 && seconds <= 13) // Ignored while clock is correcting forward or retarding
  {
    lcd.setCursor(0,1); //Start at character 0 on line 0

    // lcd.print("       Pulses       ");
    lcd.print("   1 Second Clocks  ");

  }




  else if(seconds == 14) // Ignored while clock is correcting forward or retarding
  {
    lcd.setCursor(0,1); //Start at character 0 on line 0

    lcd.print("                    ");
  }


  else if(seconds > 14 && seconds <= 16) // Ignored while clock is correcting forward or retarding
  {
    lcd.setCursor(0,1); //Start at character 0 on line 0
    lcd.print(" Slow Pulses "); // miss pulse detected so extra 1 second motor pulse added
    lcd.print(misscount);
   }

 else if(seconds == 17) // Ignored while clock is correcting forward or retarding
  {
    lcd.setCursor(0,1); //Start at character 0 on line 0

    lcd.print("                    ");
  }


else if(seconds > 17 && seconds <= 21 && yearmiss != 00 ) // Ignored while clock is correcting forward or retarding
  {
    lcd.setCursor(0,1); //Start at character 0 on line 0
    
    //lcd.print(hourmiss);
    printLCDH(hourmiss); // adds leadng zero if hour is less than 10
   // lcd.print(":");
    //lcd.print(minutemiss);
   // lcd.print(":");
    printLCD(minutemiss); // adds leadng zero if minutes is less than 10
    //lcd.print(secondmiss);
    printLCD(secondmiss); // adds leadng zero if seconds is less than 10
    lcd.print("  ");
    
    
    printLCDH(daymiss); // adds leadng zero if day is less than 10
    lcd.print("/");
    printLCDH(monthmiss); // adds leadng zero if month is less than 10
    lcd.print("/");
    lcd.print("20");
    lcd.print(yearmiss);
    
    
  }
 else if(seconds > 17 && seconds <= 21 && yearmiss == 00 ) // if no fast pulses "Never" is printed not date
  {
    lcd.setCursor(0,1); //Start at character 0 on line 0
    
    lcd.print("     Never     ");
   
    
  }

else if(seconds == 22) // Ignored while clock is correcting forward or retarding
  {
    lcd.setCursor(0,1); //Start at character 0 on line 0

    lcd.print("                    ");
  }
 else if(seconds > 22 && seconds <= 26) // Ignored while clock is correcting forward or retarding
  {
    lcd.setCursor(0,1); //Start at character 0 on line 0
    lcd.print("  Fast Pulses "); // miss pulse detected so extra 1 second motor pulse added
    lcd.print(extracount);
   }

 else if(seconds == 27) // Ignored while clock is correcting forward or retarding
  {
    lcd.setCursor(0,1); //Start at character 0 on line 0

    lcd.print("                    ");
  }


else if(seconds > 27 && seconds <= 31 && yearextra != 00 ) 
  {
    lcd.setCursor(0,1); //Start at character 0 on line 0
    
     //lcd.print(hourmiss);
    printLCDH(hourextra); // adds leadng zero if hour is less than 10
   // lcd.print(":");
    //lcd.print(minutemiss);
   // lcd.print(":");
    printLCD(minuteextra); // adds leadng zero if minutes is less than 10
    //lcd.print(secondmiss);
    printLCD(secondextra); // adds leadng zero if seconds is less than 10
    lcd.print("  ");
    
    printLCDH(dayextra); // adds leadng zero if day is less than 10
    lcd.print("/");
    printLCDH(monthextra); // adds leadng zero if month is less than 10
    lcd.print("/");
    lcd.print("20");
    lcd.print(yearextra); // adds leading zero if year is less than 10
    
  }
  else if(seconds > 27 && seconds <= 31 && yearextra == 00 ) // if no fast pulses "Never" is printed not date
  {
    lcd.setCursor(0,1); //Start at character 0 on line 0
    
    lcd.print("     Never     ");
   
    
  }
  

else if(seconds == 32) // Ignored while clock is correcting forward or retarding
  {
    lcd.setCursor(0,1); //Start at character 0 on line 0

    lcd.print("                    ");
  }

  else if(seconds > 32 && seconds <=59) // Ignored while clock is correcting forward or retarding
  {
    lcd.setCursor(0,1); //Start at character 0 on line 0
    lcd.print("  Slow "); // miss pulse detected so extra 1 second motor pulse added
    lcd.print(misscount);

    lcd.print(" ");
    lcd.print("   Fast ");        
    lcd.print(extracount);
  }



  
  // End display of slow and fast pulses on row 01
  
  }
  

  
  void printLCD(int LCDdigits){
  // utility function for digital clock display: prints preceding colon and leading 0 on mins and secs
  lcd.print(":");
  if(LCDdigits < 10)
    lcd.print('0');
  lcd.print(LCDdigits); 

}




void printLCDH(int LCDdigitH){
  // utility function for digital clock display: prints leading 0 on hours
  if(LCDdigitH < 10)  
    lcd.print("0"); // Print hour on first line
  lcd.print(LCDdigitH);
}




void printPTen(int PTen){ // light LED every min on 00

  if(PTen == 00)
  {
    //Serial.print(PTen);
    digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)

  }
  else if(PTen != 00)

    digitalWrite(led, LOW);   // turn the LED off (LOW is the voltage level)

}





void printP30(int P30){ // light LED every 30 seconds

  if(P30 == 00 || P30 == 30)
  {
   // Serial.print(P30);
    digitalWrite(led30, HIGH);   // turn the LED on (HIGH is the voltage level)

  }
  else if(P30 != 00 || P30 !=30)

    digitalWrite(led30, LOW);   // turn the LED off (LOW is the voltage level)

  else if(P30 == 59 || P30 == 29)// makes sure clock pulses 30 sec pulse if DCF77 time corrects @ 59 or 29 sec

  {

   // Serial.print(P30);
    digitalWrite(led30, HIGH);   // turn the LED on (HIGH is the voltage level)
  }
  else if(P30 != 59 || P30 !=29) //// makes sure clock pulses turn off 30 sec pulse if DCF77 time corrects @ 59 or 29 sec

    digitalWrite(led30, LOW);   // turn the LED off (LOW is the voltage level)
 }




void printP05(int P05){ // light LED 10 every 5 seconds

  if(P05 == 00 || P05 == 05 || P05 == 10 || P05 == 15 || P05 == 20 || P05 == 25 || P05 == 30 || P05 == 35 || P05 == 40 || P05 == 45 || P05 == 50 || P05 == 55)
  {
   // Serial.print(P05);
    digitalWrite(led05, HIGH);   // turn the LED on (HIGH is the voltage level)

  }
  else if(P05 != 00 || P05 !=05 || P05 !=10 || P05 !=15 || P05 !=20 || P05 !=25 || P05 !=30 || P05 !=35 || P05 !=40 || P05 !=45 || P05 !=50 || P05 !=55)

    digitalWrite(led05, LOW);   // turn the LED off (LOW is the voltage level)
  }





void printP10(int P10){ // light LED 09 every 10 seconds

  if(P10 == 00 || P10 == 10 || P10 == 20 || P10 == 30 || P10 == 40 || P10 == 50)
  {
    //Serial.print(P10);
    digitalWrite(led10, HIGH);   // turn the LED on (HIGH is the voltage level)
     }
  else if(P10 != 00 || P10 !=10 || P10 !=20 || P10 !=30 || P10 !=40 || P10 !=50)

    digitalWrite(led10, LOW);   // turn the LED off (LOW is the voltage level)

}

/*
void printP15(int P15){ // light LED 03 every 15 seconds

  if(P15 == 00 || P15 == 15 || P15 == 30 || P15 == 45)
  {
  // Serial.print(P15);
    digitalWrite(led15, HIGH);   // turn the LED on (HIGH is the voltage level)
  }
  else if(P15 != 00 || P15 !=15 || P15 !=30 || P15 !=45)

    digitalWrite(led15, LOW);   // turn the LED off (LOW is the voltage level)

}
*/
void printP20(int P20){ // light LED 08 every 20 seconds

  if(P20 == 00 || P20 == 20 || P20 == 40)
  {
   //Serial.print(P20);
    digitalWrite(led20, HIGH);   // turn the LED on (HIGH is the voltage level)
  }
  else if(P20 != 00 || P20 !=20 || P20 !=40)

    digitalWrite(led20, LOW);   // turn the LED off (LOW is the voltage level)
}


void printPhour(int Phour){ // light LED every hour on 00

  if(Phour == 00 && seconds == 00)
  {
  // Serial.print(Phour);
    digitalWrite(ledh, HIGH);   // turn the LED on (HIGH is the voltage level)
  }
  else if(seconds != 00) // turn off hour pulse when secs are not 00

      digitalWrite(ledh, LOW);   // turn the LED off (LOW is the voltage level)

}
void printPday(int Pday){ // light LED every day on 00

  if(Pday == 00 && seconds == 00)
  {
    //Serial.print(Pday);
    digitalWrite(ledd, HIGH);   // turn the LED on (HIGH is the voltage level)
  }
  else if(seconds != 00) //turn off day pulse when secs are not 00

      digitalWrite(ledd, LOW);   // turn the LED off (LOW is the voltage level)


}



 void secondsmotor (){
   // Quartz clock driver
  // toggle Quartz drive A2 & A3 evey second
  if (quartzmotor1 == LOW)
  { 
    quartzmotor1 = HIGH;
  }
  else
    quartzmotor1 = LOW;
  {
    digitalWrite(quartz01, quartzmotor1); // set the quartz motor drive A2 pin
  }
  if (quartzmotor2 == HIGH)
  { 
    quartzmotor2 = LOW;
  }
  else
    quartzmotor2 = HIGH;
  {
    digitalWrite(quartz02, quartzmotor2); // set the quartz motor drive A3 pin     

  }
  }


void blankrow3() {
  lcd.setCursor(0,3);
  lcd.print("               "); 
}





void signalmatch() {

  signalQual = DCF77_Clock::get_prediction_match();
  if(signalQual == 255 || signalQual == 0 )
  {
    signalQual = 00;
  }
  else
  {
    signalQual = signalQual * 2;
  }
   lcd.setCursor(0,3);
  lcd.print("Sig Match ");
  lcd.print(signalQual);
  lcd.print("%");
}



void precision() {
  lcd.setCursor(0,3);
  lcd.print("Accuracy ");
  lcd.print(DCF77_Frequency_Control::get_confirmed_precision());
  lcd.print("Hz "); 
}

void freqadj() {
  lcd.setCursor(0,3);
 // lcd.print("Qtz ");
  lcd.print(16000000L - DCF77_1_Khz_Generator::read_adjustment());
  lcd.print("Hz"); 
}