A DCF77 Atomic Clock (Mainflingen/Frankfurt) 

for the Raspberry Pi


Like the MSF atomic clock project described elsewhere, the installation in Mainflingen near Frankfurt is a highly accurate atomic clock. The transmission frequency is 77.5kHz  and the output power of the Mainflingen clock is considerably higher than the one in Anthorn. Hence this clock can be received over most of Europe

The finished project must be connected to a GPIO line of the Raspberry Pi. I used my 5 in 16 out interface and connected the output of the clok to the GPIO line 29. If you use a different line, don't forget to change the relevant code in the program. The antenna should be aligned with Frankfurt in Germany though I have found that I get the best results pointing the thing in an entirely different direction!

The radio circuit

I have always had tremendous problems with the reception of the Mainflingen signal, and I always blamed my location - the far North of Northern Ireland. I now blame the receivers. Our local Lidls shop sold a radio controlled clock the other day (this is written on the 18th of April 2012). I bought one on spec because I wanted the 77.5kHz crystal and the clock was only £5. It turns out that it contained one of the best atomic clock receivers I have come across. The receiver is easily removed and is a self-contained unit (shown on the right". The output is rock steady. It can also easily be converted to a MSF receiver by swapping the crystal and using a 60kHz antenna. Not bad for a fiver!

I designed a small circuit to adapt the radio to the Raspberry Pi. The two diodes drop the 5V supply voltage to make it suitable for the receiver. The circuit diagramIt operates at 3V, though for all I know it can cope with 5V as well. As I like to have a flashing LED and the original - now useless - clock came with a nice blue one, I fitted a 7404 logic chip as a driver. This gave me plenty of NOT gates which I used to give a normal and inverted output to both the LED and the output pin. Two links select your choice. Anybody interested in the PCB layout, please drop me a line.

The receiver works a treat. It is stationed about 3 meters away from my computer and shows no interference whatever. The signal comes in at a steady 100ms  for 0 and 200ms for a one and is quite predictable. The output is connected to the GPIO 29 line using my 5in 16 out interface board.

If you have bad reception and you run your receiver via a mains power supply try using batteries. This can make a huge difference.


The Program

The DCF clock takes exactly one minute to transmit the date and time. The timing diagram of three seconds is shown below.   The decoding scheme is different from the one used by the MSF clock, though there are similarities.

Every second carries one bit. To show a 0 the carrier amplitude is reduced to 30% for 100ms and for a one for 200ms. Second 0 of the sequence is high for the full second.

The DCF77 cyle

Some translations may be of use here. Starting anti clockwise from the top:

Kalenderjahr  -  year

Kalendermonat  -  month

Wochentag  - day of the week. Monday being 1 and Sunday 7

Stunde  - hour.

I leave it to the imagination of the reader to figure out what Minute stands for.

The outside numbers indicate the binary coded decimal place values of the set bits, the inside numbers are second indicators.. An example will make things clearer. All time values are transmitted via bits 21 to 57. The data for the year, for example,  are represented by bits 50 to 57. This article was written in 2011, so bit 51 and bit 54 will be high. This is because bit 54 is worth 10 and bit 51 is worth 1. Add these two numbers and you get - you've guessed it - 11. The 2000 is assumed.

Say the year is 2087. 87 =  80 + 4 + 2 +1, hence bits 57,52,51 and 50 would be set.

The program recognises the beginning of the cycle by measuring the length of the high bit. This is always larger than 130ms at the beginning of the sequence, which is a unique value.


Here is the program and if you don't like typing, you can download it via this link

 
 

   10 REM DCF_atomic_Pi
   20 REM Decode and display the DSF77 clock
   30 REM Caters for an inverted or a non-inverted signal
   40 REM
   50 REM Output of clock should be connected to a GPIO input line
   60 REM of a Raspberry Pi
   70 REM (c) Jochen Lueg
   80 REM http://roevalley.com
   90 REM Limavady, January 2013
  100 REM Vers 1.0
  110
  120
  130 REM Chagne this number if you use a differnt GPIO pin
  140 InPort%=29
  150 REM Change this line if you want a different timebase for the graphical display
  160 REM A larger number produces more pulses per screen
  170 S%=200
  180
  190 ON ERROR PROCerror
  200 OSCLI"RMEnsure GPIO 0.00 RMLoad GPIO"
  210 OSCLI"RMensure GPIO 0.40 ERROR Please install the GPIO module"
  220 PROCsetup_GPIO
  230 MODE 1280,720,32
  240 PROCport_setup
  250
  260 PROCinit
  270
  280 PROCcheck_for_inversion
  290 PRINTTAB(1,1);"Waiting for the beginning of the sequence"
  300 IF Invert%=1 THEN
  310   PROCstart_inverted
  320   PROCprint_info
  330   PROCdecode_inverted
  340 ENDIF
  350
  360 IF Invert%=0 THEN
  370   PROCstart_non_inverted
  380   PROCprint_info
  390   PROCdecode_non_inverted
  400 ENDIF
  410 STOP
  420 END
  430
  440
  450
  460
  470 DEFPROCprint_info
  480 PRINTTAB(1,3);"Incoming DCF77 binary coded decimal bits                  "
  490 PRINTTAB(1,Tab5%)"                                                      "
  500 PRINTTAB(29,Tab1%)" |R ! S N L -|    Minute   |P|    Hour   |P|    Day    | DoW |  Month  |      Year     |P|"
  510 PRINTTAB(7,Tab6%)"   ";
  520 PRINT "| R = Reserve antenna | S = Summertime | ! = S announce | N = Normal time | L=leap second |"
  530
  540 ENDPROC
  550
  560
  570 DEFPROCdecode_non_inverted
  580 LOCAL Low%,High%,C%,Byte%,Col%
  590 Col%=0
  600 C%=0
  610 REPEAT
  620   IF Col%=0 COLOUR 255,225,0
  630   IF Col%=1 COLOUR 0,222,255
  640  
  650   REPEAT
  660     SYS "GPIO_ReadData",InPort% TO Byte%
  670     IF G%=1 X%+=1:PLOT 5,X%/S%,Byte%*200 :IF X%/S%>2500 X%=0:CLG:MOVE 0,0
  680   UNTIL Byte%=1 AND TIME>5
  690   Low%=TIME
  700  
  710   TIME=0
  720   REPEAT
  730     SYS "GPIO_ReadData",InPort% TO Byte%
  740     IF G%=1 X%+=1:PLOT 5,X%/S%,Byte%*200 :IF X%/S%>2500 X%=0:CLG:MOVE 0,0
  750   UNTIL Byte%=0 AND TIME>5
  760   High%=TIME
  770   TIME=0
  780   IF Low%<15 Time%(C%)=0
  790   IF Low%>15 Time%(C%)=1
  800   PROCdecode(C%)
  810   IF High%>130 C%=-1:Col%=Col%EOR1
  820   C%+=1:IF C%>  61 C%=1
  830 UNTIL FALSE
  840 ENDPROC
  850
  860
  870 DEFPROCdecode_inverted
  880 LOCAL Low%,High%,C%,Byte%,Col%
  890 Col%=0
  900 C%=0
  910 REPEAT
  920   IF Col%=0 COLOUR 255,225,0
  930   IF Col%=1 COLOUR 0,222,255
  950   REPEAT
  960     SYS "GPIO_ReadData",InPort% TO Byte%
  970     IF G%=1 X%+=1:PLOT 5,X%/S%,Byte%*200 :IF X%/S%>2500 X%=0:CLG:MOVE 0,0
  980   UNTIL Byte%=0  AND TIME>4
  990   High%=TIME
 1000   TIME=0
 1010   REPEAT
 1020     SYS "GPIO_ReadData",InPort% TO Byte%
 1030     IF G%=1 X%+=1:PLOT 5,X%/S%,Byte%*200 :IF X%/S%>2500 X%=0:CLG:MOVE 0,0
 1040   UNTIL Byte%=1  AND TIME>4
 1050   Low%=TIME
 1060   TIME=0
 1070   IF High%<15 Time%(C%)=0
 1080   IF High%>15 Time%(C%)=1
 1090   PROCdecode(C%)
 1100   IF Low%>130 C%=-1:Col%=Col%EOR1
 1110   C%+=1 :IF C%>61 C%=1
 1120 UNTIL FALSE
 1130 ENDPROC
 1140
 1150
 1160 DEFPROClegend
 1190 COLOUR 15
 1200 PRINTTAB(1,TabY_exp%)"| DUT1 positive | DUT1 negative |      Year     |  Month  |    Day    | DoW |    Hour   |    Minute   |  !  Frame  S  |"
 1210 C%=1
 1220 DUT%=0
 1230 ENDPROC
 1240
 1250
 1260 DEFPROCstart_non_inverted
 1270 LOCAL Byte%,Low%,Byte%
 1280 TIME=0
 1290 REPEAT
 1300   SYS "GPIO_ReadData",InPort% TO Byte%
 1310   IF G%=1 X%+=1:PLOT 5,X%/S%,Byte%*200 :IF X%/S%>2500 X%=1:CLG:MOVE 0,0
 1320 UNTIL Byte%=1   AND TIME>4
 1330 TIME=0
 1340 REPEAT
 1350   SYS "GPIO_ReadData",InPort% TO Byte%
 1360   IF G%=1 X%+=1:PLOT 5,X%/S%,Byte%*200 :IF X%/S%>2500 X%=1:CLG:MOVE 0,0
 1370 UNTIL Byte%=0  AND TIME>4
 1380 TIME=0
 1390 REPEAT
 1400   REPEAT
 1410     SYS "GPIO_ReadData",InPort% TO Byte%
 1420     IF G%=1 X%+=1:PLOT 5,X%/S%,Byte%*200 :IF X%/S%>2500 X%=1:CLG:MOVE 0,0
 1430   UNTIL Byte%=1    AND TIME>4
 1440   Low%=TIME
 1450  
 1460   TIME=0
 1470   REPEAT
 1480     SYS "GPIO_ReadData",InPort% TO Byte%
 1490     IF G%=1 X%+=1:PLOT 5,X%/S%,Byte%*200 :IF X%/S%>2500 X%=1:CLG:MOVE 0,0
 1500   UNTIL Byte%=0   AND TIME>4
 1510   High%=TIME
 1520  
 1530   PRINTTAB(1,Tab5%)"High:  ";High%;"    Low:  ";
 1540   IF Low%<10 PRINT" ";
 1550   PRINT;Low%;"   Both:  ";High%+Low%;"  "
 1560   TIME=0
 1570  
 1580 UNTIL High%>130
 1590 PRINTTAB(1,1);"Beginning of the minute detected            "
 1600 C%=0
 1610 ENDPROC
 1620
 1630
 1640 DEFPROCstart_inverted
 1650 LOCAL Byte%,Low%
 1660 REPEAT
 1670   SYS "GPIO_ReadData",InPort% TO Byte%
 1680   IF G%=1 X%+=1:PLOT 5,X%/S%,Byte%*200 :IF X%/S%>2500 X%=1:CLG:MOVE 0,0
 1690 UNTIL Byte%=0    AND TIME>6
 1700 REPEAT
 1710   SYS "GPIO_ReadData",InPort% TO Byte%
 1720   IF G%=1 X%+=1:PLOT 5,X%/S%,Byte%*200 :IF X%/S%>2500 X%=1:CLG:MOVE 0,0
 1730 UNTIL Byte%=1    AND TIME>6
 1740 TIME=0
 1750 REPEAT
 1760   REPEAT
 1770     SYS "GPIO_ReadData",InPort% TO Byte%
 1780     IF G%=1 X%+=1:PLOT 5,X%/S%,Byte%*200 :IF X%/S%>2500 X%=1:CLG:MOVE 0,0
 1790   UNTIL Byte%=0  AND TIME>6
 1800   High%=TIME
 1810  
 1820   TIME=0
 1830   REPEAT
 1840     SYS "GPIO_ReadData",InPort% TO Byte%
 1850     IF G%=1 X%+=1:PLOT 5,X%/S%,Byte%*200 :IF X%/S%>2500 X%=1:CLG:MOVE 0,0
 1860   UNTIL Byte%=1  AND TIME>50
 1870   Low%=TIME
 1880  
 1890   PRINTTAB(1,Tab5%)"High:  ";High%;"    Low:  ";
 1900   IF Low%<10 PRINT" ";
 1910   PRINT;Low%;"   Both:  ";High%+Low%;"  "
 1920   TIME=0
 1930 UNTIL Low%>130
 1940 PRINTTAB(1,1);"Beginning of the minute detected             "
 1950 C%=0
 1960 ENDPROC
 1970
 1980
 1990 DEFPROCdecode(C%)
 2000 REM Minute
 2010 IF C%=27 THEN
 2020   Minute%=40*Time%(27)+20*Time%(26)+10*Time%(25)+8*Time%(24)+4*Time%(23)+2*Time%(22)+Time%(21)
 2030   PRINTTAB(58,Tab4%);"Minute: ";Minute%
 2040 ENDIF
 2050
 2060 REM hour
 2070 IF C%=34 THEN
 2080   Hour%=20*Time%(34)+10*Time%(33)+8*Time%(32)+4*Time%(31)+2*Time%(30)+Time%(29)
 2090   PRINTTAB(47,Tab4%);"Hour: ";Hour%
 2100 ENDIF
 2110
 2120 REM Day
 2130 IF C%=41 THEN
 2140   Day%=20*Time%(41)+10*Time%(40)+8*Time%(39)+4*Time%(38)+2*Time%(37)+Time%(36)
 2150   PRINTTAB(26,Tab4%);"Day: ";Day%;" "
 2160 ENDIF
 2170
 2180 REM Day of week
 2190 IF C%=44 THEN
 2200   DoW%=4*Time%(44)+2*Time%(43)+Time%(42)
 2210   IF DoW%<8 PRINTTAB(36,Tab4%);Weekday$(DoW%)
 2220 ENDIF
 2230
 2240 REM Month
 2250 IF C%=49 THEN
 2260   Month%=10*Time%(49)+8*Time%(48)+4*Time%(47)+2*Time%(46)+Time%(45)
 2270   IF Month%<13 THEN PRINTTAB(13,Tab4%);Month$(Month%)
 2280 ENDIF
 2290
 2300 REM The year
 2310 IF C%=57 THEN
 2320   Year%=2000+80*Time%(57)+40*Time%(56)+20*Time%(55)+10*Time%(54)+8*Time%(53)+4*Time%(52)+2*Time%(51)+Time%(50)
 2330   PRINTTAB(1,Tab4%);"Year: ";Year%
 2340 ENDIF
 2350
 2360 PRINTTAB(1+C%*2,Tab2%);Time%(C%);" "
 2370 IF C%=58 PRINTTAB(118,Tab2%)"    "
 2380 PRINTTAB(70,Tab4%);"Second: ";C%;"   "
 2390 ENDPROC
 2400
 2410
 2420 DEFPROCcheck_for_inversion
 2430 LOCAL Low%,High%
 2440 Low%=0: High%=0
 2450 PRINT " Please wait for 3 seconds to check for signal inversion"
 2460
 2470 PRINT
 2480 REPEAT
 2490   SYS"GPIO_ReadData",InPort% TO Byte%
 2500 UNTIL Byte%=1
 2510
 2520 FOR J%=1 TO 3
 2530   TIME=0
 2540   REPEAT
 2550     SYS"GPIO_ReadData",InPort% TO Byte%
 2560   UNTIL Byte%=0
 2570   High%+=TIME
 2580   TIME=0
 2590   REPEAT
 2600     SYS"GPIO_ReadData",InPort% TO Byte%
 2610   UNTIL Byte%=1
 2620   Low%+=TIME
 2630 NEXT
 2640 CLS
 2650 IF Low%>High% Invert%=1 ELSE Invert%=0
 2660 IF Invert%=1 PRINT" Inverted signal"
 2670 IF Invert%=0 PRINT" Non-inverted signal"
 2680 ENDPROC
 2690
 2700
 2710 DEFPROCport_setup
 2720 VDU 28,3,45,157,20
 2730 COLOUR 132
 2740 CLS
 2750 VDU 24,40;240;2520;590;
 2760 GCOL 129
 2770 CLG
 2780 ORIGIN 40,250
 2790 VDU 5
 2800
 2810 VDU 23,23,1;0;0;0; :REM Lines double thickness
 2820 GCOL15
 2830 MOVE 0,0
 2840 X%=0
 2850
 2860 VDU4
 2870 OFF
 2880 MOUSE OFF
 2890 ENDPROC
 2900
 2910
 2920 DEFPROCinit
 2930 Tab1% = 10
 2940 Tab2% = 9
 2950 Tab3% = 8
 2960 Tab4% = 18
 2970 Tab5% = 4
 2980 Tab6% = 13
 2990 Bit%=5
 3000 Ch%=1
 3010 G%=1
 3020
 3030
 3040
 3050 DIM Time%(100)
 3060 DIM Weekday$(7)
 3070 Weekday$(1)="Monday   "
 3080 Weekday$(2)="Tuesday  "
 3090 Weekday$(3)="Wednesday"
 3100 Weekday$(4)="Thursday "
 3110 Weekday$(5)="Friday   "
 3120 Weekday$(6)="Saturday "
 3130 Weekday$(7)="Sunday   "
 3140
 3150 DIM Month$(12)
 3160 Month$(1)="January  "
 3170 Month$(2)="February "
 3180 Month$(3)="March    "
 3190 Month$(4)="April    "
 3200 Month$(5)="May      "
 3210 Month$(6)="June     "
 3220 Month$(7)="July     "
 3230 Month$(8)="August   "
 3240 Month$(9)="September"
 3250 Month$(10)="October  "
 3260 Month$(11)="November "
 3270 Month$(12)="December "
 3280
 3290 Decoded$=""
 3300
 3310 ENDPROC
 3320
 3330
 3340 DEFPROCerror
 3350 PRINT REPORT$;" at line ";ERL
 3360 END
 3370 ENDPROC
 3380
 3390
 3400 DEFPROCsetup_GPIO
 3410 SYS"GPIO_EnableI2C",0
 3420 SYS"GPIO_ExpAsGPIO",2
 3430 SYS"GPIO_WriteMode",InPort%,0
 3440 ENDPROC

 

Return to interfacing index

Back to the start
Tudor with sign