A DCF77 Atomic Clock (Mainflingen/Frankfurt)


Like the MSF atomic clock project described elsewhere, the installation in Mainflingen 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 digital input port 4 of a Velleman K8055 interface board. 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! Notice that in the photograph below the small antenna supplied with the receiver has been replaced by a much larger home-brew antenna. Without this swap I could get no clean reception.

DCF77 clock

Circuit description

The heart of the project is a small circuit board which is made by a firm called Symtrik. They list it as the SYM-RFT-77 module. The module is sold combined with a small tuned ferrite rod antenna for under 8 pounds. The components are mounted on a small wooden board. This keeps the PCB and the rather heavy antenna safely together. The receiver module is in fact the same as used for the MSF 60kHz clock, except for a different ceramic crystal and a ferrite rod antenna tuned to 77.5kHz rather than 60kHz.


The radio circuit


Version 2

I have always had tremendous problems with the reception of the Mainflingen signal, and I  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 K8055. 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 inteference 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 digital input 4 of the Velleman board. You can test the reception with the help of my Slowscope program. A trace can be seen below. 


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 output of the receiver

The trace is on a scale of 250ms/div. As can be seen the input is non-inverted and the 1s at 6,10 and 18 are twice as wide as the 0s at 2, 21 and 25.

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.

I have written the program to be as simple as possible. The main aim is to demonstrate how the data bits arrive one by one and how the time is decoded as the sequence develops. Below is a sample output. 


Program output


The fourth line shows the pulse train for one minute. Cyan is the previous minute, white the current minute. The colour changes time about so that the new bits are always visible.

The next line indicates the purpose of every bit.  Take the hour for instance. This frames the bits 011010. They come in in reverse order, so this should read 010110 which is one 2, one 4 and one 10 = 16. i.e. four in the afternoon European time.

The bottom line displays the decoded calendar and time information, again in two colours.

Below is a link to an archive with the  BBC BASIC program file and also a  self-contained .exe file of the program below. Notice that the output is in central European time which differs from Britain by 1 hour. The program can cope with both an inverted and a non-inverted signal.

