• Pic® Basic


  • MSF Clock using a 16F628A & Symtrik RF module

    This article shows how the MSF time signal from Anthorn in the UK may be decoded and displayed. A Symtrik SYM-RFT-60 module is used to receive the 60kHz signal and a 16F628A employed to decode it. Both time and date are displayed on a standard 16*2 LCD. A DS1307 RTC acts as a backup for times when a valid MSF signal is unavailable.


    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
    Finally

    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!