The MSF Protocol
There is much detailed information available on the Internet regarding the MSF protocol and consequently it is not my intention to repeat it here. That said, a short overview of the signal coming from Anthorn will help the reader understand what is happening within the program.
The signal transmitted from Anthorn uses a simple carrier on-off type of modulation. The presence of the carrier (radio signal) indicates logic 0 whilst logic 1 is represented by carrier absence. All the information required to display both the time and date is received within a one minute period.
It is useful to think of each second of transmission as being broken up into ten 100ms pieces, each representing a single bit. The beginning of each minute (second 00) is marked by 500ms of logic 1 followed by 500ms of logic 0. In other words the received data is %1111100000. The following seconds (01 – 59) are transmitted in the format %1AB0000000. The 1 seen at the beginning of this string is used as a second marker. The A and B bits are varied according to the value of the data being transmitted.
Seconds 1 to 16 are used to transmit DUT1 information. This is the difference between atomic and astronomical time and is not required by this application. Seconds 17 to 51 contain time and date information in binary coded decimal form. The remaining seconds (52 – 59) are used for a variety of things such as warning that summer time (BST) is in effect and parity error checking.
It should be understood that time and date information collected during one minute relates to the minute which follows it. To put it another way, during minute 30 (for example) information about minute 31 is being collected.
Program Description
Before giving a brief overview of how the program works it is useful for the reader to be aware that the Symtrik SYM-RFT-60 module inverts the MSF signal. In other words a logic 1 is represented by (approximately) +Vcc and 0 by (approximately) 0V
It is also important to understand that the values used in the Select DataIn case statements (i.e. Case 475 To 550) are based on a crystal frequency of 4MHz. Change the crystal value and you’ll need to alter the values used. See the Proton manual for further details.
After initialisation the program uses the PulsIn command to look for a positive going pulse on (in my case) PortB bit 3. What happens next is dependent on the length of the pulse detected.
Consider the case where the first pulse received is 500ms long. This is the start of the minute marker. The seconds counter (SecCnt) is set to 0 and the variable Flag is set to 1. This bit indicates that minute synchronisation has been achieved. As none of the conditions set out in the various case statements are true, the program moves towards the end where it encounters a BusIn command which reads the DS1307 RTC. The result of this read is then displayed on an LCD. A delay of 350ms is included at the end of the While – Wend loop and is important for two reasons. Firstly, it ensures that the PulsIn command at the top of the loop does not time out. Secondly, it masks any second pulse which might occur during seconds 1 – 16 as the result of bit B being set i.e. AB = 01.
During seconds 1-16 the program detects the 100ms pulse of the second marker and increments the SecCnt variable. The DUT1 data is not required and therefore never collected.
With the arrival of second 17, the program starts to retrieve the time and date data.
All relevant time and date variables are cleared before the start of second one. With each passing second a given bit of a particular variable will be set, or not, depending on the length of the pulse detected by the PulsIn command. A 200ms pulse causes a bit to be set, otherwise it is left untouched.
So take, for example, the year data stored in the Year variable. Information about the year is transmitted (MSB first) during seconds 17 – 24 inclusive. The data for 2014 would be stored as $14 or %00010100. During seconds 20 and 22 a 200ms pulse would be transmitted causing bits Year.4 and Year.2 to be set. The pulses relating to all other bits would only be 100ms in duration.
Once all the time and date information has been collected all subsequent data is ignored until second 54 is reached. At this point, and until second 57, parity error data is collected. The data collection process is identical to that described above except that a 300ms pulse is required to set any bit in the ChkSum variable.
At the end of second 59 the process begins again. However this time, because the Flag variable bit has been set, parity bits for the time and date data collected will be generated. These are then compared with those received during the previous minute. If the two agree, then the RTC is updated. If this is not the case, the RTC remains unchanged.
Code
Code:
'**************************************************************** '* Name : MSF Radio Clock * '* Author : Bob Marshall * '* Date : 03/01/2014 * '* Version : 1.0 * '* Notes : Compiler Version 3.5.6.2 * '* : The purpose of this program is to decode and * '* : display the RF time signal from MSF Anthorn, UK. * '* : A Symtrik SYM-RFT-60 module is used to receive * '* : the 60kHz signal and a 16F628A employed to decode * '* : and display both the time and date on a standard * '* : 16*2 LCD. Long wave RF signals, such as * '* : those from Anthorn, are sometimes subject to * '* : interference which can cause an erroneous * '* : display. In this version of the program correctly * '* : decoded time and date information is used to * '* : update a DS1307 RCT chip every second. Updating * '* : the RTC so frequently is hardly necessary, but in * '* : this case there is little else for the PIC to do. * '* : Of course the update frequency could be * '* : easily altered to suit other applications. The * '* : displayed time and date are read from the RTC. * '* : This has the advantage that when the RF signal is * '* : corrupted or missing, the displayed information * '* : remains correct. * '* : The MSF protocol employs a simple form of parity * '* : error checking. This is used to determine if the * '* : time and date information is good. * '* : No effort is made to decode the DUT1 (the * '* : difference between atomic and astronomical time) * '* : data. * '**************************************************************** ;------------------------------------------------------------------------------- ;**** Added by Fuse Configurator **** ; Use the Fuse Configurator plug-in to change these settings Device = 16F628A Config FOSC_XT, WDTE_OFF, PWRTE_ON, MCLRE_OFF, BOREN_ON, LVP_OFF, CPD_OFF, CP_OFF ;**** End of Fuse Configurator Settings **** ;------------------------------------------------------------------------------- Declare Xtal = 4 Declare LCD_Interface = 4 Declare LCD_DTPin PORTB.4 Declare LCD_ENPin PORTA.0 Declare LCD_RSPin PORTA.1 Declare LCD_Lines = 2 Declare LCD_Type = 0 Declare SDA_Pin PORTA.3 Declare SCL_Pin PORTA.2 Symbol ClockPin = PORTB.3 Symbol DS1307 = $D0 Dim DataIn As Word Dim DataVal As Byte Dim BitPtr As Byte Dim Flag As Bit Dim ChkSum As Byte Dim PCnt As Bit Dim CalcChkSum As Byte Dim Temp As Word ' These variables are used to collect incoming MSF time data. Dim Year As Byte Dim Month As Byte Dim DayOfMonth As Byte Dim DoW As Byte Dim Hour As Byte Dim Minute As Byte Dim SecCnt As Byte ' These variables are used to store the time from the RTC. Dim Yr As Byte Dim Mon As Byte Dim DoM As Byte Dim Day As Byte Dim Hr As Byte Dim Minit As Byte Dim Sec As Byte CMCON = 7 'All digital = true GoTo _Main '****************************************************************************** CalcParityBit: ' Check to see if the number of 1s is an odd or even number. ' PCnt = 0 indicates an even number of 1s. ' PCnt = 1 indicates an odd number of 1s. ' End loop when no 1s are left to count. ' Invert PCnt to produce correct parity bit. PCnt = 0 Repeat If Temp.0 = 1 Then Inc PCnt Temp = Temp >> 1 Until Temp = 0 PCnt = ~PCnt Return '****************************************************************************** _Main: Cls Print "-*-MSF Clock-*-" DelayMS 3000 Cls Clear While DataIn = PulsIn ClockPin,High DataIn = DataIn/100 Select DataIn Case 475 To 550 'Start of minute marker SecCnt = 0 If Flag = 1 Then 'Year parity Temp = Year GoSub CalcParityBit CalcChkSum.3 = PCnt 'Day parity Temp.Byte0 = Month Temp.Byte1 = DayOfMonth GoSub CalcParityBit CalcChkSum.2 = PCnt 'Day of week parity Temp = DoW GoSub CalcParityBit CalcChkSum.1 = PCnt 'Time Parity Temp.Byte0 = Minute Temp.Byte1 = Hour GoSub CalcParityBit CalcChkSum.0 = PCnt If ChkSum = CalcChkSum Then BusOut DS1307,0,[0,Minute,Hour,DoW,DayOfMonth,Month,Year] Print At 1,16,"U" 'Indicates the DS1307 has been updated. 'Included for diagnostic purposes. Remove 'if not needed. Else Print At 1,16,"E" 'DS1307 NOT updated due to checksum error. 'Included for diagnostic purposes. Remove 'if not needed. EndIf EndIf Year = 0:Month = 0:DayOfMonth = 0:Hour = 0:Minute = 0:DoW = 0 ChkSum = 0:CalcChkSum = 0:Temp=0:Flag = 1 Case 75 To 150 'AB bits = 00 Inc SecCnt DataVal = 0 Case 175 To 250 'AB bits = 10 Inc SecCnt DataVal = 1 Case 275 To 350 'AB bits = 11 Inc SecCnt DataVal = 3 EndSelect Select SecCnt Case 17 To 24 BitPtr = 24 - SecCnt If DataVal = 1 Then SetBit Year,BitPtr Case 25 To 29 BitPtr = 29 - SecCnt If DataVal = 1 Then SetBit Month,BitPtr Case 30 To 35 BitPtr = 35 - SecCnt If DataVal = 1 Then SetBit DayOfMonth,BitPtr Case 36 To 38 BitPtr = 38 - SecCnt If DataVal = 1 Then SetBit DoW,BitPtr Case 39 To 44 BitPtr = 44 - SecCnt If DataVal = 1 Then SetBit Hour,BitPtr Case 45 To 51 BitPtr = 51 - SecCnt If DataVal = 1 Then SetBit Minute,BitPtr Case 54 To 57 BitPtr = 57 - SecCnt If DataVal = 3 Then SetBit ChkSum,BitPtr EndSelect BusIn DS1307,0,[Sec,Minit,Hr,Day,DoM,Mon,Yr] Print At 1,1, "Time: ",Hex2 Hr,":", Hex2 Minit,":",Hex2 Sec Print At 2,1, "Date: ",Hex2 DoM,"/",Hex2 Mon,"/20",Hex2 Yr DelayMS 350 Wend
A couple of points worth noting. Firstly, if you're going to power the clock from the mains using a low voltage adapter (wall wart), be careful not to use one of the switched mode types. These create a lot of electrical noise which makes life difficult for the MSF receiver. Secondly, and for the same reason, testing the clock near a computer is not a good idea.
More information about the MSF time signal can be found here:-and here:-
Amazingly, the compiled code only takes up 886 bytes, a tribute to Proton's efficiency I suggest. It also leaves plenty of room to add additional features if you so wish!