headerDCF77
headerDCF77

Arduino DCF77 radio clock receiver – Library

| 74 Comments

(This is part 3 in a small series on using DCF77 for accurate time keeping with an Arduino. You can find post #1 here and post #2 here)

Before we start to look at the library, let me start by saying that this is by no means the first Arduino DCF77 decoder. In fact, a large part of this library is based on the sketch made by Matthias Dalheimer. I did not intend to write a new library, but because of the noise spikes I was picking up, I started rewriting parts to make it work under noisy circumstances and, as these things seem to go, ending up writing a whole new library.

Because of the noise I added, besides the spike rejection, some checks on the decoded time. Furthermore I made made another major change in the code: The class library attaches an interrupt function to the DCF77 pin, which fills a buffer with the received bits. This interrupt-driven part is made to be quite lightweight, while the hard work (checking parity, calculating time, doing a few sanity checks) is done in the code called from the main loop. But because the interrupt driven loop fills the buffer (and starts filling a new buffer after that), so there is no real hurry in the main loop to re-enter the getTime function.

To use the library, first download the DCF77 library here:

A zipped tarball of the version as well as older versions can be found here.

and install it in the Arduino Library folder. For a tutorial on how to install new libraries for use with the Arduino development environment please refer to the following website: http://www.arduino.cc/en/Reference/Libraries. If the library is installed at the correct location, you can find the examples discussed in this and the previous post under Examples > DCF77. I also added the time library to the archiver for convenience.

Below is a demonstration of how the library processes the binary data and returns a time and date. In order for the example to give output on the binary stream make sure that logging is turned on in the DCF library. You can do this by adding the #define VERBOSE_DEBUG 1 in Utils.cpp.

I get the following output:
output Arduino DCF77 radio clock receiver   Library image

After the first full cycle we get the feedback “time inconsistent” because:

  1. The difference between the DCF77 time and the internal time (still close to 0 -which translates to a date in 1970-) is too big
  2. The difference with there is no previous DCF77 time measurement is too big because, well, there is no previous measurement.

After the second cycle there is a previous measurement and both measurement points are consistent, and we get our first DCF77 time. Success! Note that the time queried with DCF.getTime() is compensated for the period between receiving the time from the receiver and the moment that it is queried from the library.

Now, let’s try an example that actually updates the internal clock time. For this example the output I turned logging off.

Resulting in the following output:

output1 Arduino DCF77 radio clock receiver   Library image

Output example showing how to fetch a DCF77 time and synchronize the internal clock.

Finally, that kind of wraps things up. However, I want to demonstrate one last thing. I used the Time libraryquite a lot in the library, but it also has a feature that is you can nicely use in your main program.

 

Below is an example sketch showing how to use the syncProvider functionality to simplify the sketch code. Note that the loop code does not require any logic to maintain time sync and even the getDCFTime function could be removed to make the code even more concise. The Time library will automatically monitor DCF77 and sync the time as necessary.

ps. After writing this library I discovered another Arduino DCF77 class that is based on the code of Matthias Dalheimer at http://fiendie.net/arduino/funkuhr. I haven’t tried it, but the code looks quite clean, so give it a shot.

74 Comments

  1. Hallo Thijs,

    Als ik het InternalClockSync programma viade verify toets test dan krijg ik volgende foutmeldingen.

    InternalClockSync.cpp:13:19: error: DCF77.h: No such file or directory
    InternalClockSync:19: error: ‘DCF77′ does not name a type
    InternalClockSync.cpp: In function ‘void setup()’:
    InternalClockSync:24: error: ‘DCF’ was not declared in this scope
    InternalClockSync.cpp: In function ‘void loop()’:
    InternalClockSync:31: error: ‘DCF’ was not declared in this scope

    Ik gebruik Arduino 1.0.
    Heb je enig idee wat de oorzaak kan zijn?

    Alvast bedankt,

    Michielsen Luc

    • Hi Luc,

      Het probleem is dat de DCF77 niet gevonden kan worden, en in de meeste gevallen betekent dit dat de files op de verkeerde locatie staan.

      Op de Arduino site staat er dit over geschreven:
      http://www.arduino.cc/en/Hacking/Libraries

      Ik heb hier zelf alleen ervaring mee onder Windows (7), daar heb je 2 opties:
      - Als een standaard bibliotheek: D:\\libraries\DCF77\DCF77.h, DCF77.cpp, etc
      Zo heb ik de boel geinstalleerd, maar het volgende zou ook moeten werken:
      - Per gebruiker, dan zou de file hier terecht moeten komen C:\Users\\Documents\Arduino\DCF77\DCF77.h, DCF77.cpp, etc

      Als het goed is zie je dan in de Arduino IDE de examples onder Examples>DCF77.

      Succes!
      Thijs

  2. Hi Thijs,

    I just downloaded your DCF77 library from the Arduino Playground. It
    works great, thank you very much!

    Maybe you are interested to know that there is a little thing at line
    94 in DCF77.cpp that prevents the user from changing the DCF input pin.

    In function void DCF77::int0handler() it says:
    int sensorValue = digitalRead(2);

    but should be:
    int sensorValue = digitalRead(dCF77Pin);

    This is only for your information – I am far away to complain!
    Have fun!

    Regards
    Sabine

    • Hi Sabine,

      Thanks for caching that! I will solve this in the next release. Good luck using the library. if you have been able to use it in a project, I’m always interested to hear about it.

      Thijs

      • Hi Thijs,

        I am trying to build a standalone rf transmitter for the digital ham radio mode WSPR using an Arduino and a DDS. With the help of your library, I now got he time base running and will now try to set the DDS to the MFSK frequencies to transmit. Hope I will succeed! ;-)

        Best regards
        Sabine

  3. Hi Thijs,

    when I use the library with the DCF-2 hardware ( http://www.elv.de/i-c-realtime-clock-i2c-rtc-komplettbausatz.html ), the DCFPulseLength example sketch
    prints unexpected results: the cycle length is around 1000 ms, but the
    Pulse length is always in a range around 900 ms (maybe 800-920).

    This probably is the reason why the time is never synchronized. Do you have an
    idea about the reason for this effect, and how to debug it?

    Heiner

  4. Hey Thijs,

    tried out your Libary today. It works perfect for me. The only thing I had to change was the pull-up resistor. I used 1.1kOhm insted of the proposed 10kOhm. Also I didn’t used the capacitor described in the first post.

    Thank you for sharing.

  5. Hi Thijs,

    Firstly, thank you for making your excellent DCF77 library available for others to use.

    I am trying to get the Symtrik MSF60 receiver to work, here in the UK, with an Arduino (that is already hooked up to a DS3232 RTC) and was looking around for some suitable code to decode the output. The MSF examples I’ve found will not compile due to dependency issues with IDE 1.0+. Your code is bang up to date, and I have been able to use the DCFSignal and DCFPulseLength sketches to look at the receiver output in raw form, though obviously the DCFBinaryStream code cannot decode the MSF protocol.

    Do you have any pointers on how to modify the DCF77 library for use with MSF protocol?
    I guess it should be reasonably straightforward but I have a feeling that it is going to require a lot of experimentation and a huge learning curve!

    Best Regards,

    Squire

    • Hey squire, could you send me a sample of such a msf library? I could have a look at how easy it would be to make a msf library’based on the dcf library. No promises, though. Also, the debugging would have to be done by you, though, as I do t have such a receiver.

      For starters,  you could send me send me some screenshots of the output of dcfpulselength and dcfbinarystream?

      • About length of pulses using DCFPulseLength: With my DCF1 module from Pollin I find, that short pulses are at an average of roundabout 106 ms (range 95..110) and long pules are roundabout at an average of 206 ms (range 195..210).

        So pulses with my DCF module hardware seem to be much shorter than you found with your DCF hardware.

  6. Hi, Nice work :-) I’m looking at this MSF60 module http://www.earthshineelectronics.com/clock-modules/110-msf-60khz-time-receiver-module.html and wonder if I will need to make any changes to your code to get it working? …. any thoughts apreciated :-)

    • Yes, it wil definitely require significant changes: the pulse coding is different, I believe, and bit rearrange differently to a time structure.

    • Hallo Thijs,
      thanks for your library!

      Unfortunately I could not make the library fully work with my DCF1 module from Pollin, most likely because of an inverted output signal and no reverse signal output available on that cheap module I have.

      It seems as if your library cannot handle inverted output for decoding the time.

      Only the example sketch “DCFPulseLength” works well with my module and this programming example helped me a lot to find a good place for the module: Placed directly in front of my monitor, the module only got random spikes, but no clear one second pulses. So at first I thought, that my own DCF programming is full of bugs, or the hardware is not wired correctly or maybe the module is faulty. But your example “DCFPulseLength” showed me, that I just had to place the module wide enough away from my PC and LCD monitor and then the signal becomes a strong one second pulse.

      So that helped me a lot to program my own DCF decoding sketch.
      The better the signal quality, the better the decoding.

      I knew that DCF modules have no reception when operated near CRT (cathode ray tube) monitors and TVs, but I didn’t think about that the same happens when they are placed near LCD monitors. For my module, 1 metre is the minimum distance I have to keep the module away from LCD and PC, or the signal gets bad.

      • Hi,

        I’m sorry to reply this late. The noise susceptibility of the DCF receiver is indeed very high. I’m glad to hear you got your problem solved! I’m trying to buy a bigger DCF77 antenna. I will write post if this makes a realy difference.

    • I think that MSF60 decoding needs a slightly different decoder library as the decoding of MSF60 differs in some aspects from DCF77. Here is a link to a technical document I found:
      http://www.npl.co.uk/upload/pdf/MSF_Time_Date_Code.pdf

      Some things are identically, such as 60 seconds within one minute and an extra long pulse as the marker for the beginning of a new minute. And the BCD coding of the decimal values for hour, minute, day and so on is nearly the same.

      But on the other side there are some strange two-bit codes at least in the first 16 seconds of each minute, so that MSF60 does not only has three different pulse lengths (short pulse, long pulse, minute marker pulse) but has one pulse length extra: short pulse, long pulse, extra long pulse, minute marker pulse

      I think if you write some code that ignores the first 16 seconds which have the two-bit coding with three different pulse lengths, the coding is not so much different from DCF77. The actual time and date in MSF60 is coded with only two pulse lengths, just as DCF77. MSF60 is a bit different from DCF77, and so is the decoding.

      I’m just wondering if I am in the receiving range of the MSF60 transmitter. I’m living near Hamburg, Germany.

  7. Thijs,

    Thank you. I found a project by a fellow radio amateur, G7KSE, here:
    http://g7kse.co.uk/projects/arduino-msf-receiver/

    Which is based on this code:
    http://www.jarkman.co.uk/catalog/robots/MSFTimeExample.zip

    Symtrik MSF60 receiver details:
    http://www.pvelectronics.co.uk/rftime/SYM-RFT-XX.pdf

    MSF protocol from NPL:
    http://www.pvelectronics.co.uk/rftime/msf/MSF_Time_Date_Code.pdf

    I will post the serial monitor logs from my Ubuntu PC.

    Thanks,

    Squire

  8. Hi Thijs,

    thanks a lot for your DCF77 library for arduino. It’s very easy to start with.

    I wired a cheap DCF77 receiver from Pollin: http://www.pollin.de/shop/dt/NTQ5OTgxOTk-/

    It works out of the box. No extra components were necessary. :-)

    Then I ran your examples bundled with the library. It turns out that SyncProvider is one minute ahead at the first sync. InternalClockSync works as expected.

    Please find the output of InternalClockSync at http://pastebin.com/ZbtzWtqZ

    The output of SyncProvider is here: http://pastebin.com/5DSfAkjZ

    In line 4 of the output of SyncProvider it’s 12:01:00 actually. After the next sync the time is corrected (line 126).

    I tried both examples a couple of times. The hardware wasn’t touched or even looked at… ;-) The DCF77 signal is quite clear.

    Any idea what’s going wrong?

    Best regards
    Franz

    • Hi Franz,

      Thanks for using the library! The issue you see is weird, how did you know it was a minute late? It is suspicious that the difference is precisely 1 minute. The only things I can think of now is the following: when a new time is received, a time stamp from the system clock is stored together with the dcf time. Storing both is not implemented as a atomic action, so it could be one is updated while the other is not, because the transfer was interrupted. Another option is that the internal clock is updated after the timestamp but before syncProvider is called. I will try to reproduce this when I have time. do you have some sample code that produces this issue?

  9. Hi,
    thanks for this nice DCF library. I have only one problem, tried this, but it didn’t work:

    // Check DCF signal
    void CP5_TBZ::checkDCF ()
    {
    time_t DCFtime = DCF.getTime();
    if (DCFtime != 0)
    {
    m_bCurrDCF = true;
    setTime(DCFtime);
    }
    else { m_bCurrDCF = false; }

    }
    The var “m_bCurrDCF” nerver gets true, also if my LCD displays the actual time. That isn’t logical and i think ” if (DCFtime != 0)” nerver gets true. You have any idea how i control if i have the new time, the actual one?

    Best regards
    Janni

  10. Hi,
    Thanks for you clear postings on using the Conrad DCF receiver with an Arduino. I used as a basis for a timer that indicates to the kids that they have to sleep (red led), are allowed to wake up and play silently (yellow led) or can make noise and ask for breakfast (green led).
    Two remarks:
    - I found out that the combination Arduino/receiver has to be at least one meter (or about the length of a standard USB cable) away from a computer to function.
    - I only managed to get the combination running using a USB cable, either from a computer or from a mobile phone charger. When I tried to use it with an AC adapter on the power supply connector, the Arduino was not able to synchronize to the DCF signal. Do you have experience in this area?

    regards,
    Gerrit

    • Hi Gerrit,

      It nice to see the library being put to good use. I really like your idea! my daughter is now nearly 2 year old, so a little early yet for her, but I’ll try to remember it.

      About the bad signal: Since the time code is transmitted in the longwave range by amplitude modulation, it can therefore be easily disturbed, resulting in erroneous peaks. A source or RF noise is indeed the PC, the level of noise may depend on the shielding by the case.

      The samples I included in the package may help you to get a better grasp of the signal quality.

      I have been explained that noise may also creep up through the mains, either by picking up signal in the power lines or through the power supply. The latter I tried to minimize by using a by-pass capacitor. You could try using a bigger one and see if you AC power source works better. To minimize picking up signal, you can twist the cables going the DCF receiver

      Another thing you can try is buying a better antenna:
      http://fpga-xilinx.blogspot.nl/2012/04/your-6-hourly-digest-for-electronics_9462.html

      Meanwhile, I’m following Udo Kleins blog, he’s introducing a phase locked loop and exponential filtering (a simple moving average filter). This will make the library even more robust to noise:
      http://blog.blinkenlight.net/2012/12/01/dcf77-project/

      Beste wensen voor 2013!

  11. Hi Thijs,

    I got the DCF77 module as well and got it all quite easy to run, but I experience a not so good reception. even in front of a window, whereas my casio watch receives well.
    you got any tips to receive the signal better.

    • About the bad reception: I wrote this as a reply to essentially the same question by Gerrit, just below: the time code is transmitted in the longwave range by amplitude modulation, it can therefore be easily disturbed, resulting in erroneous peaks. A source or RF noise is indeed the PC, the level of noise may depend on the shielding by the case.

      The samples I included in the package may help you to get a better grasp of the signal quality.

      I have been explained that noise may also creep up through the mains, either by picking up signal in the power lines or through the power supply. The latter I tried to minimize by using a by-pass capacitor. You could try using a bigger one and see if you AC power source works better. To minimize picking up signal, you can twist the cables going the DCF receiver.

      I wonder if your Casio is really doing that much better. I most cases it is enough to get a DCF update once a day, as long if you also have a real-time clock.

      Another thing you can try is buying a better antenna:
      http://fpga-xilinx.blogspot.nl/2012/04/your-6-hourly-digest-for-electronics_9462.html

      Meanwhile, I’m following Udo Kleins blog, he’s introducing a phase locked loop and exponential filtering (a simple moving average filter). This will make the library even more robust to noise:
      http://blog.blinkenlight.net/2012/12/01/dcf77-project/

      Beste wensen voor 2013!

      • Hi Thijs,

        Beste wensen too!! Thanks for this, this is very helpful!
        Meanwhile I have been looking into your library and decided to make some changes for my own benefit, basically for the user interface experience as i connected a 2x16char screen to my Arduino. If you want I can post my changes, they are :

        - added a boolean that is false when the pulse was rejected by the int0handler or true when the boolean was accepted, basically indicating the reception (more or less)
        - indicating if a first buffer was finalized and return what the current buffer position is. this way i can display ‘Time in xx seconds’

      • Hi Thijs,

        Beste wensen too!! Thanks for this, this is very helpful!
        Meanwhile I have been looking into your library and decided to make some changes for my own benefit, basically for the user interface experience as i connected a 2x16char screen to my Arduino. If you want I can post my changes, they are :

        - added a boolean that is false when the pulse was rejected by the int0handler or true when the boolean was accepted, basically indicating the reception (more or less)
        - indicating if a first buffer was finalized and return what the current buffer position is. this way i can display ‘Time in xx seconds’

  12. Hi Thijs,
    Ik probeer de interne klok van mijn ‘Uno R3′ te synchen, maar geen resultaat. De ‘DCFSignal’ geeft een andere output dan ik op jouw screenshot zie.
    Aangesloten zoals jouw schema.
    Enig idee wat hier fout gaat?
    Groet,
    Casper
    0000000000000
    1100000000
    1000000000000000
    11111100000000
    10
    11111111100
    10
    1111111111000000000000
    111100
    1110000000
    1100
    100000000000
    111000000000
    1000
    1110
    111111111111111000
    10000000000000000000
    11111111111111111100000
    111000000000000000000000
    11111111111111000

    • He, het lijkt erop dat de antenne flink ver van de PC af moet liggen. En mijn USB signaal is niet al te best heb ik het idee. Hij werkt nu wel. Dank voor al je voorbereidend werk!
      Groet,
      casper

      • Hi Casper,

        Graag gedaan! De punten waar jij tegen aanloopt, RF interferentie, en ruis op de voeding, zijn bekende problemen. DCF77 is een lange golf signal met amplitude modulatie, en dat maakt hem gevoelig voor allerlei soorten ruis.

        Thijs

  13. Hoi Thijs ,

    ik heb zojuist de ontvanger van Conrad aan mijn Arduino Mega 2560 gehangen, maar de klok wordt niet op tijd gezet. Nou had ik deze aan pin 53 gehangen (omdat de pinnen ernaast gebruikt worden voor een lcdtje, dacht alles mooi bij elkaar te zetten) en natuurlijk heb ik het pin-nummer aangepast in de sketch. Maar toen ik ‘m toch maar aan 2 hing, wat eerst in de sketch stond, gebeurde er nog steeds niets. Ik krijg nog altijd output met de tijd die nog in het jaar 1970 zit. Enig idee waarom?

  14. Hi,

    thanks for the library, after some troubleshooting I found out that I needed to use interrupt 1 instead of 0 (#define DCF_INTERRUPT 1) on pin 2 to get it working with my arduino leonardo! The other examples without interrupt really helped me alot, because I knew at least the dcf signal was fine! :)

    greetz

    skunkjoe

  15. Hallo, ich habe eine Frage. Wenn ich Beispiele DCFsignal verwenden oder so DCFsyncprovider Arduino funktioniert, wenn ich mein Programm DCFsync Arbeit zu nutzen. Bitte haben Sie konsultiert. Danke

    /* Verze: 18.2.2013 Martin Pihrt

    SD ctecka pro LED panel…
    Posilaji se ASCI znaky na seriovou linku.
    Dale se posila prikaz na rolovani textu…

    Pripojeni SD karty:
    ** CLK/SCK – pin D13
    ** MISO – pin D12
    ** MOSI – pin D11
    ** CS – pin D10

    Pripojeni cidla DS18B20:
    ** pin #1 ds18b20 – gnd
    ** pin #2 ds18b20 – pin D9
    ** pin #3 ds18b20 – +5V
    ** rezistor 4K z +5V na pin D9

    Pripojeni DCF prijimace:
    ** data DCF out – pin D2
    */

    //knihovny
    #include “DCF77.h”
    #include “Time.h”
    #include
    #include
    File myFile;

    OneWire ds(9); // prirazeni cidla teploty k pinu D9
    int led = 14; // prirazeni LED DCF k pinu 14 tj A0
    int led2 = 15; // prirazeni LED SD k pinu 15 tj A1

    // DCF
    #define DCF_PIN 2 // prijimaci modul DCF 77 pripojen k pinu D2
    #define DCF_INTERRUPT 0 // preruseni asociovane s pinem

    time_t prevDisplay = 0;
    time_t time;
    DCF77 DCF = DCF77(DCF_PIN,DCF_INTERRUPT);

    //prenosova rychlost serial portu
    #define BAUD_RATE 115200

    //pocet segmentu – zde zadat pocet panelu tj. delku textu znaku
    #define SEGMENT 3

    // pocet sloupcu tj zobrazovanych znaku
    #define pSloupcu (SEGMENT * 4)

    unsigned int znak = 0;
    int ctiSd;

    //teplota
    byte i;
    byte present = 0;
    byte type_s;
    byte data[12];
    byte addr[8];
    float celsius;

    ///////////////////// nastaveni ////////////////
    void setup()
    {
    Serial.begin(BAUD_RATE);
    delay(500); // pockame na desku LED po resetu
    Serial.print(“C”); //vymaz bufer led panelu
    delay(50);

    DCF.Start();
    //setTime(12,00,00,18,2,2013); //setTime(hr,min,sec,day,month,yr);
    setSyncInterval(30); // Set the number of
    // seconds between re-sync
    setSyncProvider(getDCFTime); // Set the external time
    // provider

    pinMode(10, OUTPUT); // SD karta pin CS vystup
    pinMode(led, OUTPUT); // kontrolni LED DCF synchronizace OK vystup
    digitalWrite(led, LOW);
    pinMode(led2, OUTPUT); // kontrolni LED cteni z SD OK vystup
    digitalWrite(led2, LOW);

    // vypis reklamy na panelu a info verze sw

    // Serial.print(“\”INFO V”);
    // Serial.write(0xdd); //cz znak y
    // Serial.print(“PIS: \”");
    // delay(1000);
    // Serial.print(“11A”); //odsun vlevo
    // delay(3000);
    // Serial.print(“T”); //zobraz text info
    // delay(30000);
    // Serial.print(“21A”); //odsun vpravo
    // delay(3000);

    // kontrola SD karty
    Serial.print(“\”KONTROLA SD:\”");
    delay(1000);
    Serial.print(“11A”); //odsun vlevo
    delay(3000);

    if (!SD.begin(10))
    {
    Serial.print(“\”CHYBA-KARTA!\”");
    delay(2000);
    Serial.print(“21A”); //odsun vpravo
    delay(3000);
    return;
    } else {
    digitalWrite(led2, HIGH);
    Serial.print(“\”KARTA je OK \”");
    }
    delay(1000);
    digitalWrite(led2, LOW);
    Serial.print(“21A”); //odsun vpravo
    delay(3000);
    // SD overeni souboru led.txt
    Serial.print(“\”KONTROLA \”");
    delay(1500);
    Serial.print(“\”DAT na SD…\”");
    delay(1000);
    Serial.print(“11A”); //odsun vlevo
    delay(3000);
    if (SD.exists(“LED.TXT”)) {
    digitalWrite(led2, HIGH);
    Serial.print(“\”SOUBOR je OK\”");
    }
    else {
    Serial.print(“\”NA KAR”);
    Serial.write(0x8d); //cz znak T
    Serial.print(“E \”");
    delay(1500);
    Serial.print(“\”NEN”);
    Serial.write(0xe5); //cz znak I
    Serial.print(” SOUBOR:\”");
    delay(1500);
    Serial.print(“\”LED.txt! \”");
    }
    delay(1000);
    digitalWrite(led2, LOW);
    Serial.print(“21A”); //odsun vpravo
    delay(3000);
    //SD soubor otevreni
    myFile = SD.open(“LED.TXT”);
    if (myFile) {
    Serial.print(“\”");
    Serial.print(“START \”");
    delay(1000);
    digitalWrite(led2, HIGH);
    Serial.print(“21A”); //odsun vpravo
    delay(3000);
    digitalWrite(led2, LOW);
    Serial.print(“C”);
    } else {
    Serial.print(“\”CHYBA “);
    Serial.write(0xc8); //cz znak C
    Serial.print(“TEN”);
    Serial.write(0xe5); //cz znak I
    Serial.print(” \”");
    delay(1500);
    Serial.print(“\”ZE SOUBORU \”");
    delay(3000);
    Serial.print(“21A”); //odsun vpravo
    delay(3000);
    } //konec else

    } //konec setup

    void loop() /////////////// hlavni smycka //////////////////
    {

    tiskzSD();
    tiskteploty();

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

    } /////////////// konec hlavni smycka //////////////////

    //*********************************************************
    unsigned long getDCFTime()
    {
    time_t DCFtime = DCF.getTime();
    // Indicator that a time check is done
    if (DCFtime!=0) {

    digitalWrite(led, HIGH);
    delay(100);
    digitalWrite(led, LOW);
    }
    return DCFtime;
    }

    //*********************************************************
    void tiskzSD()
    {
    myFile = SD.open(“led.txt”); // otevreme soubor na SD karte
    if (myFile)
    {
    ctiData();
    delay(10);
    } // konec if

    myFile.close(); // uzavereme soubor led.txt – konec prace s SD
    }

    //******************************************
    void ctiData()
    {

    while (myFile.available())
    {
    digitalWrite(led2, HIGH);

    for (int i=0; i < (pSloupcu + 2); i++) // pr: 12 znaku + 2 uvozovky = 14 znaku
    {
    ctiSd=(myFile.read());

    if (ctiSd == '"')
    {
    znak = 0;
    delay(10);
    }

    Serial.write(ctiSd); // zapiseme na vystup data z karty

    if (znak == pSloupcu)
    {
    delay (2000); // cekáme na dalsi cteni radku z SD karty
    znak = 0;
    digitalWrite(led2, LOW);

    }

    znak++; // pocitadlo znaku

    } // konec for
    } // konec while
    } // konec void

    //*********************************************************
    void digitalClockDisplay() //// vypis casu /////
    {
    Serial.print("\"P");
    Serial.write(0xd8); //cz znak R 216
    Serial.print("ESN");
    Serial.write(0xdd); //cz znak Y 221
    Serial.print(" ");
    Serial.write(0xc8); //cz znak C 200
    Serial.print("AS: \"");
    delay(500);
    Serial.print("21A"); //odsun vpravo
    delay(3000);

    Serial.print("\"");
    Serial.print(hour());
    printDigits(minute());
    printDigits(second());
    delay(3000);
    Serial.print("\"");

    Serial.print("C"); //smazat led panel
    delay(50);
    Serial.print("\"DATUM: \"");
    delay(500);
    Serial.print("21A"); //odsun vpravo
    delay(3000);
    Serial.print("C"); //smazat led panel
    delay(50);

    Serial.print("\"");
    Serial.print(" ");
    Serial.print(day());
    Serial.print(".");
    Serial.print(month());
    Serial.print(".");
    Serial.print(year());
    Serial.print("\"");
    delay(3000);

    }

    //*********************************************************
    void printDigits(int digits) // pomocna funkce na zobrazeni nul pred casem
    {
    Serial.print(":");
    if(digits < 10)
    Serial.print('0');
    Serial.print(digits);
    }

    //*********************************************************
    void temp() //zpracovani teploty z cidla dallas
    {

    if ( !ds.search(addr)) {
    ds.reset_search();
    delay(250);
    return;
    }

    if (OneWire::crc8(addr, 7) != addr[7]) {
    return;
    }

    switch (addr[0]) {
    case 0×10:
    type_s = 1;
    break;
    case 0×28:
    type_s = 0;
    break;
    case 0×22:
    type_s = 0;
    break;
    default:
    return;
    }

    ds.reset();
    ds.select(addr);
    ds.write(0×44,1); // start conversion, with parasite power on at the end

    delay(1000); // maybe 750ms is enough, maybe not
    // we might do a ds.depower() here, but the reset will take care of it.

    present = ds.reset();
    ds.select(addr);
    ds.write(0xBE); // Read Scratchpad

    for ( i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();

    }

    // convert the data to actual temperature

    unsigned int raw = (data[1] << 8) | data[0];
    if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0×10) {
    // count remain gives full 12 bit resolution
    raw = (raw & 0xFFF0) + 12 – data[6];
    }
    } else {
    byte cfg = (data[4] & 0×60);
    if (cfg == 0×00) raw = raw << 3; // 9 bit resolution, 93.75 ms
    else if (cfg == 0×20) raw = raw << 2; // 10 bit res, 187.5 ms
    else if (cfg == 0×40) raw = raw << 1; // 11 bit res, 375 ms
    // default is 12 bit resolution, 750 ms conversion time
    }
    celsius = (float)raw / 16.0;

    }

    //*********************************************************
    void tiskteploty() //// vypis teploty /////
    {
    Serial.print("\"TEPLOTA: \"");
    delay(500);
    Serial.print("21A"); //odsun vpravo
    delay(3000);
    Serial.print("\"");
    temp(); // zpracuj teplotu
    Serial.print(celsius);
    Serial.write(0xb0); //znak ° stupnu asci 0176
    Serial.print("C");
    Serial.print("\"");
    delay(3000);
    }

    • Hi,

      I have trouble understanding your question, but I assume it is “The sample application is working, but the same code is not working in my own program. What could be the problem?”

      I would investigate the following:

      - Make use that none of your other libraries are using interrupt 0.
      - It could be that the blinking of your led (or writing to the SD card) influences the source going to the DCF receiver. This can mess with the signal. Try turning off these and see if a time is received

      Good luck,

      Thijs

  16. Hi,

    great work thanks a lot.

    Just a question is your library also exporting the weekday?
    I didn’t find any information about it?

    Cheers Robert

  17. Beste Thijs,

    Bedankt voor de artikel serie. Ben zeer onder de indruk. Heb een tijd geleden geprobeerd om dezelfde ontvanger aan de praat te krijgen.
    Nu met de hulpprogramma’s kan ik wat zien.
    Sinds kort ook een RIGO scoop.
    Deze aan pin 13 gehangen nu zie ik en de resultaten van de arduino op het scherm en ook op de scoop.

    Mijn vraag is; heb je enig idee hoelang de verbinding tussen de arduino en de ontvanger mag zijn?

    Met vriendelijke groet,

    Jan Kromhout
    Hellevoetsluis

    • Hoi Jan,

      Bedankt voor het compliment! Ik heb niet gekeken naar de afstand tussen de Arduino en ontvanger. De beste manier om er achter te komen, is door het te proberen. Als het niet lukt zou ik een Arduino redelijk dicht bij de ontvanger zetten en deze laten communiceren met een Arduino verder weg. Dat kan via ethernet, wifi, bluetooth, zigbee of serieel.

      Succes! Thijs

  18. Hoi Thijs,

    ik kreeg de library met DCFBinaryStream en VERBOSE_DEBUG aan, eerst niet aan de praat op een Arduino Pro Mini. Terwijl ik met DCFSignal en DCFPulseLength wel goeie output kreeg.

    Totdat ik de interrupt handler zoals hieronder aangegeven aanpaste. (De debug logging en returns eruit gehaald). heb verder niet uitgezocht hoe dat precies komt, maar is wel reproduceerbaar. (Mogelijk verpesten de returns of de debug logging de stack op een of andere manier).

    Iigv bedankt voor de mooie library.

    – mijn aanpassing/workaround in int0handler –

    void DCF77::int0handler() {
    int flankTime = millis();
    byte sensorValue = digitalRead(dCF77Pin);

    // Added by BJMD 01062013
    /**/ boolean validpulse = true;

    // If flank is detected quickly after previous flank up
    // this will be an incorrect pulse that we shall reject
    if ((flankTime-PreviousLeadingEdge)<DCFRejectionTime) {
    // Removed by BJMD 01062013
    // org LogLn("rCT");
    // org return;
    // Added by BJMD 01062013
    /**/ validpulse = false;
    }

    // If the detected pulse is too short it will be an
    // incorrect pulse that we shall reject as well
    if ((flankTime-leadingEdge) DCFSyncTime) {
    finalizeBuffer();
    }
    PreviousLeadingEdge = leadingEdge;
    // Distinguish between long and short pulses
    if (difference < DCFSplitTime) { appendSignal(0); } else { appendSignal(1); }
    Up = false;
    }
    }
    // added by BJMD 01062013
    /**/ } // validpulse
    }

  19. Pingback: Magic Smoke » PongClock 1.5 – DCF77 Funkuhr

  20. Hoi Thijs,

    Allereerst bedankt voor de ontwikkeling van de DCF77 Library! Ik ondervind echter een probleem. Als ik de DCF aansluit op pin 2 van de arduino uno dan werkt alles perfect, sluit ik hem echter aan op een andere pin (uiteraard met de aanpassing in de sketch naar diezelfde pin) dan wordt de tijd niet gesynced. Wat op zich vreemd is daar ik in de code niets gehardcoded zie naar die bewuste pin 2. Helaas kan ik de DCF niet op pin 2 laten omdat het seeedstudio tft scherm deze reeds in gebruik geeft. Enige idee wat de oorzaak kan zijn?

  21. Hi,
    i’m just trying to use this library with my Arduino Leonardo.
    The compiling and uploading works, even pin 13 is blinking in the second rythm. But i can’t get any time from the examples.
    I made some screenshots from the serial output from some example sketches.
    http://imgur.com/a/rSF9N

  22. Hallo Thijs,

    ben net begonnen met de arduino en zag je project dus nagebouwd en het werkte in een keer. Nu vraag ik me nog af hoe de dag en maand er uit te krijgen zijn. Ik ben totaal geen programmeur dus dat is lastiger………. Heb jij misschien een hint of voorbeeld?

    Groetjes
    Hans

    • Hoi Hans,

      Ja hoor, ik heb wel een hint. Bij de DCF77 library is ook de Time library toegevoegd. Deze geeft je allemaal functies om time_t om te zetten, bv naar dag en maand. Zie http://playground.arduino.cc/Code/time.

      Succes!

  23. Hallo Thijs,

    Ik ben erg onder de indruk van het (denk)werk wat in je DCF77 library is gegaan! Ik ben met 49 jaar net begonnen met de Arduino en er gaat een wereld voor me open.

    Omdat ik compleet verzot ben op DCF klokken, al vanaf het begin, is je library een geweldig cadeau!

    (mijn vraag staat onderaan, eerst wat uitleg… ;) )

    Ik ben bezig met een hele speciale DCF klok. Ik wil namelijk 2 rijen van 59 LED’s onder elkaar plaatsen met daarboven een normaal 7seg display met tijd/datum en temp.

    De eerste rij LED’s maakt de binnenkomende DCF pulsen zichtbaar (0=uit/1=aan) en als er een 100% volledig minuut signaal is ontvangen, dan wordt de bovenste rij ‘opgeschoven naar de onderste en begin alles weer van voor af aan.

    Je kunt dus de onderste rij LED’s de huidige tijd zien in gecodeerde vorm en de DCF pulsen die binnenkomen op de bovenste rij (leuk om te zien!)

    Daarnaast heb ik vanuit je dcf77.cpp library de fout meldingen ‘omgezet’ in LED output.
    Als er foute signalen binnenkomen zie je de betreffende LED oplichten en er gaat een ‘ERROR’ led branden ten teken dat de binnenkomende pulsen niet de juiste tijd aangeven. de onderste rij van 60 LED’s dooft dan ook.

    Als het signaal weer ‘ok’ is, er zijn dan 2 minuten lang juiste pulsen ontvangen, gaat er een groene LED branden en wordt de puls info weer weergeven op de 2 rijen van 59 LED’s.

    Overigens heb ik een antenne en dcf print gekocht bij http://www.hkw-elektronik.de
    GEWELDIG! De Conrad ontvanger viel helemaal dood als ik mijn Chinese maxim7219 chips activeerde (ik ga nu originele chips kopen) maar de HWK ontvanger werkt onvoorstelbaar veel beter. (voor maar 18 euro notabene)

    Maar nu loop ik tegen mijn zeer beperkte kennis van programmeren aan. Ben nog maar pas begonnen met c++

    Ik ben er zelfs niet in geslaagd je mooie dcf77 library te ontcijferen wat betref de ‘flow’, de volgorde. Ik begrijp niet helemaal hoe eea gekoppeld is etc. Maar ik leer nog.

    Wat ik beschreef, heb ik nu ondergebracht in de dcf77.cpp file omdat ik niet weet hoe dat anders zou moeten. het weergeven van de actuele tijd op het 7seg display lukt wel alleen klopt de sec. weergave niet. ook loopt de boel na een tijdje vast.

    Ik heb geprobeerd de dcf77.cpp file om te zetten naar de ‘normale’ library maar dat ging hopeloos mis omdat ik niet weet waar ik op moet letten.
    Ik zie nu de bomen door het c++ bos niet meer en ws. wil ik teveel als beginner… :(

    Ik vraag geen kant en klare oplossing maar hoe zou ik de 7 zeg displays moeten aansturen? Doe ik dat net als de 2 matrixen van 59 led’s ook vanuit de dcf77.cpp file?

    De ultieme klok zou een RTC hebben die elke minuut met DCF wordt vergeleken.

    Kan je me svp richting geven of een (hoop ik niet te ingewikkeld) c++ boek aanbevelen?
    Heb me suf gezocht naar meer info over libraries maar zoals gezegd raak ik verdwaald.

    Mocht je tijd hebben, bedankt!!

    Erik de Ruiter

    • Dag Erik,

      Welkom in de Arduino wereld! en wat leuk dat mijn library goed bevalt :-) Het is inderdaad zo dat de DCF77 bibliotheek wat lastig te begrijpen is. Dat komt in essentie omdat hij interrupt gestuurd is. Er zijn daardoor 2 flows in de applicatie:
      De eerste wordt getriggered door een interrupt op een flank verandering van het DCF signaal. De aangeroepen code probeert enkel te bepalen of er een puls binnengekomen is van 100, 200, of meer dan 1000 ms. De eerste 2 worden opgeslagen als een 0 of 1 in het data buffer, de laatste betekend dat de minuut afgelopen is. De tweede flow wordt aangeroepen door hoofd applicatie als je de tijd opvraagt. Het buffer wordt dan geïnterpreteerd met een data structuur die datum, tijd en een serie checks oplevert. De interrupts resulteren in de noodzaak om statische functies te gebruiken, de dubbele flow zorg ervoor dat we volatile variabelen nodig hebben.

      De interrupt gedreven implementatie is handig omdat er enkel op een flank verandering een klein stukje code uitgevoerd hoeft te worden, en het hoofdprogramma de rest van de tijd de processor tot zijn beschikking heeft. In jouw applicatie is het uitlezen van de atoomklok de hoofdzaak, dus kan je een implementatie maken zonder interrupt. De sample die de 1 en 0 teruggeeft is daarvoor een goed begin.

      Als ik je een tip mag geven: gezien je redelijk nieuw bent met c++ zou ik je project opbreken in kleinere stukken, en van simpel naar moeilijk werken: Ik zou eerst kijken of je de 1 en 0 kan afbeelden op een led matrix, en pas daarna gaan proberen om de tijd uit te lezen. Als je zover bent wil ik wel mee kijken. Wat betreft het aansturen van de leds kom je in een ander leuk Arduino gebied terecht. Verreweg de simpelste manier om een dergelijke hoeveelheid leds aan te sturen, is door een programmeerbare ledstrip te gebruiken: .

      Wat betreft een goed c++ boek, ik heb mijn eerste stappen gezet rond 1980 aan de hand Ammeraal: http://www.bol.com/nl/p/basiscursus-c/666842990/ . Het is echt heel basis, dus prima om mee te starten. Het zal je misschien niet DCF77 compleet laten begrijpen, maar wel een heel stuk helpen.

      Ik hoop dat je hier wat mee kan en heel veel succes!

      Thijs

  24. Hallo Thijs,

    Bedankt voor je tips!

    Ik heb de 2 rijen van 59 LED’s werkend. erg leuk om te zien.

    Op de eerste rij LED’s zijn dus de binnenkomende pulsen zichtbaar en als er een volledige minuut is binnengekomen, wordt het ‘display’ van de eerste rij gekopieerd naar de 2e rij LED’s en begint alles opnieuw.
    Op twee 7-segment displays is de tijd te zien en de temperatuur.
    Op een bepaald momenten elke minuut wordt kort de datum weergegeven
    Fouten in de ontvangst heb ik zichtbaar gemaakt op een aantal andere LED’s

    Ik afwachting van je antwoord had ik inmiddels een boek gevonden en doorgelezen: “Beginning C for Arduino van Jack Purdum”. Fantastisch boek!

    Nu nog een RTC integreren voor het geval het DCF signaal niet zichtbaar is en later een ontvanger om een draadloze thermometer uit te lezen.

    De RTC en de werking van de Syncprovider is nog lastig te begrijpen. Ik wil de onderliggende principes begrijpen en daar loop ik vast nog. Onvoorstelbaar weinig info hierover te vinden op het web!? Ben toch aardig ervaren in het zoeken naar info maar helaas. Enfin, door vallen en opstaan komen we er wel.

    Als ik vastloop maak ik graag gebruik van je aanbod even mee te kijken, bedankt!

    Groeten!
    Erik

  25. I absolutely love your blog.. Great colors &
    theme. Did you build this web site yourself?
    Please reply back as I’m trying to create my own website and would love to know
    where you got this from or just what the theme is named.
    Kudos!

  26. Hallo Thijs!

    Ik ben erin geslaagd je dcf77 library weer om te zetten naar 1 sketch zodat ik de flow beter kan volgen en code kan invoegen tbv matrix display’s en led’s.
    Voor een beginner als mij is dat duidelijker… ;)

    Alles werkt mits ik onderstaande regel code uit de Int0 functie sloop.

    pulseStart = OnRisingFlank ? HIGH : LOW;

    Wat gebeurt hier? Ik kan nergens vinden wat ‘? en ‘:’ betekent.

    Alvast bedankt!

  27. Pingback: DCF77 | SNODES

    • Thanks for referring to my library. I have not investigated it, but my first guess would be that the attiny85 has other pins on which interrupts can be triggered. An interrupt is used to only call the the library when a new pulse is coming in.

  28. Dear Thijs,
    many thanks for your excellent DCF77 library, all is working very well by my arduino UNO.
    But I have one question:
    What I have to do, when I want to activate a alarm or activate a output in my arduino sketch ( switch on or switch off) at different time?

    Many thanks for your answer in advance.

    Franz

  29. Dear Thijs,

    great work.

    After playing around with the library and various DCF receivers I have a suggestion to help out all the people who didnt get a signal and moving around antennas like me ;)

    I used sometime the Utils.h logs to get the info of the signal streaming in but it somewhat chrashes my sketches if that runs too long….cant explain it yet.

    As a help/workaround for quality/receiving signal I have defined a boolean variable called receiveDCF in your library.
    It gets its information from the various int0handler methods like this:

    if ((flankTime-leadingEdge)<DCFRejectPulseWidth) {
    DCF77::receiveDCF=false;
    LogLn("rPW");
    return;

    Here the definition:

    public:
    // Public Functions
    DCF77(int DCF77Pin, int DCFinterrupt, bool OnRisingFlank=true);

    static time_t getTime(void);
    static time_t getUTCTime(void);
    static void Start(void);
    static void Stop(void);
    static void int0handler();

    static bool receiveDCF;

    What do you say ?

    Best regards

    Marcus

    • I believe the crash has something to do with the interrupt function interfering with the Serial interrupt, or possibly the interrupt function taking too much time in logging, and being called again while processing. Thanks for your suggestion! What are trying to get done,exactly? Also, when receiveDCF is set to false, is it never set to true again?

      • Hi Thijs,

        I call DCF77::receiveDCF in my main display routines and visualize the result.
        As its slow changing you can see if you receive a signal or not every second or so. Like that:

        if(DCF.receiveDCF) lcd.print(“DCF77 “);
        else lcd.print(“No DCF”);

        Even better would be some calculations on #of rejected signals/pulsewidth
        in an arry for example to measure the quality of the signal more precise as signal/no signal. Maybe you have an idea.

        Here the logic of receiveDCF …very simple:

        false if rCT or rPW…like your logs.
        true if appendSignal method is used…

        intitalized as:
        bool DCF77::receiveDCF=false;

        if ((flankTime-PreviousLeadingEdge)<DCFRejectionTime) {
        DCF77::receiveDCF=false;
        LogLn("rCT");
        return;
        }

        // If the detected pulse is too short it will be an
        // incorrect pulse that we shall reject as well
        if ((flankTime-leadingEdge)<DCFRejectPulseWidth) {
        DCF77::receiveDCF=false;
        LogLn("rPW");
        return;
        }

        inline void DCF77::appendSignal(unsigned char signal) {
        Log(signal, DEC);
        DCF77::receiveDCF=true;
        runningBuffer = runningBuffer | ((unsigned long long) signal < 59) {
        // Buffer is full before at end of time-sequence
        // this may be due to noise giving additional peaks
        LogLn(“EoB”);
        finalizeBuffer();
        }
        }

Leave a Reply

Required fields are marked *.