DCF77 to set DS3231 Realtime Clock Error

Hi all, I am trying to use a DCF77 module to update the DS3231 Realtime Clock. I am using the following code that I got as an example code from a book, but somehow it does not get the time from the DCF77. What is missing? I know that the hardware is setup all right by trying SyncProvider Example included in the DCF77 library. I get a signal after 140seconds.

#include <Time.h>
#include <DS1307RTC.h>
#include <DCF77.h> 
#include <Wire.h>

#define DCF_PIN 2
#define DCF_INTERRUPT 0
int WaitingForSignalCounter = 0;

time_t time;
DCF77 DCF = DCF77(DCF_PIN,DCF_INTERRUPT);
int ledPin = 13;

void setup() 
{ 
pinMode(ledPin, OUTPUT);
Serial.begin(9600); 
DCF.Start();
  Serial.println("Waiting for DCF77 time ... ");
  Serial.println("It will take at least 2 minutes until a first update can be processed.");
  while(timeStatus()== timeNotSet) //Outputs the waiting for signal time in serial monitor. 140s should be enough)
      {      
     Serial.print(WaitingForSignalCounter);
     Serial.print("s ");
     WaitingForSignalCounter +=10;
     delay(10000);
      }
}
void loop()
{
  time_t DCFtime = DCF.getTime(); 
  if (DCFtime!=0) 
  {
  tmElements_t tm;
  breakTime(DCFtime, tm); 
  Serial.println("DCFtime!=0"); 
    if (RTC.write(tm)) 
      {
     Serial.println("RTC erfolgreich gesetzt!"); 
     digitalClockDisplay(DCFtime); 
     digitalWrite(ledPin, HIGH);
      delay(45000);
      digitalWrite(ledPin, LOW); 
      } 
     else 
      {
      delay(250); 
      Serial.println("Delay 250"); 
      }
  } 
  else 
  { digitalWrite(ledPin, HIGH);
  delay(250);
  digitalWrite(ledPin, LOW);
  delay(250);
  Serial.println("digitalwrie(ledPin, High");
  digitalClockDisplay;
  } 
}
// Hilfsfunktion für serielle Ausgabe 
void digitalClockDisplay(time_t _time)
{
  tmElements_t tm;
  breakTime(_time, tm);
  Serial.println("");
  Serial.print("Zeit: "); 
  Serial.print(tm.Hour); 
  Serial.print(":"); 
  printDigits(tm.Minute); 
  Serial.print(":"); 
  printDigits(tm.Second); 
  Serial.print(" Datum: "); 
  Serial.print(tm.Day); 
  Serial.print("."); 
  Serial.print(tm.Month); 
  Serial.print("."); 
  Serial.println(tm.Year+1970);
 }
// Hilfsfunktion für Formatierung
void printDigits(int digits)
{
Serial.print(":"); 
if(digits < 10)
Serial.print('0');
}

For those that are not from Europe: DCF77 is a service that distributes the current time and date over radio frequencies over an antenna in Frankfurt. All of Germany and most other European countries can get this signal. It is often used in alarm clocks since it means you do not have to set the time by hand.

spooner777:
I get a signal after 140seconds.

What does that mean?

Please check the signal you get, here is a sketch for testing:

#define LEDPIN 13
#define DCFPIN 8

void setup() {
  Serial.begin(9600);
  Serial.println("DCF77 test sketch by 'jurs'");
  pinMode(LEDPIN, OUTPUT);
  pinMode(DCFPIN, INPUT);
}

boolean lastState;
unsigned long lastChangeTime;
unsigned int hitime, lotime, pulsetime;

void loop() {
  boolean state= digitalRead(DCFPIN);
  if (state!=lastState)
  {
    long changeTime=millis();
    if (lastState)
    {
      Serial.print("H ");
      hitime=changeTime-lastChangeTime;
      Serial.print(hitime);
      Serial.print('\t');
    }
    else 
    {
      Serial.print("L ");
      lotime=changeTime-lastChangeTime;
      Serial.print(lotime);
      Serial.print('\t');
      pulsetime=hitime+lotime;
      Serial.print("= ");
      Serial.print(pulsetime);
      if (pulsetime>=960 && pulsetime<=1040)
      {
        Serial.print("\tOK  ");
        if (hitime<150) Serial.println('0'); else Serial.println('1');
      }
      else if (pulsetime>=1960 && pulsetime<=2040) Serial.println("\tMinute Marker");
      else Serial.println();
    }
    lastState=state;
    lastChangeTime=changeTime;
  }
}

Send the serial output you get from your receiver (about a minute or two) using that test sketch and let’s see the quality of your signal!

From your code I would make the guess that you are using the DCF library of Thijs Elenbaas, right?

The DCF library by Thijs Elenbaas is using only a very simple signal detection algorithm. It depends on the DCF module whether this library is providing good or poor results. Good results with that library are only to be expected, if the module hardware itself does some low-pass signal filtering.

