Problems with using DCF77 library made by Udo Klein

I've been using DCF77 xtal library made by Udo Klein but I'm little confused. I've been reading Simple_Clock sketch and i can't understand it completely. Are there any simple functions to get time? What does paddedPrint do more specially than Serial.print function? What does n.digit.hi and n.digit.lo mean inside that function? Do we always have to use :: when calling some function?

Also I noticed when serial monitor is closed, arduino stops decoding time. Also when i don't write Serial.begin() because i want to display time on LCD, DCF77 library doesn't work.

You are asking questions about code we can not see. Post your code and a link to the library.

mihajlo2003:
I've been using DCF77 xtal library made by Udo Klein but I'm little confused. I've been reading Simple_Clock sketch and i can't understand it completely. Are there any simple functions to get time? What does paddedPrint do more specially than Serial.print function? What does n.digit.hi and n.digit.lo mean inside that function? Do we always have to use :: when calling some function?

Why don't you give some different code a try, then?

Here is something I made for DCF a while ago as a DCF test program for Arduino:

#define DCFPIN 8
#define INVERTEDSIGNAL false

#define PULSE_ERRORLIMIT 40  // 40 ms seems to be a suitable value
#define PULSE_SHORTSECOND (1000-PULSE_ERRORLIMIT)
#define PULSE_LONGSECOND  (1000+PULSE_ERRORLIMIT)
#define PULSE_MINUTEMARK  (2000-PULSE_ERRORLIMIT)

// 8 Bytes = 64 Bits to store all 59 DCF bits in a minute
uint8_t dcfBits[8];  
byte dcfBitcount;

boolean parityOK(byte startbit, byte paritybit)
{ // test parity bit in the range startbit ... paritybit-1
  byte p=0;
  for (int i=startbit; i<=paritybit;i++) p+= bitRead(dcfBits[i/8],i%8);
  if (p%2 == 0) return true; // even parity detected
  else return false;
}

byte dcfDecodeBCD(byte startbit, byte numbits)
{ // return BCD encoded byte-value beginning at startbit
  byte b=0;
  for (int i=startbit;i<startbit+numbits;i++) bitWrite(b,i-startbit, bitRead(dcfBits[i/8],i%8));
  return b;
}

boolean dcfDecodeTime()
{
  int hour, minute, day, month, year;
  byte resultCode, parityError=0;
  // print bits of time code to serial
  for (int i=0;i<dcfBitcount;i++) Serial.print(bitRead(dcfBits[i/8],i%8));
  Serial.print('\t');Serial.println(dcfBitcount);
  if(!parityOK(21,28)) bitSet(parityError,0); // parity error minute
  if(!parityOK(29,35)) bitSet(parityError,1); // parity error hour
  if(!parityOK(36,58)) bitSet(parityError,2); // parity error date
  hour   = 10*dcfDecodeBCD(33,2);  // tens of hours, 2 bit 
  hour  += dcfDecodeBCD(29,4);     // single hours, 4 bit 
  minute = 10*dcfDecodeBCD(25,3);  // tens of minutes, 3 bit
  minute += dcfDecodeBCD(21,4);    // single minutes, 4 bit

  day = 10*dcfDecodeBCD(40,2);     // day of month (tens), 2 bit
  day += dcfDecodeBCD(36,4);       // day of month (single), 4 bit
  month = 10*dcfDecodeBCD(49,1);   // tens of month, 1 bit
  month += dcfDecodeBCD(45,4);     // single digit of month, 4 bit
  year = 10*dcfDecodeBCD(54,4);    // tens of year, 4 bit
  year += dcfDecodeBCD(50,4);      // single digit of year, 4 bit
  if (dcfBitcount!=59)
  {
    Serial.println("Error: Time code must contain 59 bits!");
  }
  else if (parityError)
  {
    Serial.println("Error: Wrong parity bit detected!");
  }
  else
  {
    Serial.print(hour);Serial.print(':');
    Serial.print(minute);Serial.print(":00  ");
    Serial.print(day);Serial.print('/');
    Serial.print(month);Serial.print('/');
    Serial.println(year);
    dcfBitcount=0;
    return true;
  }
  dcfBitcount=0;
  return false;
}


