Decoding UK's NPL MSF Time Signal

chigley

Senior Member
Sorry to be such a pain, but it's still not stable. I think this has always been a problem, even when I was powering it off AA batteries a week or so back.

After a few power cycles, it just stops working. I think the PICAXE is "locking up", although a power cycle (or reset pin grounded) doesn't solve the problem. To solve it, and make it work again, I have to reprogramme the PICAXE (with the exact same code) - as soon as the download finishes the LED starts flashing and all is hunky dory.

What could be causing it to lock up? I don't think I've made any silly connections on my board, but I can post a photo if you think that'd help. Circuit is as above, other than I'm running the MSF module at 3v as opposed to 1.5v.
 
Last edited:

hippy

Technical Support
Staff member
I'd also suggest sticking to 1V5. This is one of the problems with repurposing something which is a black blob 'silicon on chip" circuit; one quite simply doesn't know what that circuit is, its operational parameters and how far one can push it.

It is possible that the PICAXE program could lock-up ( haven't looked at the code for a long while ) and it is odd that a reset doesn't fix things when a fresh download does. I would doubt that it's the physical PICAXE locking-up but I don't have an explanation.

The program was written to be crammed into an 08M and it would be better to use a larger memory PICAXE and write the code to give better diagnostics or time reception ends up either working or not, and when not it's not easy to determine why not.
 

chigley

Senior Member
I'd also suggest sticking to 1V5. This is one of the problems with repurposing something which is a black blob 'silicon on chip" circuit; one quite simply doesn't know what that circuit is, its operational parameters and how far one can push it.

It is possible that the PICAXE program could lock-up ( haven't looked at the code for a long while ) and it is odd that a reset doesn't fix things when a fresh download does. I would doubt that it's the physical PICAXE locking-up but I don't have an explanation.

The program was written to be crammed into an 08M and it would be better to use a larger memory PICAXE and write the code to give better diagnostics or time reception ends up either working or not, and when not it's not easy to determine why not.
It's been running at 1V5 for the past hour or so, and appears to be far more stable :)
 
Great thread

Hi All

Great read everyone!! I just spent an hour or three avidly reading through this MSF. based thread. Being in to clocks as an hobby I am very interested.

Wanting to bump up to see if those who experimented have result info to offer, been sometime now since the last post!!

I am looking into a similar project advice.

The trouble with MSF. is down time and interference on the receiver.
For myself I am looking at creating a circuit that pulses out at- 1, 30 and 60 second intervals. The MSF. will only be used to synchronise the internal clock so if we loose the signal I still get an output,I then use this circuit for a timebase on my clockie projects.

I kn ow of only one similar project published on the web-

http://www.brettoliver.org.uk/masterclock.htm

I prefer a picaxe based Synchroniser!! But repect to Brett for his.

Anyone have any ideas.

Cheers
Mark
 
Last edited:
Hi All

Great read everyone!! I just spent an hour or three avidly reading through this MSF. based thread. Being in to clocks as an hobby I am very interested.

Wanting to bump up to see if those who experimented have result info to offer, been sometime now since the last post!!

I am looking into a similar project advice.

The trouble with MSF. is down time and interference on the receiver.
For myself I am looking at creating a circuit that pulses out at- 1, 30 and 60 second intervals. The MSF. will only be used to synchronise the internal clock so if we loose the signal I still get an output,I then use this circuit for a timebase on my clockie projects.

I kn ow of only one similar project published on the web-

http://www.brettoliver.org.uk/masterclock.htm

I prefer a picaxe based Synchroniser!! But repect to Brett for his.

Anyone have any ideas.

Cheers
Mark

Any results to offer.:)
 

g6ejd

Senior Member
This is the module I'm using:
http://www.pvelectronics.co.uk/index.php?main_page=product_info&cPath=9&products_id=2
Costs£6.95
Software above works fine, well I'm running it on an 18m so changed the input pin and interrupt mask and because the modules are not inverting the output from MSF change the code to reflect this.

I wil post the finished code in due course. I'm currently working on using the time signal to keep the picaxe 1307 real time clock in- time on a axe110 data logger which I think is the most versatile module sold.
 

srnet

Senior Member
Whilst I have fond memories of MSF, I once developed a Clock in PIC assembler that had a remote antenna connected by co-ax (to reduce computer & monitor generated interferance, thses days there are GPS units for around the same price, they output accurate time in this serial format;

$GPGGA,060535.334,,,,

i.e. 06:05:35.334 seconds ......

Although with the MSF clock, you can sync fairly accuratly using the edges of the timing pulses.
 

g6ejd

Senior Member
Hi Srnet, yes seen those, but 5x more expensive; yes easy to use, but for me no fun. I am just discovering the 'joys' of trying to Rx the MSF in my shack, lots of noise, even slightest change in antenna orientation makes a difference and quite a weak signal (in south of UK) since the Tx was moved to North of England and therefore requires what one might term a lot of signal processing. They could have left it in Rugby at little or no cost IMO.

I may after a few frustrating weeks of coding and fiddling, end up buying the GPS module :D
 

srnet

Senior Member
Well at 60Khz, you can use op amps and analogue filters ........

I built mine along the lines of the way sat antennas ghost the power up the co-ax, the ferrite rod and RF\AF amplifier bits were in a box that got its power and sent the signal back to the decoder via stanard RG58 co-ax. It allowed the antenna to be quite a long way from the nasty noisey computers and improved relaibility considerably.

And you will find GPS modules at well under £6.95 x 5 .
 

hamtech

Member
GP, I am trying to get your MSF decoding code to work on a 08M2 and a 18M2 but have not got it to run.

Please confirm that you have it working on both of the PicAxe chips. I am alittle confused by the pin numbering. If you run your code on an 18M2 for input pin it demands port pin etc. on the 08M2 it does not but pin 1 on the chip is positive volts so I assume you refer to the input pin 1 rather than chip pin. I am using a purpose bought little board for MSF decoding from PVR electronics. I have the input going high on no carrier.

On Hippy's msf decoder code I have same sort of trouble , I can't get his code to work either on the 8m2 chip. Same comment about input pins..



Can you clarify that the code works on both chips and b, what the pins should be on the code listing for each chip.

many thamks
Hamtech
 
Last edited:

g6ejd

Senior Member
Here' some code that includes parity checks and adjusts a RTC clock DS1307 when out of sync. Uses the AXE110 board:
Code:
' ********************
' ***** Symbols  *****
' ********************

symbol LCD     = 6
symbol BAUD    = N2400
symbol Line1   = 128
symbol Line2   = 192
symbol Line3   = 148
symbol Line4   = 212
symbol carrier_on    = 1 ' input pin state for carrier on
symbol carrier_off   = 0 '         ditto               off
symbol bit_time      = w0 '(b0 b1)
symbol address       = w0
symbol parity_test   = w0
symbol temp_word     = w1 '(b2 b3)
symbol ADVal         = w0
symbol year          = b4
symbol month         = b5
symbol day           = b6
symbol dofw          = b7
symbol hours         = b8
symbol mins          = b9
symbol secs          = b10
symbol bitA          = b11
symbol bitB          = b12
symbol i             = b13
symbol tempL         = b14
symbol nbits         = b14
symbol tempH         = b15
symbol rt_sec        = b16
symbol rt_mins       = b17
symbol rt_hours      = b18
symbol rt_day        = b19
symbol rt_date       = b20
symbol rt_month      = b21
symbol rt_year       = b22
symbol parity        = b23
symbol rx_parity     = b24
symbol parity_result = b10
symbol parity_flag   = b25
symbol press_adjust  = 180
symbol samples       = 10

' ***************************
' ***** Initialisation  *****
' ***************************
init:
	dirsB = 255 'setup Port-BG as outputs
	Pause 500
	SerOut LCD, BAUD,(254,1,254,14) 'Clear LCD
	Pause 50   'Wait for screen to clear
 	high 5     'write protect eeprom

' *********************************
' *** Main loop - Display data ****
' *********************************

main:
	gosub initialise ' all relevant variables
	
wait_for_start:
	do
        gosub receive_sec0
	loop while bit_time <= 42
	' Found SEC-00, denoted by start bit ~ 500mS
	gosub wait_for_data
	gosub read_year
	gosub read_month
	gosub read_day
	gosub read_dofw
	gosub read_hour
	gosub read_mins
'	gosub display_pressure
'	gosub display_humidity
	goto  wait_for_start
	
wait_for_data: ' Now skip 16-bits to get to bit-17 the start of the data for YEAR
	for i = 0 to 15
	  gosub receive_sec
	next i
	return
	
read_year:
	year = 0
	for i = 1 to 8
	  year = year * 2
	  gosub receive_sec
	  year = year + bitA AND $3F
	next i
	BCDTOASCII year,tempH, tempL
	serout LCD,BAUD,(254,201,"-20",tempH, tempL)
	return
	
read_month:
	month = 0
	for i = 1 to 5
	  month = month * 2
	  gosub receive_sec
	  month = month + bitA AND $1F
	next i
	BCDTOASCII month,tempH, tempL
	serout LCD,BAUD,(254,198,"-",tempH, tempL)
	return

read_day:
	day = 0
	for i = 1 to 6
	  day = day * 2
	  gosub receive_sec
        day = day + bitA AND $3F
      next i
      BCDTOASCII   day,tempH, tempL
	serout LCD,BAUD,(254,196,tempH, tempL)
	return

read_dofw:
	dofw = 0
	for i = 1 to 3
	  dofw = dofw * 2
	  gosub receive_sec
	  dofw = dofw + bitA AND $07
	next i
	serout LCD,BAUD,(254,192)
	if dofw = $00 then serout LCD,BAUD,("Sun") endif
	if dofw = $01 then serout LCD,BAUD,("Mon") endif
	if dofw = $02 then serout LCD,BAUD,("Tue") endif
	if dofw = $03 then serout LCD,BAUD,("Wed") endif
	if dofw = $04 then serout LCD,BAUD,("Thu") endif
	if dofw = $05 then serout LCD,BAUD,("Fri") endif
	if dofw = $06 then serout LCD,BAUD,("Sat") endif
	serout LCD,BAUD,(254,128)
	return
	
read_hour:
	hours = 0
	for i = 1 to 6
	  hours = hours * 2
	  gosub receive_sec
	  hours = hours + bitA
	next i
	return
	
read_mins:
	mins = 0
	for i = 1 to 7
	  mins = mins * 2
	  gosub receive_sec
	  mins = mins + bitA
	next i
	parity = 0
	' Now receive bits 52(1), 53(2), 54(3), 55(4), 56(5), 57(6), 58(7) and 59(8)
	gosub receive_sec 'Skip BIT-52B
	gosub receive_sec 'Skip BIT-53B
	gosub receive_sec 'Get  BIT-54B
      parity = parity OR bitB
      parity = parity * 2 ' shift parity bit in to parity word
      gosub receive_sec 'Get  BIT-55B
	parity = parity OR bitB
      parity = parity * 2' shift parity bit in to parity word
	gosub receive_sec 'Get  BIT-56B
	parity = parity OR bitB
      parity = parity * 2' shift parity bit in to parity word
	gosub receive_sec 'Get  BIT-57B
	parity = parity OR bitB ' no shift neded for LSB bit in to parity word
	'serout LCD,BAUD,("PB=",#parity)
	' Parity variable now has the 4 parity bits in the lower nibble.
    	gosub receive_sec 'Get  BIT-58B	
	gosub receive_sec 'Get  BIT-59B
	gosub read_RTC
	if hours <= $23 AND mins <= $59 AND parity_flag <> "*" then
   	  rx_parity = parity / 8 AND $01
	  parity_test = year
	  gosub test_parity
	  if parity_result = 1 then 'result is ODD
	    rx_parity = parity / 4 AND $01 ' Move the year parity bit down
	    parity_test = month * 256 + day
	    gosub test_parity
	    if parity_result = 1 then 'result is ODD
    	      rx_parity = parity / 2 AND $01
	      parity_test = dofw
	      gosub test_parity
	      if parity_result = 1 then
 	        rx_parity = parity AND $01
	        parity_test = hours * 256 + mins
	        gosub test_parity
	        if parity_result = 1 then
                if hours = rt_hours AND mins = rt_mins then
                  gosub write_RTC
                  rx_parity   = "*" ' Indicates all tests passed, RTC was updated
                  parity_flag = "*" ' Indicate on display that time was received correctly
                endif
              else
                rx_parity = "i" ' Indicates all test passed but not yet on a 30-min boundary e.g. 00, 30 etc
              endif
            endif
  	    endif  
        endif
      endif
     	if rx_parity <> "*" AND rx_parity <> "i" then
     	  rx_parity = "!"
     	endif
 	rx_parity = mins // 05 'Only allow time to be updated if on a 5-min boundary
	if rx_parity = 0 then
	  parity_flag = "!"
	endif
	BCDTOASCII hours,tempH,tempL
	serout LCD,BAUD,(254,128,tempH,tempL,":")
	BCDTOASCII mins, tempH,tempL
	serout LCD,BAUD,(tempH,tempL,"Hr")
	gosub display_RTC
	return

display_RTC:
	gosub read_RTC
	BCDTOASCII rt_hours, tempH, tempL
	serout LCD,BAUD,(254,140,tempH, tempL,":")
	BCDTOASCII rt_mins, tempH, tempL
	serout LCD,BAUD,(tempH, tempL,"Hr",parity_flag,254,128)
	return
	
test_parity:
      nbits = 0
      for i = 1 to 16
        parity_result = parity_test AND %00000001
        if parity_result = 1 then
          nbits = nbits + 1
        endif
        parity_test = parity_test / 2
	next i
  	parity_result = nbits + rx_parity AND $01
	return
	
receive_sec0:
      bitA = 0
      bitB = 0
	if pin0 = carrier_off then goto receive_sec0
	bit_time = 0
	do
	  pause 8 ' Ideally 10 but 8 takes account instruction delays, determined by a test of this section.
	  bit_time = bit_time + 1
	loop while pin0 = carrier_on
	gosub Flash_LED
	return

receive_sec:
	if pin0 = carrier_off then goto receive_sec
	Pause 160
	bitA = pin0 & $01
	Pause 100
	bitB = pin0 & $01
	gosub Flash_LED
	gosub display_RTC
	Pause 275
	return

initialise:
	year  = 0
	month = 0
	day   = 0
	dofw  = 0
	hours = 0
	mins  = 0 
	parity_flag = "!"
	SerOut LCD,BAUD,(254,1)
	Pause 400
	return
'
' END initialise

Flash_LED:
	High 3
	Pause 40
	Low  3
	Return
	
write_RTC:
	' Time has to be sent in BCD format to the clock
	i2cslave %11010000, i2cslow, i2cbyte
	'Format is  'secs,mins,hours,day, date,month,year, control - control byte is $10
	rt_sec = 0
	writei2c 0, (00,mins,hours,rt_day,rt_date,rt_month,rt_year,$10)
	return

read_RTC:
	' Format is secs,mins,hours,day,date,month,year
	i2cslave %11010000, i2cslow, i2cbyte
	readi2c 0, (rt_sec,rt_mins,rt_hours) ',rt_day,rt_date,rt_month,rt_year)
	return

' END OF PROGRAMME
'
 

g6ejd

Senior Member
SOme code ripped from an orginal by Hippy:
Code:
Symbol SIGNAL  = pin0       ' Signal Input Pin

Symbol ACTIVE  = 1          ' Active level ( 0 or 1 )
Symbol LCD     = 6
Symbol LED     = 3
Symbol BAUD    = N2400

Symbol bitA    = b2
Symbol bits    = b4
Symbol putPtr  = b5
Symbol bcd     = b6
Symbol bitVal  = b7
Symbol gapChar = b8
Symbol getPtr  = b10

Symbol INACTIVE = ACTIVE ^ 1
dirsB = 255 'setup Port-BG as outputs
Pause 5000
SerOut LCD, BAUD,(254,1,254,1,254,14) 'Clear LCD
Pause 500  'Wait for screen to clear
SerOut LCD, BAUD,("Waiting for signal>")
high 5      'write protect eeprom

DoRestart:
      
WaitForMinute:
  Do
    Gosub ReadBit
  Loop
  
StartMinute:
  putPtr = $50
  bits   = 16 :                              Gosub ReadBcd ' $50,$51 Unused bits  16
  bits   = 8  : bitVal = 8 : gapChar = "-" : Gosub ReadBcd ' $52,$53 Year bits    4+4
  bits   = 5  : bitVal = 1 : gapChar = "-" : Gosub Readbcd ' $54,$55 Month bits   1+4
  bits   = 6  : bitVal = 2 :                 Gosub ReadBcd ' $56,$57 Day bits     2+4
  bits   = 3  : bitVal = 4 :                 Gosub Readbcd ' $58,$59 DOW bits     3    
  bits   = 6  : bitVal = 2 : gapChar = ":" : Gosub ReadBcd ' $5A,$5B Hour bits    2+4
  bits   = 7  : bitVal = 4 : gapChar = ":" : Gosub Readbcd ' $5C,$5D Minutes bits 3+4   
  bits   = 8  :                              Gosub ReadBcd ' $5E,$5F Unused bits  8
  SerOut LCD,BAUD,(254,128,"20")     
  For getPtr = $50 To $5F
    putPtr = getPtr + $10
    Peek getPtr,bcd
    Poke putPtr,bcd
  Next
  For getPtr = $62 To $6C
    Peek getPtr,bcd
    If getPtr = $68 then
  	if bcd = 0 then serout LCD,BAUD,("Sun") endif
	if bcd = 1 then serout LCD,BAUD,("Mon") endif
	if bcd = 2 then serout LCD,BAUD,("Tue") endif
	if bcd = 3 then serout LCD,BAUD,("Wed") endif
	if bcd = 4 then serout LCD,BAUD,("Thu") endif
	if bcd = 5 then serout LCD,BAUD,("Fri") endif
	if bcd = 6 then serout LCD,BAUD,("Sat") endif
    ELSE
   	If bcd < 10 Then
        serout LCD, BAUD ,("0")
      EndIf
      serout LCD, BAUD ,(#bcd)
    Endif
    getPtr = getPtr+1
    Peek getPtr,gapChar
    If getPtr <> $6D then serout LCD,BAUD,(gapChar) endif
  Next
  serout LCD,BAUD,(254,128)
  Goto WaitForMinute

ReadBcd:
  bcd = 0
  Do 
    Gosub ReadBit
    bcd = bitVal * BitA + bcd
    bitVal = bitVal / 2
    bits = bits - 1
    If bits = 4 Then
      bcd = bcd * 10
      bitVal = 8
    End If
  Loop Until bits = 0
  Poke putPtr,bcd
  putPtr = putPtr+1
  Poke putPtr,gapChar
  putPtr = putPtr+1
  gapChar = " "
  Return
    
ReadBit:
  Do : Loop Until SIGNAL IS INACTIVE
  Do : Loop Until SIGNAL IS ACTIVE
  Pause  50
  If SIGNAL IS INACTIVE Then DoRestart
  Pause 100
  bitA = SIGNAL ^ INACTIVE
  Pause 100
  Pause 200
  If SIGNAL IS ACTIVE Then StartMinute
  'SerOut LCD, BAUD,(#bitA)
  GOSUB Flash_LED
  Return

Flash_LED:
   High LED
   Pause 40
   Low  LED
   Return
 

hamtech

Member
G6ejd many thanks will give that a try.

Your first example is exactly what I am trying to achieve on my timezone clock I have built, want to use MSF to keep the RTC qccurate and set automatically. So far I have failed using earlier posted code. Please confirm that " Symbol Signal = pin 0 " refers to logical input/output pin 0.
 

g6ejd

Senior Member
It's pin-0 of AXE110, so yes a logical pin-0, I can't remember what actual pin it is, see the axe110 data sheet. Good luck, both of these codes work BTW. The Radio clock has a positive output, so when I view it on my scope the 1-sec pulse is a positive pulse of that duration. It's become clear to me that most commericial implementations only do a time check once a day, usually at about 0200Hrs, which also favours 60Khz radio reception (night time for less absorption), I've found that passing all the parity checks is not 100% error free and when I monitor it continously it fals about 1 in 50 times. Hence do it at night.
 

hamtech

Member
It's pin-0 of AXE110, so yes a logical pin-0, I can't remember what actual pin it is, see the axe110 data sheet. Good luck, both of these codes work BTW. The Radio clock has a positive output, so when I view it on my scope the 1-sec pulse is a positive pulse of that duration. It's become clear to me that most commericial implementations only do a time check once a day, usually at about 0200Hrs, which also favours 60Khz radio reception (night time for less absorption), I've found that passing all the parity checks is not 100% error free and when I monitor it continously it fals about 1 in 50 times. Hence do it at night.


OK many thanks. Will use you code in the next few days, from reading the listing looks well commented and put together.
I assume Hippy code is still for the 08m2 chip....

Hamtech
 

hippy

Technical Support
Staff member
I assume Hippy code is still for the 08m2 chip....
I can't remember now exactly what I got working but it was pre-release of the M2. The code should work on an M2 but one would have to check the input pin type ( TTL or ST ) as that could have a bearing on things.

It is sometimes hard to get 'here it is' code to work or on something else, and you might have to take a step back to fundamental code ( such as Post #24 ) to try to determine what does work or not, build up from there.

Life will always be much easier with a digital scope or logic analyser that can show what the input signals are, otherwise you have to guess or presume what's being received. If something doesn't work you cannot easily tell if it's the code that is wrong or something else which means the code won't work as expected.
 

hamtech

Member
I can't remember now exactly what I got working but it was pre-release of the M2. The code should work on an M2 but one would have to check the input pin type ( TTL or ST ) as that could have a bearing on things.

It is sometimes hard to get 'here it is' code to work or on something else, and you might have to take a step back to fundamental code ( such as Post #24 ) to try to determine what does work or not, build up from there.

Life will always be much easier with a digital scope or logic analyser that can show what the input signals are, otherwise you have to guess or presume what's being received. If something doesn't work you cannot easily tell if it's the code that is wrong or something else which means the code won't work as expected.

Just to say a quick thank you. I have got the code working on a 20X2 with afull seconds display and a waiting for sysnc/ in sync message as appropriate too.

Thanks Guys
 
Old thread but has anyone explored generating an MSF time signal using a PICAXE?
There is a DCF77 implementation ( not pic based) and also a WWVB version but haven't seen anything for MSF.

Anyone tried this?

Nitrous
 

hippy

Technical Support
Staff member
Should be quite easy as the bits to send are well defined and only change every second or so. Calculate the 60 bits to send at the start of each minute and send them out. There's some awkwardness in the way the bits are mapped but the easiest thing there is to have all A bits consecutive followed by all B bits consecutive and then interleave them on output.

I only got halfway through doing it and can't find any example code.
 
Should be quite easy as the bits to send are well defined and only change every second or so. Calculate the 60 bits to send at the start of each minute and send them out. There's some awkwardness in the way the bits are mapped but the easiest thing there is to have all A bits consecutive followed by all B bits consecutive and then interleave them on output.

I only got halfway through doing it and can't find any example code.
Thanks for your comments Hippy.
Doug
 
Top