Using the SyncProvider example, I get the correct time consistently after roughly 140seconds. So I am not having signal issues at all. I think I am having code Issues. All I want to do is let the DCF77 update the RTC from time to time. It seems though that the code I posted does not process the signal it gets. (or show it to me, or sync the RTC with it as it is supposed to.)

I am using the library you mentioned.

spooner777:
Using the SyncProvider example, I get the correct time consistently after roughly 140seconds. So I am not having signal issues at all.

I understand: You get a DCF time after 2-3 minutes.

So let’s see about your libraries and programming logic in your code.
You are providing three different times while using three different time libraries:

#include <Time.h>  // "System time", also provides a lot of timing functions
#include <DS1307RTC.h> // "RTC time", the time running in the RTC
#include <DCF77.h>  // "DCF time", the time you get once per minute (at best)

So you need a synchronizing of your three times. Currently you seem to never use the “system time”, while you also never read the “RTC time”, and there is only one place in your code where you read the “DCF time” and write it to “RTC time”.

In one line of your sketch it looks as if you want to call a function, but you don’t do it, as the parameter is missing. You wrote:

digitalClockDisplay; // this line does nothing

but you probably wanted to do a function call:

digitalClockDisplay(someParameter); // this line does a function call

I’d recommend something like that as a programming logic for your loop() function:

  • if received a valid DCF time ==> store it to RTC
  • if one second has gone since last display update ==> read time from RTC and display it

jurs: I'd recommend something like that as a programming logic for your loop() function: - if received a valid DCF time ==> store it to RTC - if one second has gone since last display update ==> read time from RTC and display it

Exactly, how would this code have to look like?

spooner777:
Exactly, how would this code have to look like?

I will attach a code that I have done myself.

Required hardware:

  • Arduino board
  • RTC (DS1307 or DS3231) module
  • DCF77 module

Installation:
Download the attached ZIP file, then unpack the folder named “dcfRTC” which is contained in the ZIP file, into your sketch folder. Then open the “dcfRTC” sketch in your Arduino-IDE, compile and upload.

No external third-party libraries needed.

Configuration:
If your DCF module provides an “open collector output” and requires pull-up resistors:

#define DCF_INPUTMODE INPUT_PULLUP

If your DCF module provides a “push-pull output” or is already equipped with pull-up resistors:

#define DCF_INPUTMODE INPUT

“INVERTEDSIGNAL false” means, that your module provides HIGH pulses of 100/200ms (LOW 900/800ms)
“INVERTEDSIGNAL true” means, that your module provides LOW pulses of 100/200ms (HIGH 900/800ms)

Inner working:
The program will read the RTC once per second and show the time of the RTC as output on Serial.
If a valid DCF time telegram is received, the DCF time will be used to update the time of the RTC.

With setting:

#define DEBUGMODE 0

all extra debug code is switched off. If you want to see extra debugging messages, set:

#define DEBUGMODE 1

Good luck!

And send some feedback, if it works or if you find any problems!

DCFclockRTC.zip (3.3 KB)

Thanks a lot! This works amazingly well! Did you consider writing a blog entry/youtube video to further publicise your code? I was looking for this for ages, but only found either RTC or DCF Code. I managed to find the code from the original post, but that does not work.

spooner777: Thanks a lot! This works amazingly well!

Thank you very much for sending feedback about the code!

spooner777: Did you consider writing a blog entry/youtube video to further publicise your code?

No, I don't have such plans. The code posted was copied together from existing code on my harddisk this afternoon. The DCF decoder part of the sketch had already been published in the German section of this forum a couple of months ago.

And combining the DCF decoder and a RTC is not that complicated.

1st step: Ask the DCF decoder if a newly decoded time is available 2nd step: If yes, save that time to the RTC module 3rd step: Ask the millis() counter if 1000 milliseconds have passed since last date/time output 4th step: If yes, read time from RTC and output formatted date/time 5th step: loop() over to 1st step

The code as posted is also not suitable for every program, but only for programs with a fast running loop. The time for running once through the loop should not exceed 1, 2, 3 or perhaps max. 5 milliseconds.

Otherwise "polling the DCF signal" might lead to false signal readings despite of a "good" DCF signal.

For people who like to block the program execution with "delay()", this type of DCF decoding is not suitable. The code then would need to use interrupts to detect the signal flanks and HIGH/LOW times of the signal. The code as posted is only suitable for sketches free of "delay()" and free of "busy-waiting loops".

I'd have to put some more efforts into the code, to make the code fool-proof against delay() and busy-waiting-loops, using interrupt driven signal detection.

That is true. I added a delay to the loop and it won't pick up the dcf signal anymore. The RTC clock still works though. Since I need to be moving some steper motors, delays are neccesarry.

spooner777: That is true. I added a delay to the loop and it won't pick up the dcf signal anymore. The RTC clock still works though. Since I need to be moving some steper motors, delays are neccesarry.

