DCF77 HC-12 transceiver-clock

<-- Back  
Front (The colours of the LEDs are in real much more vivid) Inside the clock (3:55 hours later)
The DCF77-receiver hangs 10 cm away from the signal interfering LEDs and segment displays

Introduction

This clock decodes the DCF77-signal, displays the received DCF77 bits and various information parameters in three WS2812 RGB-rings.
After decoding it sends the time as a string into the ether with a HC-12 433MHz Wireless Serial Transceiver.
with a Bluetooth module the clock can be controlled and statistics about the received signals retrieved
The time is displayed with a 4-digit 7-segment HK16K33 and a 4-digit 7-segment I2C-TM1637 display.
(I prefer the TM1637 displays but bought the by accident HK16K33 displays.)
The received or calculated information is displayed with MAX7219 8-digits 7-segment displays.

The software makes use of an algorithm that collects the readings without using interrupts (DCFNoInt) in contrast with the DCF77 Arduino library that uses interrupt to detect a pulse change.
In this DCFNoInt-program the processor is able to collect, in it spare time, over 30,000 low or high signals.
In Mainflingen, Germany, a transmitter send on the long wave frequency of 77.5 KHz a signal that can be on or off (high or low).
Every second the signal is on for 0.1 second or 0.2 second. That translates in respectively a 0 or 1 bit.
The time is decoded in a binary-coded decimal format as shown in the picture below.



The DCFNoInt-algorithm is sensitive for long delays() in the code. The sample program demonstrates a method to avoid delays.
An advantage of this non-interrupt method is it smoothens spikes in the signal and does not require filtering because it takes an average of the received positive pulses.
Not all programs can be made 'uninterruptable' without long delays . Time consuming subroutines can make the pulse readings less usable.
The menu contains an option to read the pulses every x msec for y msec long. By playing with the x and y values the readings may be optimized for a program with long running subroutines.

It is also possible to make a smaller unit with a 24 LED ring and a HC-12 transceiver. See here how to make this receiver or modify this newer program V057 used for this DCF77-transceiver.

The efficiency of the NoInt-method is comparable with the DCF77-library in the Arduino IDE from Thijs Ellenbaas.
With good reception both methods decode over 99%.
When reception is worse it depends on the signal. Sometimes the DCFNoInt-routine outperforms the interrupt routine by 50%.
The interrupt and non-interrupt methods are both used together in this program and increases the efficiency even further.
In this program both received times must be identical before it is written to the optional RTC-module or internal Arduino clock.

 
  This is the result of a DCF77 receiver 5 cm away from WS2812 LEDs .
These LEDs (but also the 7-segment displays) interferes the reception of the signal. From the 20365 minutes the original Arduino library (Th:) receives 5026 (25%) date/times correctly. The non interrupt algorithm (Ed:) decodes 9263 (45%) times the date/time. EdT: are the 1682 proper times but not proper dates received.
  Combined the proper received times exceeded 75% (not shown). That is 3 times better.


The Program

By turning on or off the #defines with a // in the program, one or both methods can be used.

#define DCFMOD       // Use the Arduino DCF77 library with interrupts.
#define DCFTINY      // Use the DCFNoInt DCF algorithm in this program.
 
This is the heart of the algoritm; just counting the positive signals and the total received signals.
 SumSecondSignal += (!digitalRead(DCF_PIN));      // invert 0 to 1 and 1 to 0
 SumSignalCounts++;
    

After 995 milliseconds it waits for the positive signal to drop to zero.

