RTC Clock Setter using GPS

neiltechspec

Senior Member
Many of my projects use RTC Clock Modules, either DS1307's or DS3231's.

I got fed up with try to set the time from the PC and could only get within 3 or 4 secs, so came up with this today.

Uses a ublox NEO-6 GPS Module PICAXE 28X2. Needs an X1 or X2 chip for the bit shifting capabilities (maybe possible on a M2 series but I couldn't work out how).

Using GPS strings - GPRMC, GPGGA & GPZDA, at the push of a button, if Sat Lock is ok, writes the time & date (time in GMT) to the RTC module.

Time is set within half a second accuracy or better I reckon.

Neil.

Code:
#rem

This program sets a DS1307 or DS3231 using a GPS clock source.
Needs an X1 or X2 PICAXE for shifting bits left capability.

Initial Version 1.0, August 2014

Ublox NEO-6 set to output @ 9600 baud the following messages :-

$GPRMC,164757.00,A,5234.07991,N,00149.09098,W,0.400,,250714,,,A*67
$GPVTG,,T,,M,0.400,N,0.741,K,A*25
$GPGGA,164757.00,5234.07991,N,00149.09098,W,1,11,1.52,130.6,M,47.9,M,,*42
$GPGLL,5234.07991,N,00149.09098,W,164757.00,A,A*7F
$GPZDA,164757.00,25,07,2014,00,00*67
     
pin A.0 is OLED / LCD display
pin B.0 is BST switch (active high)
pin A.1 is TTL serial in from GPS Module @ 9600,8,n,1
pin A.3 is TTL serial out to GPS Module (not used)
pin C.0 is LED - 330R to 0v
pin C.1 is RTC set button (active low)
pin C.2 is true TTL serial out @ 9600,8,n,1 (for Serial to IP)
pin C.3 is I2C scl for RTC
pin C.4 is I2C sda for RTC

#endrem

#picaxe 28X2
#no_data
#terminal 19200

symbol seconds	= b20
symbol mins		= b21
symbol hour		= b22
symbol day		= b23
symbol date		= b24
symbol month	= b25
symbol year		= b26
symbol control	= b27
symbol oled		= A.0
symbol GPSin 	= A.1
symbol IPout	= C.2
symbol dbaud	= N2400_16 ;display baudrate
symbol iobaud	= T9600_16 ;I/O baudrate


Init:
	pullup %00000001			;enable pullup on port B.0 for BST switch (only port B has pullup capability)
	
	setfreq m16				;runs at 16Mhz for reliable capture @ 9600 baud
	
	pause 12000				;3sec pause for LCD Display init
	serout oled,dbaud,(254,1) 	;clear display 
	pause 200 				;50ms pause
	
	hi2csetup i2cmaster, %11010000, i2cslow_16, i2cbyte ;set RTC slave address
	
Main:
	do
	
	serin GPSin,iobaud,("$GPRMC,"),b1,b2,b3,b4,b5,b6,b7,b7,b7,b7,b7
	serin GPSin,iobaud,("$GPGGA,"),b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b9
	serin GPSin,iobaud,("$GPZDA,"),b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19
	
	if b7="V" then			;gps rx data not locked
	 high C.0				;turn on LED
	 serout oled,dbaud,(254,192,"No Sat Lock     ")
	 serout IPout,iobaud,("No Sat Lock",cr,lf)
	 sertxd("No Sat Lock",cr,lf,cr,lf)
	endif

	if pinC.1 <> 1 and b7="A" then
	 gosub Set_RTC
	endif
	
	sertxd("GPS time: ",b1,b2,":",b3,b4,":",b5,b6," GMT",cr,lf)
	
	if pinB.0=1 then
	 gosub BST
	endif
	
	serout oled,dbaud,(254,128,b1,b2,":",b3,b4,":",b5,b6)	;GPS Time, GMT or BST
	serout IPout,iobaud,(b1,b2,":",b3,b4,":",b5,b6,cr,lf)
			
	if b7="A" then	;if sat lock ok, show date, lat, long & No of Sat's
	 
	 low C.0
	 
	 pulsout C.0,400	;flash LED on C.0
	 
	 serout oled,dbaud,(254,138,b10,b11,"/",b13,b14,"/",b16,b17,b18,b19)	;GPS date
	 serout IPout,iobaud,(b10,b11,"/",b13,b14,"/",b16,b17,b18,b19,cr,lf)
	 sertxd("GPS Date: ",b10,b11,"/",b13,b14,"/",b16,b17,b18,b19,cr,lf)
	
	 serout oled,dbaud,(254,192,"Sat's: ",b8,b9)					;Sat's tracked
	 serout IPout,iobaud,("Sat's: ",b8,b9,cr,lf)
	 
       calibadc10 w24
	 w20 = 10486/w24
	 bintoascii w20,b42,b43,b44
	
	 serout oled,dbaud,(254,201," Batt: ",b43,".",b44,"v")
	 serout IPout,iobaud,("Batt: ",b43,".",b44,"v",cr,lf,cr,lf)
	 
	endif
	
	gosub RTC

	loop
	
RTC:
	hi2cin $0,(seconds,mins,hour,day,date,month,year)
	
	bcdtoascii seconds,b30,b31
	bcdtoascii mins,b32,b33
	bcdtoascii hour,b34,b35
	bcdtoascii date,b36,b37
	bcdtoascii month,b38,b39
	bcdtoascii year,b40,b41
	
	serout oled,dbaud,(254,148,"RTC Date & Time  GMT")
	
	if b30 = "?" then
	 serout oled,dbaud,(254,212,"RTC Module not Found")
	 sertxd("RTC Module not Found",cr,lf)
	 return
	endif 

	serout oled,dbaud,(254,212,b34,b35,":",b32,b33,":",b30,b31)		 ;RTC Time
	sertxd("RTC Time: ",b34,b35,":",b32,b33,":",b30,b31," GMT",cr,lf)
	
	serout oled,dbaud,(254,220,"  ",b36,b37,"/",b38,b39,"/20",b40,b41) ;RTC Date
	sertxd("RTC Date: ",b36,b37,"/",b38,b39,"/20",b40,b41,cr,lf,cr,lf)
	
	return
	
Set_RTC:
      serout oled,dbaud,(254,192,"*** Setting RTC *** ")
	
	let b5 = b5 -48		;secs tens
	let b6 = b6 -48		;secs units
	let b3 = b3 -48		;mins tens
	let b4 = b4 -48		;mins units
	let b1 = b1 -48		;hours tens
	let b2 = b2 -48		;hours units
	let b10 = b10 -48		;date tens
	let b11 = b11 -48		;date units
	let b13 = b13 -48		;month tens
	let b14 = b14 -48		;month units
	let b18 = b18 -48		;year tens
	let b19 = b19 -48		;year units
 	      
	let seconds = b5 << 4 + b6
	let mins 	= b3 << 4 + b4
	let hour 	= b1 << 4 + b2
	let day 	= $01		;01 day of week (not used by me)
	let date 	= b10 << 4 + b11
	let month 	= b13 << 4 + b14
	let year 	= b18 << 4 + b19
	let control = %00010000 ;Enable output at 1Hz
	
	hi2cout 0,(seconds,mins,hour,day,date,month,year,control)
	
	pause 4000				;1sec pause
	
	serout oled,dbaud,(254,1) 	;clear display 
	pause 200 				;50ms pause

	goto main
	
BST:
	inc b2							;add 1 to b2 value
	
	if b2=58 then let B2=48 inc b1 endif		;if b2 > "9", set it to "0" and add 1 to b1 
	if b1=50 and b2=52 then let b1=48 b2=48 endif	;if b1="2" and b2="4", set them both to "0"
	
	return
 

techElder

Well-known member
Looks like a great project to add to any number of projects that have a clock built in.

I do wish you had created symbols for the rest of your byte variables. It will take some analysis to figure out the logic of your program.
 

neiltechspec

Senior Member
Aint gonna happen.

Just wanted something quick for doing the job. It will be filed away & just pulled out when needed.

Has enough comments to remind me what connects to what. Will probably get re-jigged for a 20X2 anyway as a 28X2 is a waste for this.

Neil.
 

neiltechspec

Senior Member
Revamped for a 20X2.

Code:
#rem

This program sets a DS1307 or DS3231 using a GPS clock source.
Needs an X1 or X2 PICAXE for shifting bits left capability.

V1.0 initial version based on 28X2, August 2014
V2.0 re-written for 20X2, August 2014

Ublox NEO-6 set to output @ 9600 baud the following messages :-

$GPRMC,164757.00,A,5234.07991,N,00149.09098,W,0.400,,250714,,,A*67
$GPVTG,,T,,M,0.400,N,0.741,K,A*25
$GPGGA,164757.00,5234.07991,N,00149.09098,W,1,11,1.52,130.6,M,47.9,M,,*42
$GPGLL,5234.07991,N,00149.09098,W,164757.00,A,A*7F
$GPZDA,164757.00,25,07,2014,00,00*67
     
pin C.0 is TTL serial in from GPS Module @ 9600,8,n,1
pin C.1 is TTL serial out to GPS Module (not used at present)
pin C.2 is OLED / LCD Display
pin C.3 is RTC set button (active low)
pin C.4 is LED - 470R to 0v (optional)
pin C.5 is BST / GMT switch (high for BST)
pin B.7 is i2c scl for RTC
pin B.5 is i2c sda for RTC

#endrem

#picaxe 20X2
#no_data
#terminal 19200

symbol seconds	= b20
symbol mins		= b21
symbol hour		= b22
symbol day		= b23
symbol date		= b24
symbol month	= b25
symbol year		= b26
symbol control	= b27
symbol oled		= C.2
symbol GPSin 	= C.0
symbol GPSout	= C.1
symbol dbaud	= N2400_16 ;display baudrate
symbol iobaud	= T9600_16 ;I/O baudrate


Init:
	setfreq m16				;runs at 16Mhz for reliable capture @ 9600 baud
	
	pause 12000				;3sec pause for LCD Display init
	serout oled,dbaud,(254,1) 	;clear display 
	pause 200 				;50ms pause
	serout oled,dbaud,(254,1) 	;clear display
	serout oled,dbaud,(255,%00000000); is LCD backlight on
	pause 200 				;50ms pause
	
	hi2csetup i2cmaster,$d0, i2cslow_16, i2cbyte ;set RTC slave address
	
Main:
	do
	
	serin GPSin,iobaud,("$GPRMC,"),b1,b2,b3,b4,b5,b6,b7,b7,b7,b7,b7
	serin GPSin,iobaud,("$GPGGA,"),b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b8,b9
	serin GPSin,iobaud,("$GPZDA,"),b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19
	
	if b7="V" then			;gps rx data not locked
	 high C.4				;turn on LED
	 serout oled,dbaud,(254,192,"No Sat Lock     ")
	 sertxd("No Sat Lock",cr,lf,cr,lf)
	endif

	if pinC.3 <> 1 and b7="A" then
	 gosub Set_RTC
	endif
	
	sertxd("GPS time: ",b1,b2,":",b3,b4,":",b5,b6," GMT",cr,lf)
	
	if pinC.5=1 then
	 gosub BST
	endif
	
	serout oled,dbaud,(254,128,b1,b2,":",b3,b4,":",b5,b6)	;GPS Time, GMT or BST
			
	if b7="A" then	;if sat lock ok, show date, lat, long & No of Sat's
	 
	 low C.4
	 
	 pulsout C.4,400	;flash LED on C.4
	 
	 serout oled,dbaud,(254,138,b10,b11,"/",b13,b14,"/",b16,b17,b18,b19)	;GPS date
	 sertxd("GPS Date: ",b10,b11,"/",b13,b14,"/",b16,b17,b18,b19,cr,lf)
	
	 serout oled,dbaud,(254,192,"Sat's: ",b8,b9)					;Sat's tracked
	 
       calibadc10 w20
	 w20 = 10486/w20
	 bintoascii w20,b42,b43,b44
	
	 serout oled,dbaud,(254,201," Batt: ",b43,".",b44,"v")
	 
	endif
	
	gosub RTC

	loop
	
RTC:
	hi2cin $0,(seconds,mins,hour,day,date,month,year)
	
	bcdtoascii seconds,b30,b31
	bcdtoascii mins,b32,b33
	bcdtoascii hour,b34,b35
	bcdtoascii date,b36,b37
	bcdtoascii month,b38,b39
	bcdtoascii year,b40,b41
	
	serout oled,dbaud,(254,148,"RTC Date & Time  GMT")
	
	if b30 = "?" then
	 serout oled,dbaud,(254,212,"RTC Module not Found")
	 sertxd("RTC Module not Found",cr,lf)
	 return
	endif 

	serout oled,dbaud,(254,212,b34,b35,":",b32,b33,":",b30,b31)		 ;RTC Time
	sertxd("RTC Time: ",b34,b35,":",b32,b33,":",b30,b31," GMT",cr,lf)
	
	serout oled,dbaud,(254,220,"  ",b36,b37,"/",b38,b39,"/20",b40,b41) ;RTC Date
	sertxd("RTC Date: ",b36,b37,"/",b38,b39,"/20",b40,b41,cr,lf,cr,lf)
	
	return
	
Set_RTC:
      serout oled,dbaud,(254,192,"*** Setting RTC *** ")
	
	let b5 = b5 -48		;secs tens
	let b6 = b6 -48		;secs units
	let b3 = b3 -48		;mins tens
	let b4 = b4 -48		;mins units
	let b1 = b1 -48		;hours tens
	let b2 = b2 -48		;hours units
	let b10 = b10 -48		;date tens
	let b11 = b11 -48		;date units
	let b13 = b13 -48		;month tens
	let b14 = b14 -48		;month units
	let b18 = b18 -48		;year tens
	let b19 = b19 -48		;year units
 	      
	let seconds = b5 << 4 + b6
	let mins 	= b3 << 4 + b4
	let hour 	= b1 << 4 + b2
	let day 	= $01		;01 day of week (not used by me)
	let date 	= b10 << 4 + b11
	let month 	= b13 << 4 + b14
	let year 	= b18 << 4 + b19
	let control = %00010000 ;Enable output at 1Hz
	
	hi2cout 0,(seconds,mins,hour,day,date,month,year,control)
	
	pause 4000				;1sec pause
	
	serout oled,dbaud,(254,1) 	;clear display 
	pause 200 				;50ms pause

	goto main
	
BST:
	inc b2							;add 1 to b2 value
	
	if b2=58 then let B2=48 inc b1 endif		;if b2 > "9", set it to "0" and add 1 to b1 
	if b1=50 and b2=52 then let b1=48 b2=48 endif	;if b1="2" and b2="4", set them both to "0"
	
	return
Neil.
 

hippy

Technical Support
Staff member
Needs an X1 or X2 chip for the bit shifting capabilities (maybe possible on a M2 series but I couldn't work out how).
If that's for -

let seconds = b5 << 4 + b6

And similar, then 'x << 4' is the same as 'x * 16' so -

let seconds = b5 * 16 + b6
 
Top