"Convert" NTP to DCF77 - generate a DCF77 signal on an Arduino using an NTP time source
I hate having to set clocks. Most of our clocks at home get the time from Internet or from the DCF77 time signal.
The problem with the DCF77 time signal is that it is quite sensitive to environmental noise from lamps or other appliances, and the reception inside buildings can be problematic in some places.
I recently installed a clock in such a location. Using Udo Klein's DCF77 analysis tool it was clear that it would be nearly impossible to get the clock to work properly as initially planned, so I started looking for solutions:
- bigger antenna (eg this one)
- external antenna
- external receiver
- different time source
For different reasons, the only viable option seemed to be a different time source. But I did not want to change the clock design. While researching a solution, I came across the Chronvertor. Although this would allow to run the clock without DCF77 signal, the clock would still have to be set from time to time (due to lack of precision of the RTC, but at least twice per year for DST adjustments), so I quickly dismissed that option. However it provided inspiration for what I eventually ended up building: a NTP to DCF77 "adapter".
I had experimented previously with the TimeNTP example from the Arduino Time library, and there was plenty of information available online about the DCF77 signal, so this quickly appeared to be a viable option. This is the result: ntp2dcf.ino.
The problem with the DCF77 time signal is that it is quite sensitive to environmental noise from lamps or other appliances, and the reception inside buildings can be problematic in some places.
I recently installed a clock in such a location. Using Udo Klein's DCF77 analysis tool it was clear that it would be nearly impossible to get the clock to work properly as initially planned, so I started looking for solutions:
- bigger antenna (eg this one)
- external antenna
- external receiver
- different time source
For different reasons, the only viable option seemed to be a different time source. But I did not want to change the clock design. While researching a solution, I came across the Chronvertor. Although this would allow to run the clock without DCF77 signal, the clock would still have to be set from time to time (due to lack of precision of the RTC, but at least twice per year for DST adjustments), so I quickly dismissed that option. However it provided inspiration for what I eventually ended up building: a NTP to DCF77 "adapter".
I had experimented previously with the TimeNTP example from the Arduino Time library, and there was plenty of information available online about the DCF77 signal, so this quickly appeared to be a viable option. This is the result: ntp2dcf.ino.
Comments
Display comments as Linear | Threaded
Лъчезар Георгиев on :
crox on :
As for the license, I will think about it and update the file (probably CC or GPL), in any case if you make improvements please share them :o)
Лъчезар Георгиев on :
--- ntp2dcf.in0 2014-10-20 12:05:58.000000000 +0300
+++ ntp2dcf.ino 2014-10-27 19:59:42.000000000 +0200
@@ -99,7 +99,7 @@
void loop()
{
- if (timeStatus() != timeNotSet) {
+ if (timeStatus() == timeSet) {
if (now() != lastUpdate) { // new pulse every second
lastUpdate = now();
uint8_t curSec = second();
@@ -144,7 +144,7 @@
digitalClockDisplay();
#endif
}
- if (outOff < millis()) {
+ if ((signed long)(outOff - millis()) < 0) {
digitalWrite(DCFOUT, LOW);
}
}
@@ -294,7 +294,7 @@
#endif
sendNTPpacket(timeServer);
uint32_t beginWait = millis();
- while (millis() - beginWait < 1500) {
+ while ((signed long)(millis() - beginWait) < 1500) {
int size = Udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
#if DEBUG
Anonymous on :
if (timeStatus() != timeNotSet) {
with
if (timeStatus() == timeSet) {
Thus if the gateway crashes, DCF pulse generation will stop (for 10 minutes they drift about 0,5 s here which I think is still acceptable) and the quartz crystal of the clock will determine its time, until the connection with the NTP server is resumed and a sync can be done. The other alternative is to replace the ceramic resonator with a quartz crystal, but this is not so easy and not for everybody.
Have you checked your code against mills() rollover (occurs in 7 weeks)? Do you think that the following line is safe?
if (outOff < millis()) {
Лъчезар Георгиев on :
@@ -76,14 +76,11 @@
delay(250);
Serial.println("NTP to DCF77");
#endif
- if (Ethernet.begin(mac) == 0) {
- // no point in carrying on, so do nothing forevermore:
- while (1) {
- #if DEBUG
- Serial.println("Failed to configure Ethernet using DHCP");
- #endif
- delay(10000);
- }
+ while (Ethernet.begin(mac) == 0) {
+ #if DEBUG
+ Serial.println("Failed to configure Ethernet using DHCP, will try again...");
+ #endif
+ delay(10000);
}
#if DEBUG
Serial.print("IP number assigned by DHCP is ");
Alexander Grigorev on :
C:\Users\gam.FSKVOLGA\Desktop\ntp2dcf\ntp2dcf.ino: In function 'void setup()':
ntp2dcf:96: error: 'setSyncProvider' was not declared in this scope
setSyncProvider(getNtpTime);
^
ntp2dcf:97: error: 'setSyncInterval' was not declared in this scope
setSyncInterval(600); // default is 300
^
C:\Users\gam.FSKVOLGA\Desktop\ntp2dcf\ntp2dcf.ino: In function 'void loop()':
ntp2dcf:102: error: 'timeStatus' was not declared in this scope
if (timeStatus() != timeNotSet) {
^
ntp2dcf:102: error: 'timeNotSet' was not declared in this scope
if (timeStatus() != timeNotSet) {
^
ntp2dcf:103: error: 'now' was not declared in this scope
if (now() != lastUpdate) { // new pulse every second
^
ntp2dcf:105: error: 'second' was not declared in this scope
uint8_t curSec = second();
^
C:\Users\gam.FSKVOLGA\Desktop\ntp2dcf\ntp2dcf.ino: In function 'void calculateDCF()':
ntp2dcf:159: error: 'now' was not declared in this scope
if (LTZ.locIsDST(now())) {
^
ntp2dcf:167: error: 'minute' was not declared in this scope
bcdWrite(21, 27, minute());
^
ntp2dcf:171: error: 'hour' was not declared in this scope
bcdWrite(29, 34, hour());
^
ntp2dcf:175: error: 'day' was not declared in this scope
bcdWrite(36, 41, day());
^
ntp2dcf:177: error: 'weekday' was not declared in this scope
bcdWrite(42, 44, ((weekday()+5)%7)+1);
^
ntp2dcf:179: error: 'month' was not declared in this scope
bcdWrite(45, 49, month());
^
ntp2dcf:181: error: 'year' was not declared in this scope
bcdWrite(50, 57, year()-2000);
^
exit status 1
'setSyncProvider' was not declared in this scope
Этот отчёт будет иметь больше информации с
включенной опцией Файл -> Настройки ->
"Показать подробный вывод во время компиляции"
crox on :
See the comments in the code - I'm using the one from https://www.pjrc.com/teensy/td_libs_Time.html