Please note that this latest version of the program uses the digital input 4 rather than an ADC input of the Velleman board.

 
   10 REM K8055_DCF_4_0
   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 analogue input A1
   60 REM of a Velleman K8055 USB interface booard
   70 REM (c) Jochen Lueg
   80 REM http://roevalley.com/newsbrowser/v-projects/v-index.htm
   90 REM Limavady, September 2013
  100 REM Vers 4.0
  110 REM Uses digital input 4
  120
  130
  140 ON ERROR PRINT REPORT$;" at line ";ERL  : END
  150 PROCK8055_init
  160 ON ERROR PROCerror
  170 ON CLOSE PROCclose
  180 PROCport_setup
  190 PROCinit
  200 PROCcheck_for_inversion
  210 PRINTTAB(21,1);"Waiting for the beginning of the sequence"
  220
  230 IF Invert%=1 THEN
  240   PROCK8055_start_inverted
  250   PROCprint_info
  260   PROCdecode_inverted
  270 ENDIF
  280
  290 IF Invert%=0 THEN
  300   PROCK8055_start_non_inverted
  310   PROCprint_info
  320   PROCdecode_non_inverted
  330 ENDIF
  340 PROCclose
  350 END
  360
  370
  380 DEFPROCclose
  390 SYS K8055_ClearAllDigital%
  400 SYS K8055_CloseDevice%
  410 SYS "FreeLibrary",K8055_Board%
  420 QUIT
  430 ENDPROC
  440
  450
  460 DEFPROCprint_info
  470 COLOUR Col3%
  480 PRINTTAB(21,8);"Incoming DCF77 binary coded decimal bits                  "
  490 PRINTTAB(21,Tab5%)"                                                      "
  500 PRINTTAB(20,10)"|   Variable internal codes   |R ! S N L -|    Minute   |P|    Hour   |P|    Day    | DoW |  Month  |      Year     |P|"
  510 PRINTTAB(49,11)" |R = Reserve antenna | S = Summertime  | ! = S announce |"
  520 PRINTTAB(49,12)" |N = Normal time     | L = leap second | P = Parity bit |"
  530 ENDPROC
  540
  550
  560 DEFPROCdecode_non_inverted
  570 LOCAL Low%,High%,C%,State%
  580 C%=0
  590 REPEAT
  600   COLOUR Col1%
  610   REPEAT
  620     SYS K8055_ReadDigitalChannel%,Port% TO State%
  630     IF G%=1 X%+=1:PLOT 5,X%/S%,State%*222 :IF X%/S%>2900 X%=0:CLG:MOVE 0,0
  640   UNTIL State%=1 AND TIME>5
  650   Low%=TIME
  660   SYS K8055_WriteAllDigital%,128
  670   TIME=0
  680   REPEAT
  690     SYS K8055_ReadDigitalChannel%,Port% TO State%
  700     IF G%=1 X%+=1:PLOT 5,X%/S%,State%*222 :IF X%/S%>2900 X%=0:CLG:MOVE 0,0
  710   UNTIL State%=0 AND TIME>5
  720   High%=TIME
  730   SYS K8055_WriteAllDigital%,64
  740   TIME=0
  750   IF Low%<15 Time%(C%)=0
  760   IF Low%>15 Time%(C%)=1
  770   PROCdecode(C%)
  780   IF High%>130 C%=-1:SWAP Col1%,Col2%
  790   C%+=1
  800   PROCcheck_keyboard
  810 UNTIL FALSE
  820 ENDPROC
  830
  840
  850 DEFPROCdecode_inverted
  860 LOCAL Low%,High%,C%,Col1%,Col2%,State%
  870 Col1%=15 : REM White
  880 Col2%=6  : REM Cyan
  890 C%=0
  900 REPEAT
  910   COLOUR Col1%
  920   REPEAT
  930     SYS K8055_ReadDigitalChannel%,Port% TO State%
  940     IF G%=1 X%+=1:PLOT 5,X%/S%,State%*222 :IF X%/S%>2900 X%=0:CLG:MOVE 0,0
  950   UNTIL State%=0  AND TIME>4
  960   High%=TIME
  970   SYS K8055_WriteAllDigital%,128
  980   TIME=0
  990   REPEAT
 1000     SYS K8055_ReadDigitalChannel%,Port% TO State%
 1010     IF G%=1 X%+=1:PLOT 5,X%/S%,State%*222 :IF X%/S%>2900 X%=0:CLG:MOVE 0,0
 1020   UNTIL State%=1  AND TIME>4
 1030   Low%=TIME
 1040   SYS K8055_WriteAllDigital%,64
 1050   TIME=0
 1060   IF High%<15 Time%(C%)=0
 1070   IF High%>15 Time%(C%)=1
 1080   PROCdecode(C%)
 1090   IF Low%>130 C%=-1:SWAP Col1%,Col2%
 1100   C%+=1 :IF C%>60 C%=1
 1110   PROCcheck_keyboard
 1120 UNTIL FALSE
 1130 ENDPROC
 1140
 1150
 1160 DEFPROCcheck_keyboard
 1170 IF INKEY(-84) G%=G% EOR 1
 1180 IF INKEY(-49) S%=1 :CLG:MOVE 0,0  :X%=1
 1190 IF INKEY(-50) S%=2 :CLG:MOVE 0,0 :X%=1
 1200 IF INKEY(-18) S%=3 :CLG:MOVE 0,0 :X%=1
 1210 IF INKEY(-19) S%=4 :CLG:MOVE 0,0 :X%=1
 1220 ENDPROC
 1230
 1240
 1250 DEFPROCK8055_start_non_inverted   :   REM Find beginnming of sequence
 1260 LOCAL State%,Low%,State%
 1270 REPEAT
 1280   SYS K8055_ReadDigitalChannel%,Port% TO State%
 1290   IF G%=1 X%+=1:PLOT 5,X%/S%,State%*222 :IF X%/S%>2900 X%=1:CLG:MOVE 0,0
 1300 UNTIL State%=1   AND TIME>4
 1310 REPEAT
 1320   SYS K8055_ReadDigitalChannel%,Port% TO State%
 1330   IF G%=1 X%+=1:PLOT 5,X%/S%,State%*222 :IF X%/S%>2900 X%=1:CLG:MOVE 0,0
 1340 UNTIL State%=0  AND TIME>4
 1350 TIME=0
 1360 REPEAT
 1370   REPEAT
 1380     SYS K8055_ReadDigitalChannel%,Port% TO State%
 1390     IF G%=1 X%+=1:PLOT 5,X%/S%,State%*222 :IF X%/S%>2900 X%=1:CLG:MOVE 0,0
 1400   UNTIL State%=1    AND TIME>4
 1410   Low%=TIME
 1420   SYS K8055_WriteAllDigital%,128
 1430   TIME=0
 1440   REPEAT
 1450     SYS K8055_ReadDigitalChannel%,Port% TO State%
 1460     IF G%=1 X%+=1:PLOT 5,X%/S%,State%*222 :IF X%/S%>2900 X%=1:CLG:MOVE 0,0
 1470   UNTIL State%=0   AND TIME>4
 1480   High%=TIME
 1490   SYS K8055_WriteAllDigital%,64
 1500   PRINTTAB(21,Tab5%)"High:  ";High%;"    Low:  ";
 1510   IF Low%<10 PRINT" ";
 1520   PRINT;Low%;"   Both:  ";High%+Low%;"  "
 1530   TIME=0
 1540   PROCcheck_keyboard
 1550 UNTIL High%>130
 1560 C%=0
 1570 ENDPROC
 1580
 1590
 1600 DEFPROCK8055_start_inverted   :   REM Find beginnming of sequence
 1610 LOCAL State%,Low%
 1620 REPEAT
 1630   SYS K8055_ReadDigitalChannel%,Port% TO State%
 1640   IF G%=1 X%+=1:PLOT 5,X%/S%,State%*222 :IF X%/S%>2900 X%=1:CLG:MOVE 0,0
 1650 UNTIL State%=0    AND TIME>6
 1660 REPEAT
 1670   SYS K8055_ReadDigitalChannel%,Port% TO State%
 1680   IF G%=1 X%+=1:PLOT 5,X%/S%,State%*222 :IF X%/S%>2900 X%=1:CLG:MOVE 0,0
 1690 UNTIL State%=1    AND TIME>6
 1700 TIME=0
 1710 REPEAT
 1720   REPEAT
 1730     SYS K8055_ReadDigitalChannel%,Port% TO State%
 1740     IF G%=1 X%+=1:PLOT 5,X%/S%,State%*222 :IF X%/S%>2900 X%=1:CLG:MOVE 0,0
 1750   UNTIL State%=0  AND TIME>6
 1760   High%=TIME
 1770   SYS K8055_WriteAllDigital%,128
 1780   TIME=0
 1790   REPEAT
 1800     SYS K8055_ReadDigitalChannel%,Port% TO State%
 1810     IF G%=1 X%+=1:PLOT 5,X%/S%,State%*222 :IF X%/S%>2900 X%=1:CLG:MOVE 0,0
 1820   UNTIL State%=1  AND TIME>50
 1830   Low%=TIME
 1840   SYS K8055_WriteAllDigital%,64
 1850   PRINTTAB(21,Tab5%)"High:  ";High%;"    Low:  ";
 1860   IF Low%<10 PRINT" ";
 1870   PRINT;Low%;"   Both:  ";High%+Low%;"  "
 1880   TIME=0
 1890   PROCcheck_keyboard
 1900 UNTIL Low%>130
 1910 C%=0
 1920 ENDPROC
 1930
 1940
 1950 DEFPROCdecode(C%)
 1960 REM Minute
 1970 IF C%=27 THEN
 1980   Minute%=40*Time%(27)+20*Time%(26)+10*Time%(25)+8*Time%(24)+4*Time%(23)+2*Time%(22)+Time%(21)
 1990   PRINTTAB(78,Tab4%);"Minute: ";Minute%
 2000 ENDIF
 2010
 2020 REM hour
 2030 IF C%=34 THEN
 2040   Hour%=20*Time%(34)+10*Time%(33)+8*Time%(32)+4*Time%(31)+2*Time%(30)+Time%(29)
 2050   PRINTTAB(67,Tab4%);"Hour: ";Hour%
 2060 ENDIF
 2070
 2080 REM Day
 2090 IF C%=41 THEN
 2100   Day%=20*Time%(41)+10*Time%(40)+8*Time%(39)+4*Time%(38)+2*Time%(37)+Time%(36)
 2110   PRINTTAB(46,Tab4%);"Day: ";Day%;" "
 2120 ENDIF
 2130
 2140 REM Day of week
 2150 IF C%=44 THEN
 2160   DoW%=4*Time%(44)+2*Time%(43)+Time%(42)
 2170   IF DoW%<8 PRINTTAB(56,Tab4%);Weekday$(DoW%)
 2180 ENDIF
 2190
 2200 REM Month
 2210 IF C%=49 THEN
 2220   Month%=10*Time%(49)+8*Time%(48)+4*Time%(47)+2*Time%(46)+Time%(45)
 2230   IF Month%<13 THEN PRINTTAB(33,Tab4%);Month$(Month%)
 2240 ENDIF
 2250
 2260 REM The year
 2270 IF C%=57 THEN
 2280   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)
 2290   PRINTTAB(21,Tab4%);"Year: ";Year%
 2300 ENDIF
 2310
 2320 PRINTTAB(21+C%*2,Tab2%);Time%(C%);" "
 2330 IF C%=58 PRINTTAB(138,Tab2%)"    "
 2340 PRINTTAB(90,Tab4%);"Second: ";C%;"   "
 2350 ENDPROC
 2360
 2370
 2380 DEFPROCcheck_for_inversion
 2390 LOCAL Low%,High%
 2400 Low%=0: High%=0
 2410 PRINTTAB(21,0)"Please wait for 3 seconds to check for signal inversion"
 2420 SYS K8055_CloseDevice%
 2430 SYS K8055_OpenDevice%,Board%
 2440 PRINT
 2450 REPEAT
 2460   SYS K8055_ReadDigitalChannel%,Port% TO State%
 2470 UNTIL State%=1 AND TIME>4
 2480 FOR J%=1 TO 3
 2490   TIME=0
 2500   REPEAT
 2510     SYS K8055_ReadDigitalChannel%,Port% TO State%
 2520   UNTIL State%=0 AND TIME>4
 2530   High%+=TIME
 2540   TIME=0
 2550   REPEAT
 2560     SYS K8055_ReadDigitalChannel%,Port% TO State%
 2570   UNTIL State%=1 AND TIME>4
 2580   Low%+=TIME
 2590 NEXT
 2600 CLS
 2610 IF Low%>High% Invert%=1 ELSE Invert%=0
 2620 IF Invert%=1 PRINTTAB(21,0)"Inverted signal"
 2630 IF Invert%=0 PRINTTAB(21,0)"Non-inverted signal"
 2640 ENDPROC
 2650
 2660
 2670 DEFPROCport_setup
 2680 PROCwindow(1500,520,"DCF77 atomic clock decoder")
 2690 VDU 28,0,16,185,0
 2700 VDU 24,40;40;2940;390;
 2710 COLOUR12,60,60,60
 2720 GCOL 140
 2730 CLG
 2740 ORIGIN 40,50
 2750 VDU5
 2760 MOVE 0,330
 2770 PRINT" To stop or start plotting press 'G' for possibly up to a second"
 2780 PRINT" Press 1 to 5 to change the time-base"
 2790
 2800 VDU 23,23,1;0;0;0; :REM Lines double thickness
 2810 GCOL11
 2820 MOVE 0,0
 2830 X%=1
 2840 OFF
 2850 VDU4
 2860 ENDPROC
 2870
 2880
 2890 DEFPROCinit
 2900 Tab1% = 10
 2910 Tab2% = 9
 2920 Tab3% = 8
 2930 Tab4% = 6
 2940 Tab5% = 4
 2950 Tab6% = 13
 2960 Bit%=5
 2970 Port%=4
 2980 Board%=0
 2990 G%=1
 3000 S%=4
 3010 Col1%=15 : REM White
 3020 Col2%=6  : REM Cyan
 3030 Col3%=3
 3040 DIM Time%(100)
 3050 DIM Weekday$(7)
 3060 Weekday$(1)="Monday   "
 3070 Weekday$(2)="Tuesday  "
 3080 Weekday$(3)="Wednesday"
 3090 Weekday$(4)="Thursday "
 3100 Weekday$(5)="Friday   "
 3110 Weekday$(6)="Saturday "
 3120 Weekday$(7)="Sunday   "
 3130
 3140 DIM Month$(12)
 3150 Month$(1)="January  "
 3160 Month$(2)="February "
 3170 Month$(3)="March    "
 3180 Month$(4)="April    "
 3190 Month$(5)="May      "
 3200 Month$(6)="June     "
 3210 Month$(7)="July     "
 3220 Month$(8)="August   "
 3230 Month$(9)="September"
 3240 Month$(10)="October  "
 3250 Month$(11)="November "
 3260 Month$(12)="December "
 3270
 3280 ENDPROC
 3290
 3300
 3310 DEFPROCwindow(WindowWidth%,WindowHeight%,Wt$)
 3320 MODE 30
 3330 SYS "SetWindowPos",@hwnd%,0,0,0,WindowWidth%,WindowHeight%,6
 3340 COLOUR 128
 3350 CLS
 3360 COLOUR 15
 3370 VDU 26
 3380 SYS "SetWindowText",@hwnd%,Wt$
 3390 ENDPROC
 3400
 3410
 3420 DEFPROCerror
 3430 PRINT REPORT$;" at line ";ERL  :
 3440 SYS K8055_ClearAllDigital%,1
 3450 SYS K8055_ClearAllAnalog%,1
 3460 SYS K8055_CloseDevice%,1
 3470 SYS "FreeLibrary",K8055_Board%
 3480 END
 3490 ENDPROC
 3500
 3510
 3520 DEFPROCK8055_init
 3530 REM  Typing errors in routine name do not generate an error message - they just hang up the program.
 3540 REM  These are all the system calls in the order found in the manual
 3550 SYS"LoadLibrary","K8055D.dll" TO K8055_Board%
 3560 SYS"GetProcAddress",K8055_Board%,"OpenDevice" TO K8055_OpenDevice%
 3570 SYS"GetProcAddress",K8055_Board%,"CloseDevice" TO K8055_CloseDevice%
 3580 SYS"GetProcAddress",K8055_Board%,"ReadAnalogChannel" TO K8055_ReadAnalogChannel%
 3590 SYS"GetProcAddress",K8055_Board%,"ReadAllAnalog" TO K8055_ReadAllAnalog%
 3600 SYS"GetProcAddress",K8055_Board%,"OutputAnalogChannel" TO K8055_OutputAnalogChannel%
 3610 SYS"GetProcAddress",K8055_Board%,"OutputAllAnalog" TO K8055_OutputAllAnalog%
 3620 SYS"GetProcAddress",K8055_Board%,"ClearAnalogChannel" TO K8055_ClearAnalogChannel%
 3630 SYS"GetProcAddress",K8055_Board%,"ClearAllAnalog" TO K8055_ClearAllAnalog%
 3640 SYS"GetProcAddress",K8055_Board%,"SetAnalogChannel" TO K8055_SetAnalogChannel%
 3650 SYS"GetProcAddress",K8055_Board%,"SetAllAnalog"  TO K8055_SetAllAnalog%
 3660 SYS"GetProcAddress",K8055_Board%,"WriteAllDigital" TO K8055_WriteAllDigital%
 3670 SYS"GetProcAddress",K8055_Board%,"ClearDigitalChannel" TO K8055_ClearDigitalChannel%
 3680 SYS"GetProcAddress",K8055_Board%,"ClearAllDigital" TO K8055_ClearAllDigital%
 3690 SYS"GetProcAddress",K8055_Board%,"SetDigitalChannel" TO K8055_SetDigitalChannel%
 3700 SYS"GetProcAddress",K8055_Board%,"SetAllDigital"  TO K8055_SetAllDigital%
 3710 SYS"GetProcAddress",K8055_Board%,"ReadDigitalChannel" TO K8055_ReadDigitalChannel%
 3720 SYS"GetProcAddress",K8055_Board%,"ReadAllDigital"  TO K8055_ReadAllDigital%
 3730 SYS"GetProcAddress",K8055_Board%,"ResetCounter"  TO K8055_ResetCounter%
 3740 SYS"GetProcAddress",K8055_Board%,"ReadCounter"  TO K8055_ReadCounter%
 3750 SYS"GetProcAddress",K8055_Board%,"SedtCounterDebouceTime"  TO K8055_SetCounterDebounceTime%
 3760 ENDPROC
 3770


Return to interfacing index


Back to the start
Tudor with sign