I don't thinkt that delays are necessary.

Delays prevent that more than one thing can execute undisturbed at the same time on a controller with a single core.

Typically you write non-blocking "cooperative multitasking" code in your sketch to handle multiple actions at the same time. Such as I already wrote "cooperative multitasking" code to handle two different actions: - read the DCF module and update RTC time - read the RTC time and display each second

You easily can add more tasks, if the code is done in a "cooperative multitasking" way.

Or you are doing different tasks at different times. What about that: Perhaps you find some time of the day when the stepper motors are not active, perhaps nighttime between 2 and 3 a clock?

A DS3231 is a very accurate RTC which is accurate to 60 seconds per year, that is 5 seconds per month. So if you want the RTC to provide a better accuracy than 5 seconds to the official time in Middle Europe, it would be enough to update the DCF time once per month.

jurs: I'd have to put some more efforts into the code, to make the code fool-proof against delay() and busy-waiting-loops, using interrupt driven signal detection.

You could, but as a general approach, sequential non-blocking code in loop() has many advantages. One is that there is less chance that separate code modules will depend on the same timers or interrupts as another. As a consequence, the number of tasks is limited only by available processor time, not by the allocation of the precious hardware resources.

This approach does not rule out the use of timers and interrupts. In fact, it allows the programmer to assign those resources more effectively to tasks.

Concerning making it foolproof, it is often hard for a wise person to imagine what a fool will do. Usually that kind of effort is a wash.

aarg: You could, but as a general approach, sequential non-blocking code in loop() has many advantages. One is that there is less chance that separate code modules will depend on the same timers or interrupts as another. As a consequence, the number of tasks is limited only by available processor time, not by the allocation of the precious hardware resources.

This approach does not rule out the use of timers and interrupts. In fact, it allows the programmer to assign those resources more effectively to tasks.

Concerning making it foolproof, it is often hard for a wise person to imagine what a fool will do. Usually that kind of effort is a wash.

So does this just mean using the whole millis-thing instead of delay?

Hallo,

I just realised, that I wrote german in an English forum. Sorry for that ! I just have question to the sketch from jurs, because I get the following message:

6 932 1190 2122 1 1 Error: Time code must contain 59 bits!

What is the meaning of this and which changes I need to make? Thanks for any suggestion, kind regards, Arne

Arne3a:
Was bedeutet das und welche Änderungen muss ich vornehmen?

First of all you should change the language when posting in this part of the forum

When posting in "Programming Questions, you better use ONLY ENGLISH, which is the correct language to be used for your message in “Programming Questions”!

Postings in German (Deutsch) language are ONLY placed correctly, when posted in

Deutsch

Yes, I just realised use of the wrong language... Sorry. Was done without intention.

Arne

Hallo,

The script from jurs provided a nice time with an DCF-receptor from elv.

I gott the time update, after I - changed position in my house - unplugged the USB cable from the arduino.

My "real" goal is to use the DCF time set in the RTC for the update of a wordclock. Now I am struggling-

Currently I try to integrate the time in the sketch for the clock, but there are some obstacles.

What would be the best / easiest way to get the time out of the script provided by jurs? Is there a possibility to retrieve the date with a small set of code?

Thank you for your ongoing help! Very much appreciated! kind regards, Arne

I thought that Jurs, the author of that code, was on this thread, at least for reminding you to use English in this part of the forum.

What I can say is this that maintaining an RTC using a DCF77 receiver is relatively straightforward, assuming you have a working receiver sketch for the dcf77 receiver and in a reliable signal area. However there are a number of problems:

  1. If you simply accept the time that the DCF receiver gives, you could have some nasty surprises, particularly in a noisy signal environment. You'll see occasionally strange times on your clock.

  2. You can't guarantee that the DCF signal is readable at the time when there is a daylight saving change so for few days, your clock might be one hour out of sync.

I have developed a sketch which solves both these problems, but I'm a bit reluctant to publish it simply because it is not simple to support if people have questions, and the coding isn't beautiful either.

But, anyway, it works like this:

The real time clock runs in UTC and is the primary time source for the clock. Any time which is read from the DCF receiver is converted to UTC and compared with the RTC. If there is a delta (discrepancy) between the RTC and the DCF reading then the delta is stored. If the next plausible reading from DCF has approximately the same delta offset to the RTC time, then it is accepted as a change to the RTC. This eliminates most false readings. The clock uses a variant of the time zone library and handles daylight saving changes itself so is accurate even when the DCF signal is not available around a daylight savings time changeover.

I'm about 400 Km south of Frankfurt and I have problems with local electrical interference causing missing signals. The worst issues around me are switching mode power supplies, mobile phone chargers and the like. I even had problems with the frequency of the clock display multiplexing and had to optimise this during the design to reduce interference to its DCF receiver. For reception problems, first check that you are using an adequate low noise power supply for the clock.