Syncing a DS1307 automatically using python

My real time clock (DS1307) arrived yesterday. Before I had this I was using the Time package to set and get time stamps for my data collection. There was one big problem I had with the hole syncing of the time. It had to be done manually. It seemed impossible for me to get the seconds from 1970, then paste them into the serial command and do all this within a few seconds. There had to be a better way. I found a post on the Arduino wiki, showing how to set the time using NTP. This was not an option as I don’t have an ethernet shield. I decided to have a look into using c++ to set the time, but then discovered platform dependancies which would complicate things. I decided to go with python. Disclaimer: I have extremely little experience with python, let alone Arduino (c code). I did a bit of research about communicating between Arduino and python. Thanks to this page it wasn’t hard to get started. With alot of trial and error (probably should have payed more attention to that link), I figured out that every Serial.print on the Arduino side must have new line at the end, by using either Serial.println() or the ‘\n’ symbol.

To sync the Arduino’s RTC you need two scripts, a python script and a script for the Arduino. From here on I assuming you read that pervious link and tried it out. I don’t remember seeing it mentioned on that page but you require the addition pyserial library for this to work.

On the Python side

#!/usr/bin/python
#The libraries required
import serial  
import time  
import datetime

#A list (not in my case) of possible arduino devices.
locations=['/dev/tty.usbserial-A80090pL']

###Unless it's needed, I think it's best to let the arduino handle the delays

for device in locations:  
	try:  
		print "Trying...",device  
		arduino = serial.Serial(device, 9600)
		#Print the response from the Arduino - to show the communiction has started.
		print arduino.readline()	
		break  
	except:  
		print "Failed to connect on",device     
  
try:  
	#Get the current time
	t = datetime.datetime.now();
	#Send the current time to the Arduino
	arduino.write(t.strftime("%Y-%m-%d %H:%M:%S"))
	#Receive the time string from above back from the Ardunio.
	print arduino.readline()
	#Receive what the minute is from the DS1307. 
	print arduino.readline()

except:
	print "Failed to send!"
 

The above code, creates a serial connection with the Arduino, based on the USB device specified in locations. It is possible to list several seperated with a comma. It then gets the system time, and then passes this to the Arduino.

On the Arduino side
The arduino requires a script that will receive the string of numbers from the serial connection and convert them to ints and pass them to the RTC. I used a function I found on a forum to convert the string to int values. These are then passed to the RTC syncing functions within the DS1307new library. In theory this script would also work without the use of the python script, by just using a serial monitor window from within the Arduino IDE.

/*
 Author: Jason Lessels
 Date created: 19/06/2011
 License: GPL (>=2)
 Description: A script to receive A time input from a serial communication to set the time. The time format
 must be in 'yyyy mm dd hh dd ss' format for this to work.
 */

#include <Wire.h> 
#include <DS1307new.h>


String dateIn;
int TimeSet = 0;
void setup(){
	Serial.begin(9600);
	delay(100);
	Serial.print("I hear you\n");
}



void loop(){
	if(Serial.available()==19&&TimeSet==0){
		for(int i=0;i<19;i++){
			dateIn += String(byte(Serial.read()));
			
		}
		RTC.stopClock();
		RTC.fillByYMD(getInt(dateIn.substring(0,4)),getInt(dateIn.substring(5,7)),getInt(dateIn.substring(8,10)));
		RTC.fillByHMS(getInt(dateIn.substring(11,13)),getInt(dateIn.substring(14,16)),getInt(dateIn.substring(17,19)));
		RTC.setTime();
		RTC.startClock();
		Serial.println(dateIn);
		RTC.getTime();
		Serial.println(RTC.second,DEC);
		TimeSet=1;
		
		
	}
}

/*
 -------Functions-------
 I obtained the following function from
//http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1285085509
 */
int getInt(String text)
{
	char temp[6];
	text.toCharArray(temp, 5);
	int x = atoi(temp);
	return x;
} 

Check to see if the time is synced
A short script to check display the time through a serial connection.

#include <Wire.h>                       
#include <DS1307new.h>

void setup(){
	Serial.begin(9600);
	delay(100);
	Serial.println("What time is it in Arduino world?");
}


void loop()
{
	RTC.getTime();
	if (RTC.hour < 10)                    // correct hour if necessary
	{
		Serial.print("0");
		Serial.print(RTC.hour, DEC);
	} 
	else
	{
		Serial.print(RTC.hour, DEC);
	}
	Serial.print(":");
	if (RTC.minute < 10)                  // correct minute if necessary
	{
		Serial.print("0");
		Serial.print(RTC.minute, DEC);
	}
	else
	{
		Serial.print(RTC.minute, DEC);
	}
	Serial.print(":");
	if (RTC.second < 10)                  // correct second if necessary
	{
		Serial.print("0");
		Serial.print(RTC.second, DEC);
	}
	else
	{
		Serial.print(RTC.second, DEC);
	}
	Serial.print(" ");
	if (RTC.day < 10)                    // correct date if necessary
	{
		Serial.print("0");
		Serial.print(RTC.day, DEC);
	}
	else
	{
		Serial.print(RTC.day, DEC);
	}
	Serial.print("-");
	if (RTC.month < 10)                   // correct month if necessary
	{
		Serial.print("0");
		Serial.print(RTC.month, DEC);
	}
	else
	{
		Serial.print(RTC.month, DEC);
	}
	Serial.print("-");
	Serial.print(RTC.year, DEC);
	Serial.println();
	delay(1000);
}

Now all that is left to do is upload the Arduino script. Determine which tty device the Arduino is and run the python script. Now your DS1307 is synced (within less than a second) for the next 5 years (battery dependent). If anyone has suggestions to make this better, I would love to hear them.

Update on the difference between the two clocks
As I mentioned earlier, I’m new to this. I was wondering how accurate the two times will be synced. I added some micros() before and after the data (see below). With this I had results floating around 4000 micro seconds (0.0004 seconds). I then checked out the time delay for the data to be transfered. Using a baud rate of 9600 it works out to be (19*8/9600) 0.016 seconds. I increased the baud rate in both scripts to 115200, and the new transfer time is (19*8/115200) 0.0013 seconds. So the DS1307 time should be within 0.002 seconds of the computers time. That’s good enough for me, I suppose if you want better than that you should get an ethernet shield.

if(Serial.available()==19&&TimeSet==0){
                timer1 = micros();
		for(int i=0;i<19;i++){
			dateIn += String(byte(Serial.read()));
			
		}
		RTC.stopClock();
		RTC.fillByYMD(getInt(dateIn.substring(0,4)),getInt(dateIn.substring(5,7)),getInt(dateIn.substring(8,10)));
		RTC.fillByHMS(getInt(dateIn.substring(11,13)),getInt(dateIn.substring(14,16)),getInt(dateIn.substring(17,19)));
		RTC.setTime();
		RTC.startClock();
                timer2 = micros()-timer1;
Advertisements

3 responses to “Syncing a DS1307 automatically using python

  1. nice job man…but thnk therez no need to interface RTC to get the time via python….

    • Actually, there is a need to set the RTC from a PC and that is at the time of startup, imagine your alarm clock flashing 12:00. Same thing here.

      The other scenario is when daylight saving time (DST) comes around. You could elect to calculate the offset yourself for summer or set the RTC at the appropriate time.

  2. Pingback: DS1302 Real Time Clock | Hard Copy Arduino

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s