if((millis() - DCFmsTick) >995))     // Compute every second the received DCF-bit to a time 
 { 
 while (1-digitalRead(DCF_PIN))     // Avoid splitting a positive signal 
  {
   SumSignalCounts++;
   SumSecondSignal++;
  } 

These few lines took weeks of experimenting and solve why it lost every few minutes a good reception of the time.
The internal Arduino clock drifts more than expected. 1 second in less than 10 minutes.
In line 848 there is a correction possibility to make the calculation of the pulse percentage close to 10% and 20%.
The signal length can be seen in the serial monitor or Bluetooth connection with option A from the menu and of course on the clock it self.

 SumSignalCounts*=1.10;     // Correction to correct pulses to an average of 100 and 200 msecs

When the signal is decoded in line 913 a signal length between 5.1 and 16% is a 0 bit and between 16% and 32% a 1 bit.
No signal for a second is the start of a new minute and all other signal lengths are an error.

int msec  = (int)(1000 * SumSecondSignal / SumSignalCounts);                  // This are roughly the milliseconds times 10 of the signal length
 switch(msec)
  {
   case   0 ...  10: if (SumSignalCounts > 50)                                 // Check if there were enough signals
                       {Bitpos = 59; Receivebitinfo = 2; Receivebit = 0; }     // If enough signals and one second no signal found. This is position zero
                              else { Receivebitinfo = 9; Receivebit = 0; }     // If not it is a bad signal probably a zero bit
                                                                        break; // If signal is less than 0.05 sec long than it is the start of minute signal
   case  11 ...  50: Receivebitinfo = 8; Receivebit = 0;                break; // In all other cases it is an error
   case  51 ... 160: Receivebitinfo = 0; Receivebit = 0;                break; // If signal is 0.1 sec long than it is a 0 
   case 161 ... 320: Receivebitinfo = 1; Receivebit = 1;                break; // If signal is 0.2 sec long than it is a 1 
   default:          Receivebitinfo = 9; Receivebit = 1;                break; // In all other cases it is an error probably a one bit
  }

Errors are flagged in the Receivebitinfo and the flag TimeSignaldoubtfull is set. When set the time/date is not reported.
The decoding routine returns TimeOk = 5 as result.
When TimeOK = 1 then the Date and time are correct. When TimeOk = 2 the date is possibly wrong but the time is OK and differs less than 2 minutes from the previous received time.

Statistics are stored into EEPROM once a day at 0:00.
Statistics can be seen from the menu with option S

 

When A is pressed in the menu every second this line is printed

@MH. 4181 36100 11% (0) 14:42:47 05-01-2000/6 F1 Ed:10943 Th:11094 Min:11717 OK:0 L:Y
@MH. 8905 37769 23% (1) 14:42:48 05-09-2000/6 F1 Ed:10943 Th:11094 Min:11717 OK:0 L:Y
@MH. 4095 36086 11% (0) 14:42:49 05-09-2000/6 F1 Ed:10943 Th:11094 Min:11717 OK:0 L:Y
@MH. 4286 36099 11% (0) 14:42:50 05-09-2000/6 F1 Ed:10943 Th:11094 Min:11717 OK:0 L:Y
@MH. 4424 36059 12% (0) 14:42:51 05-09-2000/6 F1 Ed:10943 Th:11094 Min:11717 OK:0 L:Y
@MH. 4150 36099 11% (0) 14:42:52 05-09-2000/6 F1 Ed:10943 Th:11094 Min:11717 OK:0 L:Y
@MH. 3992 36100 11% (0) 14:42:53 05-09-2000/6 F1 Ed:10943 Th:11094 Min:11717 OK:0 L:Y
@MH. 3831 36058 10% (0) 14:42:54 05-09-2000/6 F1 Ed:10943 Th:11094 Min:11717 OK:0 L:Y
@MH. 9440 38493 24% (1) 14:42:55 05-09-2020/6 F1 Ed:10943 Th:11094 Min:11717 OK:0 L:Y
@MH. 3783 36051 10% (0) 14:42:56 05-09-2020/6 F1 Ed:10943 Th:11094 Min:11717 OK:0 L:Y
a
When S is pressed
s
----> Statistics -----
DCFEd:10943                  DCFNoInt algorithm 
DCF77:11094                  DCF Arduino library 
Both:10537                   Identical time at the same minute 
Valid times:11474            Valid times receive with both algorithms 
Total minutes:11717          Total time running
DCF Eff:97% Signal:99 DCF    Valid times in % and consecutive good minutes received (0-99) 
0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23 -- Hour
60 60 60 60 60 60 58 60 58 60 56 58 58 54 60 60 58 60 56 58 58 53 60 55 -- Valid times NoInt
60 60 60 60 60 60 60 60 59 60 54 47 60 55 60 60 60 58 58 58 60 54 60 60 -- Valid times Int
03 03 04 03 03 05 00 03 04 02 03 07 03 17 01 01 02 05 03 01 03 02 02 03 -- Signal faults
1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
56 57 57 57 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
57 58 58 58 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
05 03 03 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
1  2  3  4  5  6  7  8  9  10 11 12
00 00 00 00 00 00 00 54 00 00 00 00 
00 00 00 00 00 00 00 55 00 00 00 00 
00 00 00 00 00 00 00 19 00 00 00 00 
0  1  2  3  4  5  6  7  8  9    Last 10 years (year modulo 10)
00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 
  DCF77 Lib OK --> 14:42 05-09-2020                       The Arduino library decode a date/time 
TIME & DATE OK --> 14:42 05-09-2020                       The DCFNoInt algorithm decode a date/time
@L001|14:42:01 05-09-2020|DCF-eff:97% Signal:99 |DCF      Line sent with the HC-12
T144202                                                   Line sent with HC-12 to set time in my clocks

After two years statistics are:

----> Statistics -----
DCFEd:855591
DCF77:785000
Both:759415
Valid times:878673
Total minutes:1006933
DCF Eff:87% Signal:99 DCF
0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23 
60 58 58 58 60 56 60 60 58 60 58 60 60 54 56 58 60 60 56 58 00 00 00 42 
60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 00 00 00 43 
02 04 02 03 01 03 04 00 05 00 04 02 05 03 02 01 03 04 03 02 00 00 00 03 
1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
58 59 58 58 57 56 42 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
59 60 59 59 59 57 43 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
03 02 03 02 02 05 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
1  2  3  4  5  6  7  8  9  10 11 12
57 56 57 57 57 57 57 58 58 56 56 56 
57 52 48 57 57 58 58 58 58 55 56 56 
07 08 07 05 08 04 06 06 03 07 05 08 
 0  1  2  3  4  5  6  7  8  9    Last 10 years (year modulo 10)
08 52 56 00 00 00 00 00 00 00 
57 56 55 00 00 00 00 00 00 00 
15 09 10 00 00 00 00 00 00 00 

The DCF77 algorithm stopped working for some time and has a slightly lower score. After a restart of the clock the system worked again.
Yesterday around 23h the MAX7219 display did not react anymore and a power down was needed.

 

The LEDs and Display

The DCFNoInt (DCFTINY in the define) algorithm was developed to drive the LEDs of the clock.
The clock contains three rings of 8, 24 and 60 LEDs.
The outer ring displays the received bits per minute. blue = 0 and red = 1.
The middle ring display the signal efficiency per hour and the current hour with a white LED.
The inner ring displays various parameters.
DCF clock display
Small DCF77 clock display
Dutch design of the front display. I printed it on paper and placed it before the LEDs.

A TM1637 or HT16K33 display shows the current time.
A MAX7219 display is used to show the pulse width in msec, and the time as it is decoded by the algorithm
and the decoding efficiency in time as a percentage.
In the first seconds it displays the valid received times and total minutes it is running and then the date as 'ddmm'
After 20 seconds the right four digits are the bit received by the LDR that controls the light intensity of the LEDs.
So a lot of info and changing digits.

The time is transmitted at 433 MHz with a HC12 transceiver module.
The HC-12 can replace a Bluetooth module. They use the same baud rate of 9600 bps. Only the RX and TX lines are switched.
The coding to get the received characters from the module is identical.
 
With a Bluetooth module connected the DCF77 clock can be operated with a phone.
Search for "BLE HM-10 Terminal serial" for programs in the app stores of the phone
On a PC/laptop with Bluetooth a connection can also be set up.

The Menu

The menu is as below and can be printed when entering the I in the serial monitor of the Arduino IDE
or on a phone when connected with the Bluetooth module.

*** DCF HC12 Bluetooth Transmitter ***
Enter time as: Thhmmss (T132145)
A  DCF debug info On/Off
B  Short DCF debug info On/Off
C  Clear statistics
E  Reset MAX7219
F  Toggle full or interval DCFtiny readings
G  (G20) DCF loop measures every (0-999) msec
H  (H50) measurements in DCF loop (0-999)
I  For this info
K  Toggle HC12 transmission ON/OFF
Lnn (L5) Min light intensity ( 1-255)
Mnn (M90)Max light intensity (1%-250%)
N  (N2208)Turn On/OFF LEDs between Nhhhh
O  Turn Display ON/OFF
R  Reset
S  Print statistics
------------------------------------------
    Ed Nieuwenhuys sep-2020
  Brightness Min:  4 bits Max:  15%
    LDR read Min:  0 bits Max: 187 bits
  DCF loop every:  5 msec  for:  25 times
LEDs off between: 22 - 08
------------------------------------------
Software version: V055 Station: L001
16:42:41 01-09-2020

 

The Electronics

An Arduino Nano Every is used to run the program.
Sketch uses 35859 bytes (72%) of program storage space. Maximum is 49152 bytes.
Global variables use 1553 bytes (25%) of dynamic memory, leaving 4591 bytes for local variables. Maximum is 6144 bytes.

Fritzing design of the PCB.  

 

The parts are connected to a PCB (designed for my Fibonacci and colour clocks).
A voltage divider with the 2.2 kOhm and 1.1 kOhm resistors lowers to voltage from 5V to 3.3V for the Bluetooth module
The 470 Ohm resistors are used between the two LEDs and between the signal line of the WS2812 LEDs and the processor.
The 22 kOhm resistor
gives good results with the GL5528 LDR photo resistor.
A 1000 uF capacitor protects the circuit and the WS2812 LEDs against power spikes.
There is no need for a rotary decoder and these pins are used to connect the TM1637 display.


The following pins are connected:
     // Digital hardware constants 

 DCF_PIN       = 2,  // DCFPulse on interrupt pin
 CLK_TM1637    = 3,  // PIN 3 TM1637Display
 DIO_TM1637    = 4,  // PIN 4 TM1637Display
 LED_PIN       = 5,  // LED rings on pin PIN 5
 BT_TX         = 6,  // Rx-pin on BT-mod to TX-pin on Arduino
 BT_RX         = 7,  // Tx-pin on BT-mod to RX-pin on Arduino 
 HC_12TX       = 8,  // RXD on HC-12 to TX Pin on Arduino 
 HC_12RX       = 9,  // TXD on HC-12 to RX Pin on Arduino
 MAX7219CLK    = 10, // MAX7219CLK
 MAX7219CS     = 11, // MAX7219CS 
 MAX7219DataIn = 12, // MAX7219DataIn
 DCF_LED_Pin   = 13  // Show DCF-signal
 };
 // Analog hardware constants ----
 EmptyA0       = 0, // A0
 EmptyA1       = 1, // A1
 PhotoCellPin  = 2, // A2 LDR
 EmptyA3       = 3, // A3
 SDA_pin       = 4, // SDA I2C pin for HT16K33 time display and DS3231 RTC clock module
 SCL_pin       = 5, // SCL I2C pin for HT16K33 time display and DS3231 RTC clock module
 EmptyA6       = 6, // Empty
 EmptyA7       = 7  // Empty 

Software

DCF_HC12TransmitterV57.ino

librariesForDCFtransceiver.zip


More info about clocks and DCF77 here:
https://ednieuw.home.xs4all.nl/Woordklok/index.html

Ed Nieuwenhuys
13 September 2022