Missing seconds on DCF77 clock with pulse generator


I am building a DCF77 Master Bracket Clock as a backup to my main master & slave clock system.

I have used a DCF77 receiver module to get the time and display it on a 4x20 LCD display and a old quartz skeleton clock. The pulse outputs to drive my various slaves are displayed by LEDs.

I ran the project on breadboard and all seemed fine. Now I have put the clock together and started driving the quartz clock motor with pulses I seem to be missing a few seconds a day.

The code loop below relies on the change of display each second to generate my Quartz drive pulse.
99.9% of the time it is fine but when I leave the clock running overnight I nearly always find the seconds on the quartz clock are a few seconds out. I have never been watching when the clock misses a second so I am not sure when it fails.

The Time and Timezone libraries are used.
I am not quite sure how the Time library corrects/decodes the DCF77 signal but I think it must jump the odd second every now and then causing the program to miss a loop.

Is there a way to force the loop every second even if the display misses a second while keeping in sync with the DCF77?

EG if the display does not change for a second then start the loop and check again the next second.

void loop()
{  
  if( now() != prevDisplay) //update the display only if the time has changed
  {
    prevDisplay = now();
    //lcd.clear(); //clear LCD screen
    digitalClockDisplay();
 
    
  }
}

void digitalClockDisplay(){
 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) 
// 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     
       
       
 
  // 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("Last Sync ");

  // show last sync time on LCD
  printLCDH(hoursync);
  lcd.print(":");
  printLCDH(minutesync);
  lcd.print(":");
  printLCDH(secondsync);
  lcd.setCursor(0,2);
  lcd.print("Sync Status 0");
  lcd.print(timeStatus());
  lcd.print("  GMT");
  lcd.setCursor(0,3);
  lcd.print(" DCF77 Master Clock");
  
}

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)

}


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

if( now() != prevDisplay) //update the display only if the time has changed
{
prevDisplay = now();

What happens if now() does not return the same value on both calls? Lost time.

Hmmm, what did you say your problem was?

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

Curly
braces
are
good.
So
is
proper
indenting. As is done by Tools + Auto Format.

Thanks for the reply.

Have added missing curly braces to my code. I presumed as it compiled without them in some situations when I accidentally missed them is was OK not to use them so i just carried on.

Did not know about Auto Format- Thanks for that.

Would I not lose time if now() returned the same value? Say if the decoded DCF77 returned the same time for 2 seconds then it would stay in the loop for another second and my Quartz pulse drive would miss a pulse?

What if I" waited for the display to change" or " waited for 1001 ms to elapse" then jump to " digitalClockDisplay()"

The quartz clock would be 1ms fast for 1 second then correct itself when the display changed.

What if I" waited for the display to change" or " waited for 1001 ms to elapse" then jump to " digitalClockDisplay()"

What if you assigned the value to a variable, and used it in both places?

Don't try to be smarter than the clock.

What if you assigned the value to a variable, and used it in both places?

Not sure what you mean?

I was thinking "keep waiting for display to change" else timeout after 1 second and go through the digitalClockDisplay() to update the Quartz clock pulse. This will keep the Quartz clock motor on time. The next second it will wait again for the display to change again etc etc.

Not sure what you mean?

void loop()
{
   someType currDisplay = now();
   if(currDisplay != prevDisplay)
   {
      prevDisplay = currDisplay;
      // Change the display...

(where someType is the same (undefined) type as prevDisplay).

OK I see what you mean. So I now have another variable to work with.

I have just setup another chip running the program and connected a clock motor to monitor the seconds while logging the time and millis( ) on my serial port . I want to try and see where the seconds are failing.

I have been lucky with my 2nd trial setup and found a missing second very quickly.
Table below shows serial port print of time and program time. I ran it through excel to quickly spot the

Data Secs Diff Millis( ) Diff mS Sync
20:38:07 28 11 2013 410682 07 1 410682 1000
20:38:08 28 11 2013 411682 08 1 411682 1000
20:38:09 28 11 2013 412682 09 1 412682 1000
20:38:10 28 11 2013 413682 10 1 413682 1000
20:38:11 28 11 2013 414682 11 1 414682 1000
20:38:12 28 11 2013 415682 12 1 415682 1000
20:38:13 28 11 2013 416683 13 1 416683 1001
20:38:14 28 11 2013 417682 14 1 417682 999
20:38:15 28 11 2013 418682 15 1 418682 1000
20:38:16 28 11 2013 419682 16 1 419682 1000
20:38:17 28 11 2013 420687 17 1 420687 1005 Sync
20:38:19 28 11 2013 421687 19 2 421687 1000
20:38:20 28 11 2013 422687 20 1 422687 1000
20:38:21 28 11 2013 423687 21 1 423687 1000
20:38:22 28 11 2013 424687 22 1 424687 1000
20:38:23 28 11 2013 425687 23 1 425687 1000
20:38:24 28 11 2013 426687 24 1 426687 1000
20:38:25 28 11 2013 427687 25 1 427687 1000
20:38:26 28 11 2013 428687 26 1 428687 1000
20:38:27 28 11 2013 429687 27 1 429687 1000
20:38:28 28 11 2013 430687 28 1 430687 1000
20:38:29 28 11 2013 431687 29 1 431687 1000
20:38:30 28 11 2013 432687 30 1 432687 1000
20:38:31 28 11 2013 433687 31 1 433687 1000
20:38:32 28 11 2013 434688 32 1 434688 1001
[/table]
At 20:38:17 the clock sync'd and the next second jumped 2 seconds. The actual program run time was 1 second.
Maybe I can check time() against previous time()and if it is more than 1 add another pulse in the second?
My clock motor should be able to cope.

I have tried a test on my quartz cock motor and it will double pulse if I add a 100mS delay between pulses. I have read that care should be taken using "delay" .
I guess I have some time to play with between the second pulses so it should not cause a problem?

All I need is to check after any "sync" if there is more than a second between time() and previous time() then add a double pulse.

I think I need to add some code to check if a "sync" occurs on 0,5,10,20, 30 as these pulse will also be missed.

I have now managed to detect missing pulses and an extra one to keep my analogue clock in sync. I just need to do this for the other pulses and also chimes...........................

  }
}

void loop()
{  
  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();
    }
}

void digitalClockDisplay(){

I have also changed the display a bit to show when last missing pulse was detected and also number of missing pulses per day.