Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 12:36 20 Sep 2026 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : [MM2]DCF77 Decoder

Author Message
twofingers

Guru

Joined: 02/06/2014
Location: Germany
Posts: 1772
Posted: 01:56pm 10 Feb 2019
Copy link to clipboard 
Print this post

This is yet another DCF77 Decoder.
I fear it will only interest Europeans. Because of
  Quote  DCF77 is a German longwave time signal and standard-frequency radio station.
DCF77 on Wikipedia

The code is well commented and tested.
I used a very old (~30 years?) DCF77 module from Conrad Electronics in germany.



The red LED is pulsing at 1 Hz and indicates the DCF77 signal.
My module is connected to the MM2 with a 2m telephone cable.



'****************************************************
'*
'* Yet another DCF77-Decoder for MicroMites, Version 1.0
'*
'* System: MMBasic 5.0
'* Micromite 2 (PIC32MX170/28, Micks BP170 + 2.8" TFT)
'* by twofingers 1-2019 at TBS
'* --------------------------
'* f. Conrad-Modul
'* Pin1=GND Pin2=5V or 3.3V
'* Out=inverting output=Pin3 (connected to the MM with a 2m cable)
'*
'* LED (+2.7k) from Pin3 to Pin2
'* to make the 1 Hz pulses visible
'* --------------------------
'* MM Input = DCFPIN
'* --------------------------
'* Note:
'* In order to have a reliable result, at least
'* two successive times should be determined
'*
'* Ignored:
'* Summer time announcement (bit 16)
'* Leap second announcement (bit 19)
'*
'* https://en.wikipedia.org/wiki/DCF77
'*----------------------------------------------------
' This code may be freely distributed and changed.
' Provided AS IS without any warranty.
' Use it at your own risk. All information is provided for
' educational purposes only!
'------------------------------------------------------
' ++++++ Credit to Geoff for his great MMBasic ++++++
'******************************************************

Option EXPLICIT

Dim As integer pass=0
Dim As integer tGap(60) 'tGap() = Gap_length
Dim As integer DCF(60)'DCF-Telegramm in Bitform
' reverse bit order = least significant bit goes first.
Dim WT$(7) 'Weekdays
WT$(1)="Monday"
WT$(2)="Tuesday"
WT$(3)="Wednesday"
WT$(4)="Thursday"
WT$(5)="Friday"
WT$(6)="Saturday"
WT$(7)="Sunday"

Dim DST$(2) = ("","CET","CEST") 'german: MEZ,MESZ=Sommerzeit
Dim DCF_date$, DCF_time$

Dim VT100_Cup$=Chr$(27)+"[1A" 'VT100 Cursor up
Dim VT100_Del$=Chr$(27)+"[2K" 'VT100 erase cursorline

Const DCFPIN=15
Const TRUE=1, FALSE=0
Const THRESHOLD=150 'gap length threshold, between 100ms and 200ms
Const TOLERANCE=50
Const min_pw=1000-TOLERANCE
Const max_pw=1000+TOLERANCE 'limits of period duration of sec cycle
Const min_mmark=2000-TOLERANCE
Const max_mmark=2000+TOLERANCE 'limits of period duration of minute mark

Dim As integer BitN 'Sec_index
Dim As integer tSec 'tSec=Period length, rising edge to rising edge
Dim As integer SyncOK 'Minute mark found!
Dim As integer DCF_Time_OK=FALSE
Dim As integer DCF_error =FALSE


Do '***** Begin Main Loop ******
pass=pass+1
BitN=0
tSec=0
SyncOK=FALSE

SetPin DCFPIN,INTH,HiLevel

Print
Print "MM DCF77 Decoder V1.0 "Time$, "Pass: "pass
Print

Timer=0

' Let's see if we have a 1000ms pulse (1 Hz) signal
' The interrupt does the job. tSec=time of one period of the 1 Hz DCF signall
Do
Print "Waiting for 1 Hz Signal (1 cycle/1000ms) ",Str$(tSec,4)"ms";VT100_Cup$
Loop Until InRange(tSec,min_pw,max_pw)
' now we have probably a DCF77 signal
' Note: The better it matches the 1000 ms, the better the signal quality
Print VT100_Del$+"DCF77 signal available ... "
DCF_error=FALSE

Do '****************
If InRange(tSec,min_mmark,max_mmark) Then ' we found a 2000ms period
BitN=0:SyncOK=1:tSec=0
Print
Print "Minute mark found! Collecting DCF77 data ..."
Print "0 1 2 3 4 5 6 x10"
Print;
' Sub LoLevel does the job
EndIf
If BitN=59 And SyncOK=1 Then ' seems we are complete
DCF_error = Not DCF77_readout()
Exit Do
EndIf
If BitN >59 Then ' uff! No sync found. Let's start again ...
Print
Print "Error: Minute mark not found "
Exit Do
EndIf
If DCF_error Then
Print
Print "Error: DCF_error (Signal)"
Exit Do
EndIf
Loop

Loop While Not DCF_Time_OK'***** End Main Loop ******

