Sunday, October 3, 2010

DS1307 Real Time Clock Working

With a bunch of help from John Boxall of Tronixstuff.com, we finally got the Time / Date functions working on our Arduino, with the DS1307 breakout board from Sparkfun. Thanks John.

More info at http://www.instructables.com/id/The-Arduino-Weather-Station-Thermostat/step6/Arduino-Clock-Module/

Finished code and wiring is below:

// Connections:
// LCD pin 1 to Arduino GND
// LCD pin 2 to Arduino 5v
// LCD pin 3 (Contrast) to GND
// rs (LCD pin 4) to Arduino pin 12
// rw (LCD pin 5) to Arduino pin 11
// enable (LCD pin 6) to Arduino pin 10
// LCD pin 15 to Arduino pin 13
// LCD pin 16 to Arduino GND
// LCD pins d4, d5, d6, d7 to Arduino pins 5, 4, 3, 2

//Tested with DS1307 Breakout from Sparkfun
//pin SDA to Arduino Analog pin 4
//pin SCL to Arduino Analog pin 5
//pin GND to Arduino GND
//pin VCC to Arduino 5v


#include <Wire.h>
#define DS1307_I2C_ADDRESS 0x68
#include <LiquidCrystal.h> // we need this library for the LCD commands
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

int backLight = 13; // pin 13 will control the backlight

// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
return ( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
return ( (val/16*10) + (val%16) );
}
// 1) Sets the date and time on the ds1307
// 2) Starts the clock
// 3) Sets hour mode to 24 hour clock
// Assumes you're passing in valid numbers
void setDateDs1307(byte second, // 0-59
byte minute, // 0-59
byte hour, // 1-23
byte dayOfWeek, // 1-7
byte dayOfMonth, // 1-28/29/30/31
byte month, // 1-12
byte year) // 0-99
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.send(0);
Wire.send(decToBcd(second)); // 0 to bit 7 starts the clock
Wire.send(decToBcd(minute));
Wire.send(decToBcd(hour));
Wire.send(decToBcd(dayOfWeek));
Wire.send(decToBcd(dayOfMonth));
Wire.send(decToBcd(month));
Wire.send(decToBcd(year));
Wire.send(0x10); // sends 0x10 (hex) 00010000 (binary) to control register - turns on square wave
Wire.endTransmission();
}
// Gets the date and time from the ds1307
void getDateDs1307(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
// Reset the register pointer
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.send(0);
Wire.endTransmission();
Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
// A few of these need masks because certain bits are control bits
*second = bcdToDec(Wire.receive() & 0x7f);
*minute = bcdToDec(Wire.receive());
*hour = bcdToDec(Wire.receive() & 0x3f); // Need to change this if 12 hour am/pm
*dayOfWeek = bcdToDec(Wire.receive());
*dayOfMonth = bcdToDec(Wire.receive());
*month = bcdToDec(Wire.receive());
*year = bcdToDec(Wire.receive());
}
void setup()
{
pinMode(backLight, OUTPUT);
digitalWrite(backLight, HIGH); // turn backlight on. Replace 'HIGH' with 'LOW' to turn it off.

byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
Wire.begin();
Serial.begin(9600);
// Change these values to what you want to set your clock to.
// You probably only want to set your clock once and then remove
// the setDateDs1307 call.
second = 0;
minute = 42;
hour = 9;
dayOfWeek = 1;
dayOfMonth = 3;
month = 10;
year = 10;

//setDateDs1307(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
lcd.begin(16, 2); // tells Arduino the LCD dimensions

}
void loop()
{
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
lcd.clear(); // clear LCD screen
lcd.setCursor(0,0);
lcd.print(" ");
lcd.print(hour, DEC);
lcd.print(":");
if (minute<10)
{
lcd.print("0");
}
lcd.print(minute, DEC);
lcd.print(":");
if (second<10)
{
lcd.print("0");
}
lcd.print(second, DEC);
lcd.setCursor(0,1);
lcd.print(" ");
switch(dayOfWeek){
case 1:
lcd.print("Sun");
break;
case 2:
lcd.print("Mon");
break;
case 3:
lcd.print("Tue");
break;
case 4:
lcd.print("Wed");
break;
case 5:
lcd.print("Thu");
break;
case 6:
lcd.print("Fri");
break;
case 7:
lcd.print("Sat");
break;
}
lcd.print(" ");
lcd.print(month, DEC);
lcd.print("/");
lcd.print(dayOfMonth, DEC);
lcd.print("/20");
lcd.print(year, DEC);
delay(1000);
}

7 comments:

  1. I suppose a case (1-12) could be done for the month as well?
    For example: Instead of showing 3 as the month, maybe the short version of the month would be better?
    So: Tue, 19 Mar 2012 instead of Tue 19/3/2012.
    Also, could the update be triggered with the square wave pin (7) on the DS1307 or does that replace an external 32kHz crystal with a little less accuracy?
    About to get an arduino and was doing research on it before taking the plunge.

    ReplyDelete
  2. there is no pin 7 on the ds module. it's I2C. Yes, you could display the month instead of the number pretty easily.

    ReplyDelete
  3. learn arduino language in easy manner :

    http://all-about-embedded.blogspot.com/2012/07/arduino-language-tutorial_28.html

    ReplyDelete
  4. Steve, I have just copied and paste the above code and the clock works fine except day of week stuck on "Sun".Then, just below Serial.begin(9600), //Change these values to what you want to set your clock to.I tried to change the values but with no success.The clock is now running the second day and still stuck on Sunday.Any advice please will be welcomed. I have no experience in coding but I do follow some logic at times. Thank you

    ReplyDelete
  5. As of Arduino 1.0, the wire.h library inherits from the Stream functions, making it consistent with other read/write libraries. Because of this, send() and receive() have been replaced with read() and write().

    ReplyDelete
  6. OK I have tried this and I get a mess of errors when I compile the program. This is just a couple of the errors but most are just like this with different numbers:

    Clock.cpp:76:6: error: ‘class TwoWire’ has no member named ‘send’
    Clock.cpp:77:6: error: ‘class TwoWire’ has no member named ‘send’
    Clock.cpp: In function ‘void getDateDs1307(byte*, byte*, byte*, byte*, byte*, byte*, byte*)’:
    Clock.cpp:91:6: error: ‘class TwoWire’ has no member named ‘send’
    Clock.cpp:95:25: error: ‘class TwoWire’ has no member named ‘receive’

    I wired my device just as you have, tho I have a different screen and different DS1307 module. My screen is a LCD Keypad Shield and my DS1307 has 2 interfaces, a 5 pin and 7 pin on the other side.

    I am using the 5 pin side of the DS1307 and I mapped out the pins of the shield to the 16 pins on the LCD (which is the same LCD just soldered to a shield). As far as I can tell I have all the libraries in my computer's Arduino folder. /usr/shared/arduino/librarys. Any ideas? Thanks for the support in advance


    ReplyDelete
  7. If you read the comment right above yours, you will see that the new versions of Arduino IDE (1.0 and later) use Read() and Write () instead of Send() and receive().

    ReplyDelete