boolean dcfHandleBit(uint16_t hiTime, uint16_t pulseTime)
{
  if (dcfBitcount<60)
  {
    if (hiTime<150) bitClear(dcfBits[dcfBitcount/8],dcfBitcount%8);
    else  bitSet(dcfBits[dcfBitcount/8],dcfBitcount%8);
    dcfBitcount++;  
  }
  if (pulseTime>=PULSE_MINUTEMARK) return dcfDecodeTime();
  return false;
}

boolean dcfUpdate()
{
  static boolean lastState;
  static unsigned long lastChangeTime;
  static uint16_t hiMillis,loMillis;
  static byte cnt;
  boolean state= digitalRead(DCFPIN);
  if (INVERTEDSIGNAL) state=!state;
  if (state!=lastState)
  {
    long timeDiff=millis()-lastChangeTime;
    lastState=state;
    lastChangeTime+= timeDiff;
    if (state)
    {
      cnt++;
      loMillis+= timeDiff;
      uint16_t pulsetime=hiMillis+loMillis;
      if ((pulsetime>=PULSE_SHORTSECOND && pulsetime<=PULSE_LONGSECOND)|| pulsetime>=PULSE_MINUTEMARK) 
      {
        Serial.print(cnt);Serial.print('\t');
        Serial.print(hiMillis);Serial.print('\t');
        Serial.print(loMillis);Serial.print('\t');
        Serial.print(pulsetime);Serial.print('\t');
        Serial.println();
        boolean result=dcfHandleBit(hiMillis, pulsetime);
        hiMillis=0;
        loMillis=0;
        cnt=0;
        return result;
      }
    }
    else hiMillis+= timeDiff;
  }
  return false;
}




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

void loop() {
  if (dcfUpdate()) Serial.println("SUCCESS!");
}

No library used. There is just one function "dcfUpdate() which does all the job of reading the DCF module, collecting bits and decoding time telegrams accordingly the DCF standard.

Can you make it work?

Here's my code. It's based on simple clock example from library. Library used: GitHub - udoklein/dcf77: Noise resilient DCF77 decoder library for Arduino

#include <dcf77.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

int years;
byte months;
byte days;

byte hours;
byte minutes;
byte seconds;


#if defined(__AVR__)
const uint8_t dcf77_analog_sample_pin = 5;
const uint8_t dcf77_sample_pin = A5;       // A5 == d19
const uint8_t dcf77_inverted_samples = 0;
const uint8_t dcf77_analog_samples = 1;
const uint8_t dcf77_pin_mode = INPUT;  // disable internal pull up
//const uint8_t dcf77_pin_mode = INPUT_PULLUP;  // enable internal pull up

#else
const uint8_t dcf77_sample_pin = 53;
const uint8_t dcf77_inverted_samples = 0;

const uint8_t dcf77_pin_mode = INPUT;  // disable internal pull up
//const uint8_t dcf77_pin_mode = INPUT_PULLUP;  // enable internal pull up
#endif

uint8_t sample_input_pin() {
  const uint8_t sampled_data =
#if defined(__AVR__)
    dcf77_inverted_samples ^ (dcf77_analog_samples ? (analogRead(dcf77_analog_sample_pin) > 200) : digitalRead(dcf77_sample_pin));
#else
    dcf77_inverted_samples ^ digitalRead(dcf77_sample_pin);
#endif
  return sampled_data;
}


Adafruit_PCD8544 lcd = Adafruit_PCD8544(13, 12, 11, 10, 9);

