I got the clock (also got the one from Maplin as well) but found the MSF protocol was not as similar as I first thought. I would like to build a library to handle all three protocols (WWV, MSF and DCF) but its slow going due to pressure of work limiting my time.
I did not want to open a new thread. Yesterday I bought the DCF receiver at Conrad for like 10 Euro.
I wired everything together. Pin 1 to GND, Pin 2 to 5V and Pin 3 to the Arduino Pin 7 with a pull up resistor of 8,2 kOhm (did not have 8kOhm) as described in playground now.
If I run the program, the LCD shows some activity but the Serial dump is just alternating between 0:0:1 and 0:0:0 for time
Time: 0:0:1 Date: 0.0.0
Time: 0:0:0 Date: 0.0.0
Time: 0:0:1 Date: 0.0.0
Time: 0:0:0 Date: 0.0.0
Any ideas? I left it for half an hour and the only thing happened was that sometimes time went up to 0:0:4 but I don't get any reliable time?
Update: With the updates library it spits out a lot of debugging information.
Always saying Begin of a new minute every few seconds but seems to be appending someting and appending, so I will leave it along for some time.
can you post the code you are running
It's near Stuttgart (South-west-Germany), so shouldn't be that much of a problem.
/**
* Arduino DCF77 decoder v0.2
* Copyright (C) 2006 Mathias Dalheimer (md@gonium.net)
*
* 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 2 of the License, or
* 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <MsTimer2.h>
/**
* Where is the DCF receiver connected?
*/
#define DCF77PIN 2
/**
* Where is the LED connected?
*/
#define BLINKPIN 13
/**
* Turn debugging on or off
*/
#define DCF_DEBUG 1
/**
* Number of milliseconds to elapse before we assume a "1",
* if we receive a falling flank before - its a 0.
*/
#define DCF_split_millis 140
/**
* There is no signal in second 59 - detect the beginning of
* a new minute.
*/
#define DCF_sync_millis 1200
/**
* Definitions for the timer interrupt 2 handler:
* The Arduino runs at 16 Mhz, we use a prescaler of 64 -> We need to
* initialize the counter with 6. This way, we have 1000 interrupts per second.
* We use tick_counter to count the interrupts.
*/
#define INIT_TIMER_COUNT 6
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT
int tick_counter = 0;
/**
* DCF time format struct
*/
struct DCF77Buffer {
unsigned long long prefix :21;
unsigned long long Min :7; // minutes
unsigned long long P1 :1; // parity minutes
unsigned long long Hour :6; // hours
unsigned long long P2 :1; // parity hours
unsigned long long Day :6; // day
unsigned long long Weekday :3; // day of week
unsigned long long Month :5; // month
unsigned long long Year :8; // year (5 -> 2005)
unsigned long long P3 :1; // parity
};
struct {
unsigned char parity_flag :1;
unsigned char parity_min :1;
unsigned char parity_hour :1;
unsigned char parity_date :1;
} flags;
/**
* Clock variables
*/
volatile unsigned char DCFSignalState = 0;
unsigned char previousSignalState;
int previousFlankTime;
int bufferPosition;
unsigned long long dcf_rx_buffer;
/**
* time vars: the time is stored here!
*/
volatile unsigned char ss;
volatile unsigned char mm;
volatile unsigned char hh;
volatile unsigned char day;
volatile unsigned char mon;
volatile unsigned int year;
/**
* used in main loop: detect a new second...
*/
unsigned char previousSecond;
/**
* Initialize the DCF77 routines: initialize the variables,
* configure the interrupt behaviour.
*/
void DCF77Init() {
previousSignalState=0;
previousFlankTime=0;
bufferPosition=0;
dcf_rx_buffer=0;
ss=mm=hh=day=mon=year=0;
#ifdef DCF_DEBUG
Serial.println("Initializing DCF77 routines");
Serial.print("Using DCF77 pin #");
Serial.println(DCF77PIN);
#endif
pinMode(BLINKPIN, OUTPUT);
pinMode(DCF77PIN, INPUT);
#ifdef DCF_DEBUG
Serial.println("Initializing timerinterrupt");
#endif
MsTimer2::set(1000, advanceClock); // 500ms period
#ifdef DCF_DEBUG
Serial.println("Initializing DCF77 signal listener interrupt");
#endif
attachInterrupt(0, int0handler, CHANGE);
}
/**
* Append a signal to the dcf_rx_buffer. Argument can be 1 or 0. An internal
* counter shifts the writing position within the buffer. If position > 59,
* a new minute begins -> time to call finalizeBuffer().
*/
void appendSignal(unsigned char signal) {
#ifdef DCF_DEBUG
Serial.print(", appending value ");
Serial.print(signal, DEC);
Serial.print(" at position ");
Serial.println(bufferPosition);
#endif
dcf_rx_buffer = dcf_rx_buffer | ((unsigned long long) signal << bufferPosition);
// Update the parity bits. First: Reset when minute, hour or date starts.
if (bufferPosition == 21 || bufferPosition == 29 || bufferPosition == 36) {
flags.parity_flag = 0;
}
// save the parity when the corresponding segment ends
if (bufferPosition == 28) {flags.parity_min = flags.parity_flag;};
if (bufferPosition == 35) {flags.parity_hour = flags.parity_flag;};
if (bufferPosition == 58) {flags.parity_date = flags.parity_flag;};
// When we received a 1, toggle the parity flag
if (signal == 1) {
flags.parity_flag = flags.parity_flag ^ 1;
}
bufferPosition++;
if (bufferPosition > 59) {
finalizeBuffer();
}
}
/**
* Evaluates the information stored in the buffer. This is where the DCF77
* signal is decoded and the internal clock is updated.
*/
void finalizeBuffer(void) {
if (bufferPosition == 59) {
#ifdef DCF_DEBUG
Serial.println("Finalizing Buffer");
#endif
struct DCF77Buffer *rx_buffer;
rx_buffer = (struct DCF77Buffer *)(unsigned long long)&dcf_rx_buffer;
if (flags.parity_min == rx_buffer->P1 &&
flags.parity_hour == rx_buffer->P2 &&
flags.parity_date == rx_buffer->P3)
{
#ifdef DCF_DEBUG
Serial.println("Parity check OK - updating time.");
#endif
//convert the received bits from BCD
mm = rx_buffer->Min-((rx_buffer->Min/16)*6);
hh = rx_buffer->Hour-((rx_buffer->Hour/16)*6);
day= rx_buffer->Day-((rx_buffer->Day/16)*6);
mon= rx_buffer->Month-((rx_buffer->Month/16)*6);
year= 2000 + rx_buffer->Year-((rx_buffer->Year/16)*6);
}
#ifdef DCF_DEBUG
else {
Serial.println("Parity check NOK - running on internal clock.");
}
#endif
}
// reset stuff
ss = 0;
bufferPosition = 0;
dcf_rx_buffer=0;
}
/**
* Dump the time to the serial line.
*/
void serialDumpTime(void){
Serial.print("Time: ");
Serial.print(hh, DEC);
Serial.print(":");
Serial.print(mm, DEC);
Serial.print(":");
Serial.print(ss, DEC);
Serial.print(" Date: ");
Serial.print(day, DEC);
Serial.print(".");
Serial.print(mon, DEC);
Serial.print(".");
Serial.println(year, DEC);
}
/**
* Evaluates the signal as it is received. Decides whether we received
* a "1" or a "0" based on the
*/
void scanSignal(void){
if (DCFSignalState == 1) {
int thisFlankTime=millis();
if (thisFlankTime - previousFlankTime > DCF_sync_millis) {
#ifdef DCF_DEBUG
Serial.println("####");
Serial.println("#### Begin of new Minute!!!");
Serial.println("####");
#endif
finalizeBuffer();
}
previousFlankTime=thisFlankTime;
#ifdef DCF_DEBUG
Serial.print(previousFlankTime);
Serial.print(": DCF77 Signal detected, ");
#endif
}
else {
/* or a falling flank */
int difference=millis() - previousFlankTime;
#ifdef DCF_DEBUG
Serial.print("duration: ");
Serial.print(difference);
#endif
if (difference < DCF_split_millis) {
appendSignal(0);
}
else {
appendSignal(1);
}
}
}
/**
* The interrupt routine for counting seconds – increment hh:mm:ss.
*/
void advanceClock() {
ss++;
if (ss==60) {
ss=0;
mm++;
if (mm==60) {
mm=0;
hh++;
if (hh==24)
hh=0;
}
}
}
/**
* Interrupthandler for INT0 – called when the signal on Pin 2 changes.
*/
void int0handler() {
int length = millis() - previousFlankTime;
if (length < 10) {
// ignore jitter
return;
}
// check the value again – since it takes some time to
// activate the interrupt routine, we get a clear signal.
DCFSignalState = digitalRead(DCF77PIN);
}
/**
* Standard Arduino methods below.
*/
void setup(void) {
// We need to start serial here again,
// for Arduino 007 (new serial code)
Serial.begin(9600);
DCF77Init();
}
void loop(void) {
if (ss != previousSecond) {
serialDumpTime();
previousSecond = ss;
}
if (DCFSignalState != previousSignalState) {
scanSignal();
if (DCFSignalState) {
digitalWrite(BLINKPIN, HIGH);
} else {
digitalWrite(BLINKPIN, LOW);
}
previousSignalState = DCFSignalState;
}
//delay(20);
}
It's that example from gonium.net » Blog Archive » Arduino DCF77 v0.2 released (with some changes that someone in the comments made, using Mstimer2 instead)
Is there a way how to know whether it is just not working or I am out of range? Because atm I cannot go outside with my Arduino. I first have to wire together my lcd and box which requires me for the light to be attached as well. So I can at soonest by Saturday test it outside.
Why not try the code linked earlier in this thread?
Because it's a different receiver and the pin logic is totally different in the first post. I tried the DCF77 tutorial in playground as well which ecplicitly states it uses the DCF receiver of Conrad.
I never did get my Conrad receiver to work with this.
Did you manage it and how?
Has anyone got this working with a UK MSF signal yet?
I'm looking into building a fairly large LED clock that must be radio controlled. I wouldn't mind using an Arduino for that project but it does look complicated.
Oh, actually, never mind. I just found a far easier way of getting atomic time on the Arduino. Using a GPS module. ;D
It has a serial interface that just sends a string with UTC time and current coordinates. And a cheap one costs about the same as a MSF receiver.
I suspect GPS may not work very well indoors, unless you get a really sensitive receiver or use an external antenna.
I've just ordered an MSF module (£7 from PV Electronics, also sold on eBay by yashu75) :
They also do DCF and WWVB modules. And Sparkfun do a similar (not identical) module for WWVB, as well:
My plan is to extend/modify RadioTime to do MSF instead of DCF. MSF docs are here:
Mem - you said you had made a start on the MSF code - do you have any bits to share, or should I just start in ? Or, does anyone else have MSF code running ?
Ta!
Richard
I've got MSF code running happily now against one of those modules.
Details and code are here:
Hello.
I'm very interested in the DCF77 Time Module and I have order one from PVElectronics, but I have some questions about its technical data:
Supply voltage range: Max 5V, Min 1.8.
What voltage are you using? 3.3 or 5v?
PON Input Level High: Min 0.85.
Is this enough to arduino? is some interface transistor needed?
Thank you very much.
I have powered mine from the 3.3v rail on a Uno, and I have not had any interface issues. I just wired the output pin of the module directly to analogue 0 on the Arduino. I'm using the pin as a digital input, not an analogue one.
I have wired the PON pin to ground, which keeps the receiver powered up all the time, so I am not interested in the PON levels.
OK. PON = ENABLE.
Is there any special reason to use analog instead of digital?
Thank you very much.
Yes, I am using it with a LOLShield and it ties up all the digital pins. Analogue is all that was left!
Jarkman, are you using any pull-up resistor like:
http://gonium.net/md/2006/11/05/arduino-dcf77-radio-clock-receiver/
?
Thanks
No, I found that my receiver did not require one.
Incidentally, I have found that my receiver's reliability varies with the time of day. It generally gets a fix first time in the evening (which means it knows the time within 120 seconds of boot), but during the daytime it can take 15 minutes.
I think the difference is down to radio propagation changes with time of day. I intent to rework some of my code to make it less vulnerable to short spikes, which ought to help.
That's the reason why I will use a combination of a ds1307 and a dcf77 receiver.
DS1307 to keep time and dcf77 to make corrections.
The dcf77 module will sync the RTC every start of minute found.