' copy the DCF time into the MM if you like
'time$=DCF_time$
'date$=DCF_date$

End'--------------------------------------------------------

'* TWO interrupt routines

'* Setpin interrupt sub to detect the rising edge,
'* the time of one cycle, tSec = ~1000ms or ~2000ms
Sub HiLevel
SetPin DCFPIN,INTL,LoLevel
tSec=Timer:Timer=0
If tSec<min_pw Then DCF_error=TRUE 'we lost the DCF signal?
End Sub

'* Setpin interrupt sub to detect the falling edge
'* we get the gap length - tGap() = ~100 or ~200ms
Sub LoLevel ' Setpin interrupt sub, high to low
SetPin DCFPIN,INTH,HiLevel
tGap(BitN)=Timer
If SyncOK Then
Print Str$(tGap(BitN)>threshold,1);
Else
Print "Searching for minute mark" BitN, Str$(tSec,4)"ms"; VT100_Cup$
EndIf
If BitN<60 Then BitN=BitN+1 'just in case to prevent overflow
End Sub


' let's see what the DCF telegram says
' ****** readout, takes about 46ms ******
Function DCF77_readout()
Local min, hour, day, mon, year, i, tAs integer
Local weekday$

SetPin DCFPIN,OFF 'interrupt disable

' convert pulse widths (i.e. gaps) to bits
For i= 0 To 58
DCF(i)= tGap(i) >threshold
Next

DCF77_readout = TRUE
Print
' Some error checks:
' Bit 0 must be 0
' Bit20 must be 1
' Bit17 = not Bit18
If DCF(0)<>0 Then DCF77_readout = FALSE:Print "E1":Exit Function
If DCF(20)<>1 Then DCF77_readout = FALSE:Print "E2":Exit Function
If DCF(17)<>Not DCF(18) Then DCF77_readout = FALSE:Print "E3":Exit Function
' Parity check
If Parity(21,28) Or Parity(29,35) Or Parity(36,58) Then
DCF77_readout = FALSE
Print "E4"
Exit Function
EndIf

min = BCD_Sum(21,27)
hour = BCD_Sum(29,34)

day = BCD_Sum(36,41)
weekday$=wt$(BCD_Sum(42,44))

mon = BCD_Sum(45,49)
year = BCD_Sum(50,57)

DCF_date$=Str$(day,2,0,"0")+"-"+Str$(mon,2,0,"0")+"-"+Str$(2000+year,4,0,"0")
DCF_time$=Str$(hour,2,0,"0")+":"+Str$(min,2,0,"0")+":"+"00"

If ValidTime(DCF_time$) Then
Print "Success!"
Print DCF_date$,DCF_time$, weekday$, DST$(DCF(17)+1)
DCF_Time_OK=TRUE
Else
Print "DCFtime INVALID!"
DCF_Time_OK=FALSE
EndIf
Print String$( 80,"_")
' Print:Print "Press <Space> to continue"
' Do: Loop Until Inkey$ = " "
End Function


' check the parity
Function Parity(a,b) As integer
Local p,i
p=0
For i = a To b
p = p + DCF(i)
Next
Parity = p Mod 2
End Function


' Converts DCF() bits from BCD to decimal (max 9bit)
Function BCD_Sum(a,b) As integer
Local As integer bcd(9) = (0,1,2,4,8,10,20,40,80,100), i
For i = a To b
BCD_Sum = BCD_Sum + DCF(i)*bcd(i-a+1)
Next
End Function


Function ValidTime(tm$) As integer
Local legal(3)=(0,23,59,59), i As integer
ValidTime=TRUE
For i = 1 To 7 Step 3 '1,4,7
If Val(Mid$(tm$,i,2))>legal(i\3+1) Then ValidTime=FALSE: Exit For
Next i
End Function


Function InRange(x,min,max) As integer
InRange = x>=min And x<= max
End Function


' rBCD2Dec() converts a part of an array of bit numbers BCD to decimal,
' reverse bit order = least significant bit goes first.
' e.g. dcf(7)=(1,1,1,0,0,0,1,0) = 47
' // not used in this program //
Function rBCD2Dec(a,b) As integer
Local As integer i, d=1
Do
For i = 0 To 3
rBCD2Dec = rBCD2Dec + DCF(a)*2^i*d
If a=b Then Exit Do
a=a+1
Next
d=d*10
Loop
End Function



2019-02-10_233412_mm_dcf77.zip

Any comments welcome.
Regards
Michael

‚My name is Ozymandias, king of kings
Look on my works, ye Mighty, and despair!‘
Nothing beside remains. Round the decay
Of that colossal wreck, boundless and bare
The lone and ...
 
Frank N. Furter
Guru

Joined: 28/05/2012
Location: Germany
Posts: 1153
Posted: 07:25pm 10 Feb 2019
Copy link to clipboard 
Print this post

Hi Michael,

thanks a lot!!!
My last DCF77 receiver I programmed under PBP over 10 years ago (with the same Conrad module) and it works since then in a roller blind control of my parents. I had long intended to realize a DCF77 clock with a Micromite - you came before me!
THANKS!

Frank
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2026