void setup() {
  lcd.begin();
  lcd.setContrast(50);
  lcd.clearDisplay();

  using namespace Clock;

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

void loop() {
  Clock::time_t now;

  DCF77_Clock::get_current_time(now);

  hours = BCD::bcd_to_int(now.hour);
  minutes = BCD::bcd_to_int(now.minute);
  seconds = BCD::bcd_to_int(now.second);

  days = BCD::bcd_to_int(now.day);
  months = BCD::bcd_to_int(now.month);
  years = BCD::bcd_to_int(now.year) + 2000;

  lcd.print(days);
  lcd.print('/');
  lcd.print(months);
  lcd.print('/');
  lcd.println(years);

  lcd.print(hours);
  lcd.print(':');
  lcd.print(minutes);
  lcd.print(':');
  lcd.println(seconds);

  lcd.print("+0");
  lcd.println(now.uses_summertime ? '2' : '1');

  switch (DCF77_Clock::get_clock_state()) {

    case Clock::useless:
      lcd.println("Useless");
      break;

    case Clock::dirty:
      lcd.println("Dirty");
      break;

    case Clock::synced:
      lcd.println("Synced");
      break;

    case Clock::locked:
      lcd.println("Locked");
      break;
  }

  lcd.display();
  lcd.clearDisplay();
}

jurs:
Why don't you give some different code a try, then?

Here is something I made for DCF a while ago as a DCF test program for Arduino:

#define DCFPIN 8

#define INVERTEDSIGNAL false

#define PULSE_ERRORLIMIT 40  // 40 ms seems to be a suitable value
#define PULSE_SHORTSECOND (1000-PULSE_ERRORLIMIT)
#define PULSE_LONGSECOND  (1000+PULSE_ERRORLIMIT)
#define PULSE_MINUTEMARK  (2000-PULSE_ERRORLIMIT)

// 8 Bytes = 64 Bits to store all 59 DCF bits in a minute
uint8_t dcfBits[8]; 
byte dcfBitcount;

boolean parityOK(byte startbit, byte paritybit)
{ // test parity bit in the range startbit ... paritybit-1
  byte p=0;
  for (int i=startbit; i<=paritybit;i++) p+= bitRead(dcfBits[i/8],i%8);
  if (p%2 == 0) return true; // even parity detected
  else return false;
}

byte dcfDecodeBCD(byte startbit, byte numbits)
{ // return BCD encoded byte-value beginning at startbit
  byte b=0;
  for (int i=startbit;i<startbit+numbits;i++) bitWrite(b,i-startbit, bitRead(dcfBits[i/8],i%8));
  return b;
}

boolean dcfDecodeTime()
{
  int hour, minute, day, month, year;
  byte resultCode, parityError=0;
  // print bits of time code to serial
  for (int i=0;i<dcfBitcount;i++) Serial.print(bitRead(dcfBits[i/8],i%8));
  Serial.print('\t');Serial.println(dcfBitcount);
  if(!parityOK(21,28)) bitSet(parityError,0); // parity error minute
  if(!parityOK(29,35)) bitSet(parityError,1); // parity error hour
  if(!parityOK(36,58)) bitSet(parityError,2); // parity error date
  hour  = 10dcfDecodeBCD(33,2);  // tens of hours, 2 bit
  hour  += dcfDecodeBCD(29,4);    // single hours, 4 bit
  minute = 10
dcfDecodeBCD(25,3);  // tens of minutes, 3 bit
  minute += dcfDecodeBCD(21,4);    // single minutes, 4 bit

day = 10dcfDecodeBCD(40,2);    // day of month (tens), 2 bit
  day += dcfDecodeBCD(36,4);      // day of month (single), 4 bit
  month = 10
dcfDecodeBCD(49,1);  // tens of month, 1 bit
  month += dcfDecodeBCD(45,4);    // single digit of month, 4 bit
  year = 10*dcfDecodeBCD(54,4);    // tens of year, 4 bit
  year += dcfDecodeBCD(50,4);      // single digit of year, 4 bit
  if (dcfBitcount!=59)
  {
    Serial.println("Error: Time code must contain 59 bits!");
  }
  else if (parityError)
  {
    Serial.println("Error: Wrong parity bit detected!");
  }
  else
  {
    Serial.print(hour);Serial.print(':');
    Serial.print(minute);Serial.print(":00  ");
    Serial.print(day);Serial.print('/');
    Serial.print(month);Serial.print('/');
    Serial.println(year);
    dcfBitcount=0;
    return true;
  }
  dcfBitcount=0;
  return false;
}

boolean dcfHandleBit(uint16_t hiTime, uint16_t pulseTime)
{
  if (dcfBitcount<60)
  {
    if (hiTime<150) bitClear(dcfBits[dcfBitcount/8],dcfBitcount%8);
    else  bitSet(dcfBits[dcfBitcount/8],dcfBitcount%8);
    dcfBitcount++; 
  }
  if (pulseTime>=PULSE_MINUTEMARK) return dcfDecodeTime();
  return false;
}

boolean dcfUpdate()
{
  static boolean lastState;
  static unsigned long lastChangeTime;
  static uint16_t hiMillis,loMillis;
  static byte cnt;
  boolean state= digitalRead(DCFPIN);
  if (INVERTEDSIGNAL) state=!state;
  if (state!=lastState)
  {
    long timeDiff=millis()-lastChangeTime;
    lastState=state;
    lastChangeTime+= timeDiff;
    if (state)
    {
      cnt++;
      loMillis+= timeDiff;
      uint16_t pulsetime=hiMillis+loMillis;
      if ((pulsetime>=PULSE_SHORTSECOND && pulsetime<=PULSE_LONGSECOND)|| pulsetime>=PULSE_MINUTEMARK)
      {
        Serial.print(cnt);Serial.print('\t');
        Serial.print(hiMillis);Serial.print('\t');
        Serial.print(loMillis);Serial.print('\t');
        Serial.print(pulsetime);Serial.print('\t');
        Serial.println();
        boolean result=dcfHandleBit(hiMillis, pulsetime);
        hiMillis=0;
        loMillis=0;
        cnt=0;
        return result;
      }
    }
    else hiMillis+= timeDiff;
  }
  return false;
}

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

void loop() {
  if (dcfUpdate()) Serial.println("SUCCESS!");
}




No library used. There is just one function "dcfUpdate() which does all the job of reading the DCF module, collecting bits and decoding time telegrams accordingly the DCF standard.

Can you make it work?

I don't know why, but your code doesn't seem to work for me. Where I live, again I don't know why, but I can't receive time signal. Odd thing is, that I'm within DCF77 transmitter range and I live approximately 1250 km from it. Currently I'm emulating DCF77 transmitter with my computer soundcard and speaker as described in this tutorial: Bastian Born - Developer Dump

mihajlo2003:
Currently I'm emulating DCF77 transmitter with my computer soundcard and speaker as described in this tutorial: Bastian Born - Developer Dump

You are "emulating" the real DCF77 sender by using your PCs soundcard?
WEIRD!

If this does not work using your Arduino and DCF module (which one?): Does it work with a real DCF77 enabled clock?

It works with my module and with my clock. I don't know what module is because took it from some clock.

Here's the video made by the author of the website: DCF77 radio controlled clock changed with timegen - YouTube

I also have relatively short ferrite rod about 6 cm in length. Maybe that's why I'm unable to receive signal.

mihajlo2003:
Maybe that's why I'm unable to receive signal.

Sorry, but I don't understand anything.
In #7 you write about "It works with my module" and in #8 I read " I'm unable to receive signal".
I'm clueless about what might be working while you are unable to receive signal at the same time.

Bye

jurs:
Sorry, but I don't understand anything.
In #7 you write about "It works with my module" and in #8 I read " I'm unable to receive signal".
I'm clueless about what might be working while you are unable to receive signal at the same time.

Bye

I wanted to say I'm unable to receive signal from real DCF77 station but I'm able to receive signal from my computer when I emulate station. Hope you understand me now!

mihajlo2003:
I wanted to say I'm unable to receive signal from real DCF77 station but I'm able to receive signal from my computer when I emulate station. Hope you understand me now!

DCF77 signals become very much disturbed by electromagnetic interference in modern rooms with modern electric equipment.

Keep the DCF module at least two meters (6 feet or so) away from any:

-computers

  • computer monitors
  • TV
  • switching AC/DC power adapters / smartphone chargers
  • fluorescent lamps
    -fluorescent energy saving lamps

jurs:
DCF77 signals become very much disturbed by electromagnetic interference in modern rooms with modern electric equipment.

Keep the DCF module at least two meters (6 feet or so) away from any:

-computers

  • computer monitors
  • TV
  • switching AC/DC power adapters / smartphone chargers
  • fluorescent lamps
    -fluorescent energy saving lamps

I do all that.

  1. Ensure you are using the most up to date version of the library (available e.g. here: Releases · udoklein/dcf77 · GitHub). The most up to date version publicly available is v3.1.4.

  2. If you get weird behaviour it must be first understood if you face a hardware or a software issue. Please flash the Swiss_Army_Debug_Helper.ino into you arduino and collect 1 hour of debug information in mode "Dm" and attach it to your reply". This will allow me to analyze if the hardware or the software has an issue. As a general rule: if the debug helper fails to collect something your hardware is to blame.

  3. The padded print function just adds "padding". That is leading zeroes in order to make the output appear nicer. The n.digit.lo and n.digit.hi are due to the fact that I use "variant structs" in order to implement BCD conversion. The "." is used for component access. The use of variant structs is an optimization to save runtime as well as memory.

Thanks! I'll upload Swiss_Army_Debug_Helper