I use a number of implementations of the DS1307 or DS3231 Real Time Clock chip, preferably the latter these days as they are considerably more accurate and compatible with DS1307 code.
In some applications, it is necessary or sometimes just better to preset the clock before connecting it into the application, and the need arises to set the clock ‘stand alone’. The method I have used for this has been clumsy and not as accurate as one might want for the DS3231, so this article describes a new solution.
The solution uses an Arduino as the engine if you like. Above is an Arduino Pro, but a range of similar Arduinos would be equally suitable. ALso pictured are three RTCs, one connected to pins A2, A3, A4 and A5 providing GND, VCC, SDA and CLK respectively.
The firmware implements a basic command interpreter with commands to set the clock and read it back.
#include <Time.h> #include <TimeLib.h> #include <DS1307RTC.h> #include <Wire.h> #include "Cmd.h" #define BAUD 57600 time_t t; tmElements_t tm; void setup() { //setup VCC and GND on a3, a2, SDA and CLK a4, a5 pinMode(16, OUTPUT); digitalWrite(16, LOW); pinMode(17, OUTPUT); digitalWrite(17, HIGH); Serial.begin(57600); Serial.print("DS1307RTC setting utility\n"); Serial.print("-------------------------\n\n"); cmdInit(); cmdAdd("setrtc", srtc); cmdAdd("getrtc", grtc); while (!Serial) ; // wait for serial delay(1000); cmdPoll(); } void loop() { cmdPoll(); delay(1000); } void print2digits(int number) { if (number >= 0 && number < 10) { Serial.print('0'); } Serial.print(number); } void srtc(int arg_cnt, char **args){ int yyyy,mm,dd,h,m,s; sscanf(args[1],"%4d%2d%2d%2d%2d%2d",&yyyy,&mm,&dd,&h,&m,&s); tm.Year=yyyy-1970; tm.Month=mm; tm.Day=dd; tm.Hour=h; tm.Minute=m; tm.Second=s; tm.Year=yyyy-1970; t = makeTime(tm); RTC.set(t); //use the time_t value to ensure correct weekday is set setTime(t); } void grtc(int arg_cnt, char **args){ if (RTC.read(tm)) { Serial.print("RTC: (HH:MM:SS) "); print2digits(tm.Hour); Serial.write(':'); print2digits(tm.Minute); Serial.write(':'); print2digits(tm.Second); Serial.print(" (YYYY/MM/DD) "); Serial.print(tmYearToCalendar(tm.Year)); Serial.write('/'); print2digits(tm.Month); Serial.write('/'); print2digits(tm.Day); Serial.println(); } else{ if (RTC.chipPresent()){ Serial.println("The DS1307 is stopped. Please run the SetTime"); Serial.println("example to initialize the time and begin running."); Serial.println(); } else{ Serial.println("DS1307 read error! Please check the circuitry."); Serial.println(); } } }
Above is the code, mostly derived from some various library examples.
Above is a screen shot of the serial monitor in Arduino IDE being used to set and read back the time.
A better idea is a script of some kind that sets the time from the workstation clock. There are a number of ways to do this, the following is an Expect script.
#!/usr/bin/expect #script to set KISS mode package require Expect encoding system iso8859-1 if {[lindex $argv 0] == ""} { # set port \\\\.\\COM12 set port /dev/ttyUSB0 } else { set port [lindex $argv 0] } set baud 57600 send_tty "Open port $port\n"; set com [open $port r+] fconfigure $com -mode $baud,n,8,1 -encoding binary -buffering none -translation binary set spawned [spawn -open $com] set timeout 2 after 1000 expect { ">>" { set newTime [clock seconds] set newTime [clock add $newTime 4 seconds] send "setrtc [clock format $newTime -format %Y%m%d%H%M%S]\n"} } expect -re $ #clear buffer expect { ">>" { send "getrtc\n"} } after 2000 expect -re .$ #send_tty $expect_out(buffer) exit
Above, the expect script runs on Windows (under ActiveTCL with Expect) and Linux.
Above, a screen shot of the Expect script running in Windows 10.
A zip of the source and modified command interpreter files is downloadable from setrtc .