Arduino app to set DS1307 Real Time Clocks.

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.

IMG_1563

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.

Screenshot - 29_05_16 , 16_06_19

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.

Screenshot - 29_05_16 , 16_07_12

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 .