An I2C Bus Example Using the DS1307 Real-Time Clock

A more complete description of I2C can be read here on Wikipedia, but I will give you the four sentence summary here. I2C is a serial data bus protocol that allows multiple devices to connect to each other with fairly slow data transfer rates. These slow data transfer rates are fast enough for many devices and allow the bus to be very simple to implement. The real beauty of this protocol is that you can control up to 112 devices with just two wires from a microcontroller. Many microcontrollers have a libraries to support I2C; on Arduino the official Wire library handles the details for you.

In this example I use an Arduino board as the bus master and have just one slave device on the I2C bus, a DS1307. You can read the DS1307 data sheet here. As I mentioned before Arduino has a library called Wire that handles all the details of the I2C protocol. Wire uses analog pin 4 for the Serial Data (SDA) connection and analog pin 5 for the Serial Clock (SCL) connection. The I2C protocol defines the bus as an open drain bus, which means you need to use pull-up resistors on each of the two bus wires. Here is the circuit of how I wired the DS1307 to Arduino using a I2C bus.

Here is the code I wrote. There are a lot of other places on the web that have code for using the DS1307, but I couldn’t find a simple and efficient one that just did what I needed. This code has two main functions for accessing the DS1307. One sets the time and date, and the other gets the time and date. The DS1307 returns it’s numbers coded in binary-coded decimal (BCD). This code also converts the numbers returned from the DS1307 out of BCD for you. If all you want to do is display the time BCD is probably better, but most of the time I won’t be just displaying the time. Instead I’ll be using it to decide when to run events and for this it’s better to work with normal numbers.

//
// Maurice Ribble 
// 4-17-2008
// http://www.glacialwanderer.com/hobbyrobotics

// This code tests the DS1307 Real Time clock on the Arduino board.
// The ds1307 works in binary coded decimal or BCD.  You can look up
// bcd in google if you aren't familior with it.  There can output
// a square wave, but I don't expose that in this code.  See the
// ds1307 for it's full capabilities.

#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68

// 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) );
}

// Stops the DS1307, but it has the side effect of setting seconds to 0
// Probably only want to use this for testing
/*void stopDs1307()
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0);
  Wire.send(0x80);
  Wire.endTransmission();
}*/

// 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));      // If you want 12 hour am/pm you need to set
                                   // bit 6 (also need to change readDateDs1307)
   Wire.send(decToBcd(dayOfWeek));
   Wire.send(decToBcd(dayOfMonth));
   Wire.send(decToBcd(month));
   Wire.send(decToBcd(year));
   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()
{
  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 = 45;
  minute = 3;
  hour = 7;
  dayOfWeek = 5;
  dayOfMonth = 17;
  month = 4;
  year = 8;
  setDateDs1307(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
}

void loop()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;

  getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  Serial.print(hour, DEC);
  Serial.print(":");
  Serial.print(minute, DEC);
  Serial.print(":");
  Serial.print(second, DEC);
  Serial.print("  ");
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  Serial.print(year, DEC);
  Serial.print("  Day_of_week:");
  Serial.println(dayOfWeek, DEC);

  delay(1000);
}

UPDATE 5-20-2008
Updated the code to fix a few bugs Fabien pointed out. He also informed me of this: “Because you’re hooking up the clock to analog pins 4 & 5 on the Arduino and using the Wire lib, you don’t need to bother with pull-up resistors in your schematics. Turns out that the Arduino has built-in pull-up resistors for these pins. The Two Wire library enables the built-in pull-ups in the twi_init() function in twi.c (located here: \arduino-0011\hardware\libraries\Wire\utility).”

Thanks Fabien!

77 Comments

  1. timavalanche said,

    June 5, 2008 @ 4:30 pm

    This is a great tutorial. Thanks so much.

    Could you explain what the purpose of this is?

    *hour = bcdToDec(Wire.receive() & 0x3f);

    The “0x3f”.

  2. Glacial Wanderer said,

    June 5, 2008 @ 8:47 pm

    What I’m doing here is logically “and-ing” the value I got back from the ds1307 with a hex value of 3f. 0x3f in binary is 00111111. When you “and” a value with another that is a 1 it keeps the first value and anything that is a 0 goes to zero so this 3f mask is just forcing the 2 most significant bits to 0. If you look at this register in the ds1307 the top two bits have a 0 (which doesn’t matter) and the an am/pm flag. If I displayed the am/pm flag it would make my time wrong so I masked out that value.

  3. rafaelquines said,

    July 11, 2008 @ 8:14 pm

    Hi! I need your help.

    I’m trying to make it works, but never work.

    I used your source code with my arduino board. The DS1307 circuit has everything that is necessary, including pullup-resistors. When I run my app in board, and print in SERIAL, o DS1307 wait 5 seconds to change the field “seconds”… Can you help me?

    7:3:47 4/17/8 Day_of_week:5
    7:3:47 4/17/8 Day_of_week:5
    7:3:47 4/17/8 Day_of_week:5
    7:3:47 4/17/8 Day_of_week:5
    7:3:47 4/17/8 Day_of_week:5
    7:3:47 4/17/8 Day_of_week:5
    7:3:47 4/17/8 Day_of_week:5
    7:3:47 4/17/8 Day_of_week:5
    7:3:47 4/17/8 Day_of_week:5
    7:3:48 4/17/8 Day_of_week:5
    7:3:48 4/17/8 Day_of_week:5
    7:3:48 4/17/8 Day_of_week:5
    7:3:48 4/17/8 Day_of_week:5
    7:3:48 4/17/8 Day_of_week:5
    7:3:48 4/17/8 Day_of_week:5
    7:3:48 4/17/8 Day_of_week:5
    7:3:48 4/17/8 Day_of_week:5

    Thanks

  4. Glacial Wanderer said,

    July 14, 2008 @ 10:39 am

    So you’re saying that the DS1307 works, but it runs at 1/5th normal speed? My guess is that the crystal you have installed with your ds1307 is the wrong one. I used a packaged crystal/ds1307 chip so I didn’t need to worry about this. You should probably look at the hardware spec and make sure the crystal frequency you’re using to drive the ds1307 is the correct one. Good luck!

  5. arduinonano said,

    July 15, 2008 @ 2:17 am

    I tried running your code with the same Sparkfun RTC and an Arduino Nano. I’m seeing 2 problems:

    1. The values written to the RTC registers and read back subsequently seem to be offset by 1 (register). The registers are, in order; second, minute, hour, day, date, month, year. Values written into the registers, when read back are off. So the value written into the second register appears in the minute register when read back and so on.

    This problem seems to go away when I remove the Wire.send (0) instruction (in the code) just prior to writing to the registers, but I believe that instruction sends the word address that is expected by the 1307.

    2. The second problem, which is probably related, is that the clock doesn’t run. The same value is returned in the loop all the time. Actually, the same values are returned even if the RTC is not connected at all!!!

    I tried this with a different DS1307 module from a different vendor with exactly the same results.

    Do you have any idea why things are not working?

    thanks!

  6. Glacial Wanderer said,

    July 15, 2008 @ 6:51 am

    That’s really odd. If you search the forums at http://www.arduino.cc you can find other examples using this hardware. It might be interesting to see if those show the same problem. Another option is work backwards from the hardware spec like I did. I don’t know why it’s not working for you. This code worked fine for me and it seemed to be working for others. When you eventually find the problem (either my code or something on your end) it would be great if you could give us an update so others can learn from your efforts. Sorry I didn’t have any other ideas :-(

  7. arduinonano said,

    July 24, 2008 @ 12:01 am

    I’m out of ideas from a software perspective so I ordered an iDuino. Maybe the hardware that I have is faulty somehow. I’ll let you know how it turns out.

  8. Glacial Wanderer said,

    July 24, 2008 @ 4:50 am

    The purpose of *hour = bcdToDec(Wire.receive() & 0×3f) is:

    If you look at the 1307 data sheet you will see that the hours register stores the 0-9 hour in bits 0-3. The ten’s bit for the hour is stored in bits 4-5. The 6-7 bits store the am/pm value and a 0. I am converting the hours to a value between 0-23 so I don’t want the am/pm value. When I &0x3f (this is 00111111 in binary) that is going to force bits 6-7 to 0 and then leave all the other bits as what they were. If you want to understand how that works ask google about bitwise logic operations.

  9. TruckTrash said,

    September 5, 2008 @ 7:05 pm

    Hey GWander,

    Nice code, I had a similar problem to arduinonano at first, and I tried many different things, but the one thing that worked was to just shutdown the entire power to the Arduino and RTC and then start it up again. Made sure the power stayed dead for a little while. Then your code worked just as you said it would. I am actually using it for event logging and you saved me a good six hours of coding and troubleshooting. =) I plan on creating a how-to for my A/C controller, and when I do I will give you a link-back, as well as I have credited you in my code comments.

    Thanks again!

  10. Glacial Wanderer said,

    September 7, 2008 @ 1:49 pm

    Glad this code was useful. I’m always interested in hearing about other projects derived from my work so please let me know when you have something to share!

  11. TruckTrash said,

    February 6, 2009 @ 6:10 pm

    Hey GWander,

    I just back on this project and updated your RTC code a little. Check it out.

    http://combustory.com/index.php/RTC1307_-_Real_Time_Clock

  12. Rick said,

    May 13, 2009 @ 2:18 pm

    Did this in assembly lanuage for a 68hc11 some time ago, and I still had the 1307 around, so it seemed like a good first project to try out on my freshly constructed Modern Device BBB, USB interface, serial LCD, and the Arduino C programming environment. Wow – it really went smoothly – no issues at all, which is pretty amazing for all the new hardware and software. Thanks for the head start with this code. I did make a couple of changes that I will pass on for what they are worth.

    First, I changed the delay at the end to 971mS – I arrived at this number for my system/program by watching the display and measuring the amount of time between dropped seconds (for example: going from 14:41:12 to 14:41:14 and then 40 seconds later going from 14:41:52 to 14:41:14) with the initial 1000 mS delay. This represents a loop timing “error” of 1 second every 40 seconds, so I adjusted the delay by 1/40 second (25mS) to allow for the processing time of the loop code. Thus, my next interation was using a delay of 975mS, which resulted in 4 minutes and 13 seconds between dropped seconds – one every 253 seconds, hence another 4mS adjustment. This brings down the dropped seconds display glitch to less than 4 an hour, which will not be very noticeable – a significant improvement over every 40 seconds. Will have to incorporate interrupts to eliminate entirely and remove code time as a factor.

    The other two changes are just a couple of program enhancements that might be of interest. I created a SerialPrintPlus routine that displays a leading 0 for a value less than 10 and adds on a passed string at the end. Why? Well it makes the program somewhat smaller and easier to write. Anytime I see some block of code that is largely repeated, I start thinking about making a subroutine for it. The display time and date code is such a case. The other change was to display the day of the week as a 3 character string Mon, Tue, etc. A couple of good exercises in the use of pointers. Here is the revised code:

    // Prints a leading 0 if value is <10, plus adds on the passed string at the end
    void SerialPrintPlus(byte val, char* str)
    {
    if(val<10)Serial.print(“0″); // print leading 0 for val<10
    Serial.print(val, DEC); // print val as decimal value
    Serial.print(str); // print passed string
    }

    Following code is excerpted from loop -

    char* day[]={“Day”, “Mon”, “Tue”, “Wed”, “Thu”, “Fri”, “Sat”, “Sun”};

    SerialPrintPlus(hour,”:”); // print var with leading 0 if <10
    SerialPrintPlus(minute,”:”); // and add the passed string at the end
    SerialPrintPlus(second,”?n”); // Example: 19:27:03
    SerialPrintPlus(month,”/”); // 05/09/2009 Sat
    SerialPrintPlus(dayOfMonth,”/20″); // good until year 2100 – IC and code
    SerialPrintPlus(year,” “);
    Serial.print(day[dayOfWeek]); // print day of week as 3 char string
    // since dayOfWeek has values from 1-7
    // added a “dummy” string “Day” for day[0]

    delay(971); // loop takes ~29mS to run, so this eliminates
    // dropped seconds in the display to around
    // one per 1000 seconds (~16 minutes) or less
    } // need to incorporate interrupts to totally fix

  13. EricJ said,

    May 24, 2009 @ 10:43 pm

    Nice additions, Rick. Looks like you cut and paste your changes from a word processor. All the ” characters have been converted to open-quotes and close-quotes which cause the Arduino IDE to puke about a “stray \ character” or something like that. Drove me nuts until I realized what was happening. Also, shouldn’t the “?n” simply be ” ” in the seconds line?

    I didn’t find it necessary to change the delay() from 1000. This might vary from board to board. I watched it for about 10 minutes. I need an aspirin to treat the eye strain but no skipped seconds.

    I’m going to be using this in a data logger that is accessed every few days from a Windows Form so I’m going to be setting the DS1307 clock from the system clock on the Windows laptop. And I don’t really need this formatting, but I learned a few things from your example and appreciate Maurice’s code and your helpful additions.

    Eric

  14. Maurice Ribble said,

    May 25, 2009 @ 6:00 am

    The ?n should be \n. It inserts a new line.

  15. Chris Spurgeon said,

    June 28, 2009 @ 3:19 pm

    I’ve been trying to use your code with a Macetech Chrono Dot ( http://macetech.com/store/index.php?main_page=product_info&cPath=5&products_id=8 ) which I’m told behaves identically to the Sparkfun RTC, but it doesn’t seem to work for me. All I get back is “0:0:0 0/0/0 Day_of_week:0″.

    As far as you know, should the code work for the Chrono Dot as well? Would the wiring diagram stay the same? (BTW, I’ve tried it both with and with the resistors. No difference.)

    Thanks!

    Chris

  16. Chris Spurgeon said,

    June 28, 2009 @ 3:46 pm

    Got it! It wasn’t your code or Macetech’s chip, it was my board! I was trying it with a Arduino Mega. Once I switched over to running things on an Arcuino Diecimila, it fired right up.

    But now I’m curious, why DOESN’T this run on a Mega? Do I need to connect to different pins? On the Diecimila, how do you know to connect to analog pins 4 and 5? I don’t see that specified in the code. Is that some sort of default in the Wire class? I don’t see anything like that there either.

  17. Maurice Ribble said,

    June 28, 2009 @ 4:25 pm

    If you look at this page is says to use pins 4/5. http://arduino.cc/en/Reference/Wire

    If you look at the mega page it points out that the wire lib uses different pins. http://arduino.cc/en/Main/ArduinoBoardMega

    “I2C: 20 (SDA) and 21 (SCL). Support I2C (TWI) communication using the Wire library (documentation on the Wiring website). Note that these pins are not in the same location as the I2C pins on the Duemilanove or Diecimila.”

    Hope this helps.

  18. Chris Spurgeon said,

    June 28, 2009 @ 4:43 pm

    Thanks Maurice! I never thought of actually looking at the Mega page. D’oh.

  19. Lee said,

    July 17, 2009 @ 11:26 am

    I was wondering in your coding examples why you used pointers. I am relatively new to both C++ and Arduino (read “absolute novice” – still working on my C++ tutorial). I am looking forward to my first implementation of the RTC but want to know what I am doing, not just hack together a bunch of different code.

    Thanks,

  20. Maurice Ribble said,

    July 17, 2009 @ 12:23 pm

    Pointers have many uses. In the case of getDateDs1307() I was using them to return values from a function.

  21. Howard said,

    July 21, 2009 @ 2:04 pm

    Many thanks for the code – I have re-written for the PCF8563

    //
    // Howard Benn
    // 21 July 2009
    // PCF8563 code based on DS1307 code by http://www.glacialwanderer.com/hobbyrobotics

    // For those not in know about I2C and the wire lib
    // PCF8563 write address is 0xA2 the LSB being R/W – so you to get the Arduino address you have right shift
    // Hence address becomes 0×51 (write it in binary and it is more obivious)
    // To read or write you set the device address, then register address then value
    // multiple reads and writes are OK as it will auto increment the register address

    #include “Wire.h”
    #define PCF8563_I2C_ADDRESS 0×51

    // 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 PCF8563
    // 2) Starts the clock
    // 3) Sets hour mode to 24 hour clock
    // Assumes you’re passing in valid numbers
    // 02H Seconds
    // 03H Minutes:p
    // 04H Hours
    // 05H Date
    // 06H Day of the week
    // 07H Century bit 19XX = 1 | 20XX = 0 MSB then LSBs = month
    // 08H year

    void setDateRTC(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 assumes 20xx
    byte year) // 0-99
    {
    Wire.beginTransmission(PCF8563_I2C_ADDRESS);
    Wire.send(0); //start at address 0
    Wire.send(0); // control 1 – starts clock and resets any test modes
    Wire.send(0); // control 2 – resets alarms interrupts etc
    Wire.send(decToBcd(second));
    Wire.send(decToBcd(minute));
    Wire.send(decToBcd(hour));
    Wire.send(decToBcd(dayOfMonth));
    Wire.send(decToBcd(dayOfWeek));
    Wire.send(decToBcd(month));
    Wire.send(decToBcd(year));
    Wire.endTransmission();
    }

    // Gets the date and time from the PCF8563
    void getDateRTC(byte *second,
    byte *minute,
    byte *hour,
    byte *days,
    byte *dayOfWeek,
    byte *month,
    byte *year)
    {
    // Reset the register pointer
    Wire.beginTransmission(PCF8563_I2C_ADDRESS);
    Wire.send(2);
    Wire.endTransmission();

    Wire.requestFrom(PCF8563_I2C_ADDRESS, 7);
    if (Wire.available() == 7){
    // A few of these need masks because certain bits are control bits
    *second = bcdToDec(Wire.receive() & 0x7f);
    *minute = bcdToDec(Wire.receive())& 0x7f;
    *hour = bcdToDec(Wire.receive() & 0x3f);
    *days = bcdToDec(Wire.receive() & 0x3f);
    *dayOfWeek = bcdToDec(Wire.receive() & 0×07);
    *month = bcdToDec(Wire.receive() & 0x1f);
    *year = bcdToDec(Wire.receive());
    }
    }

    void setup()
    {
    // 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 = 00;
    // minute = 55;
    // hour = 18;
    // dayOfWeek = 2;
    // dayOfMonth = 21;
    // month = 7;
    // year = 9;
    // setDateRTC(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
    }

    void loop()
    {
    byte second, minute, hour, days, dayOfWeek, month, year;

    getDateRTC(&second, &minute, &hour, &days, &dayOfWeek, &month, &year);
    Serial.print(hour, DEC);
    Serial.print(“:”);
    Serial.print(minute, DEC);
    Serial.print(“:”);
    Serial.print(second, DEC);
    Serial.print(” “);
    Serial.print(days, DEC);
    Serial.print(“/”);
    Serial.print(month, DEC);
    Serial.print(“/”);
    Serial.print(year, DEC);
    Serial.print(” Day_of_week:”);
    Serial.println(dayOfWeek, DEC);

    delay(1000);
    }

  22. Miguel said,

    October 2, 2009 @ 8:42 am

    Hi,

    I was trying to run it with arduino duemilanove and the RTC ds1307 (http://www.bricogeek.com/shop/56-placa-reloj-rtc-ds1307.html), but it didn´t run. Not lectures and not prints on the serial..

    Could you show any simple example of use for example, put it on time and turn on a led and turn it off, fr example, every 1minute, or an exact time and day or something like that? Just to be sure that it runs and i understand how to connect it….

    Thanks. Cheers!

  23. Maurice Ribble said,

    October 3, 2009 @ 6:03 am

    Hi Miguel, unfortunately I don’t have this setup anymore. All I can really do is suggest you try to run through some of the simpler tutorials about the arduino (try some here http://arduino.cc/en/Tutorial/HomePage). Once you have a better understanding of Arduino programming you should be able to debug the problem yourself. If you have general questions about Ardiuno a great place to ask questions is http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl

  24. Joe said,

    October 9, 2009 @ 11:22 pm

    Thanks for the code. I got it working but it seems that the time doesn’t start until I hit the serial window button. If I set clock to 10:30:00 for example, it takes but the clock start ticking only after I enable the serial port display via the Arduino IDE.

    Any ideas?

    Also, what do I need to remove to use the program strictly as a mechanism to set the time? I tried removing some sections and it compiles ok but maybe that’s what’s causing my serial port time problem?

  25. Joe said,

    October 9, 2009 @ 11:27 pm

    Actually, what’s strange is if I upload the program, and then enter the serial display in Aruduino, the time advances like I described in my previous post but if you close the serial window and open it up, the time resets to what I originally set it to. It’s like it’s not picking up where it left off. How can this be? Isn’t the serial port display function supposed to do just that, display what the arduino is outputting? I can’t wrap my brain around this one.

  26. Maurice Ribble said,

    October 10, 2009 @ 1:52 am

    Hi Joe, glad you found this code useful. The problem you are are seeing it that every time you connect to the serial port the Arduino resets (this is just how the bootloader and the software are setup). The way to fix this is to load the time code once and then modify the code so you don’t keep setting the clock’s time every time the arduino boots. This should fix your problem.

  27. Joe said,

    October 10, 2009 @ 8:50 pm

    Yep, that did the trick. Thanks alot. Code worked like a charm. It was a pain trying to find working code until I came across this site. I really appreciate you making it available. With a little modification, I managed to add some code so that I get timestamps on my temperature readings from my temp sensor setup. Managed to get it working with my motion detector too and I finally have time stamps to my data collection points.

    One thing I’m still not clear on is how to change the time format to 12 hour. Could you point me to the line in your code to modify?

    Also, I got everything working by having 2 copies of your code, 1 to set the time, another to read the time. Sketches that incorporate timestamps and sensor values obviously have the code from the 2nd script which works fine. I’m able to read the time by commenting out the following line:

    setDateDs1307(second, minute, hour, dayOfWeek, dayOfMonth, month, year);

    If there’s a cleaner or more proper way to get the same result, please let me know but this seems to work.

  28. Joe said,

    October 11, 2009 @ 3:43 pm

    One more thing, have you figured out a way to maybe feed this sketch the real time via processing for the purposes of setting the clock on the RTC close to the real time as possible? I used a stopwatch to see how long the sketch for settings the clock runs, and then I manually upload the sketch that many seconds before the time I’m setting in the sketch. I got close, within a second but this will drift in no time :-)

  29. Maurice Ribble said,

    October 12, 2009 @ 10:09 am

    There is this comment in the code about changing to 12 hours.

    // If you want 12 hour am/pm you need to set
    // bit 6 (also need to change readDateDs1307)

    It’s been a long times since I wrote this and I never tested 12 hour mode. I’d suggest looking at the data sheet and then try changing the code.

    I wrote a different tutorial that showed how to use processing to graph accelerometer/gyroscope data in real time. It could be modified for your purposes. http://www.glacialwanderer.com/hobbyrobotics/?p=261

  30. Joe A said,

    January 26, 2010 @ 9:56 am

    Hi i am trying to use the code above provide by Maurice Ribble, (4-17-2008) to display time/date on a lcd screen. Any ideas on how to do this. Any help would be great

    Thanks

  31. Rodney said,

    February 2, 2010 @ 2:17 pm

    Hey Joe,

    I’m in the process of making an arduino alarm clock, so maybe I can help you with your LCD.
    Got it to work on the 16×2 lcd if you use liquidcrystal and replace the serial.print with lcd.print. Be sure to either match your pins on change them in the sketch. Also, specify your cursor, that library is pretty well laid-out, though, so it should be easy enough.

    I skipped the 16×2 and got a big glcd (ks0108). Currently, I’m having an issue getting it to read the rtc data. PrintNumber (hour) and so on makes my numbers print one on top of the other. So far I’ve got a clearscreen to refresh it, but a blinking clock looks silly. Also, trying to figure out how to go from a vlw file to .h file so i can use a larger font to display the time. Anyone?

    True story

  32. Prune said,

    February 5, 2010 @ 8:20 pm

    Hi,

    I don’t understand how your stuff is working.
    Reading the datasheet, your device have two addresses : one for WRITE operations (7bits + 0) and one for READ (7bits +1).
    You seems to always be using the first one, as your fixed slave address is 0X68, or 0110100+0
    That should mean you can read from the device, but never write… Am I missing something ?

  33. Prune said,

    February 5, 2010 @ 9:41 pm

    Looks like the Wire library takes care of adding the latest 0/1 depending on a read or write request ? I’ll have to dig the Wire code.

    For the moment I can only talk to my I2c componant on the Ox00 address, and the answer does not comply with the datasheet… :)
    what’s wrong with this chips ?
    FYI, it’s a AMIS-30624 i’m trying to use…

  34. Mike said,

    March 4, 2010 @ 11:49 am

    Looks like it is working for me but the one thing I can’t figure out is how to save the current time settings so that when power is removed from the arduino and reconnected time continues. I assume it is supposed to work that way?? am I missing something?

  35. nirkolounriodra said,

    March 4, 2010 @ 1:11 pm

    ok, good post.

  36. DS1307 – first glance said,

    March 21, 2010 @ 10:53 pm

    [...] connected all the pins to the correct connectections, but nothing happend, the samplecode found at http://www.glacialwanderer.com/hobbyrobotics/?p=12 showed me at first 00:00:00 as [...]

  37. Quessyurbarge said,

    April 1, 2010 @ 6:12 am

    where did you read this?

  38. Shran said,

    April 16, 2010 @ 4:38 am

    Hi, i got the code working, but stumbled upon another problem ;-)

    I did write a little program to synchronize Arduino’s time with the time of my PC-clock. I wanted to know the accuracy of the ds1307 and my PC was also in charge of determining whether arduino’s clock was too slow, on time or too fast.
    Day 1, Arduino’s clock ran perfectly, day 2 it was a second slow. day 3 it was two seconds slow etc. etc. until it was day 7. At day seven it was right on time again without… having changed the time of the ds1307. Next week exactly the same happened.

    So, I started wondering whether the ds1307 had a mind of it’s own until I noticed that my PC’s clock gets synchronized with windows.time.com every week. Apparently my ds1307 does a much better job in keeping track of time as the clock in my PC ;-)

    I noticed that one can change the polling interval using regedit, to have a more accurate PC-time. I reset it to 2 hours, but… timeservers aren’t fond of that, after two weeks windows.time.com wouldn’t synchronize my clock every 7200 seconds any more. It still does synchronize every week though and if I really… need to know the exact second I can always ask my 1307 ;-)

  39. AtomsFat said,

    April 17, 2010 @ 10:37 am

    Why you put this variables inside the loop byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; ?

    If I put this outside is any difference ?

  40. Maurice Ribble said,

    April 17, 2010 @ 11:42 am

    I put them inside loop because it’s a good coding practice to reduce global variables. There are various reasons this is good like reducing software bugs and allowing more efficient use of the stack/ram by the processor. In this case it doesn’t really matter since it’s such a simple program.

  41. Andreas said,

    April 17, 2010 @ 2:23 pm

    FYI
    This code also works with a DS1337.

    Thanks for the example!

  42. spencer said,

    April 21, 2010 @ 11:38 pm

    This is great. I have the problem that I can’t set the time. It always shows 0:00:00 day of week0. Any help is apprechiated

  43. Oliver said,

    April 28, 2010 @ 5:18 pm

    Hi Spencer, you just have to connect battery input

  44. AvrLabCom said,

    June 17, 2010 @ 1:33 am

    Hello have you this project but under WinAVR GCC?

  45. Rob Smith said,

    August 10, 2010 @ 6:37 am

    Hi, I’m am just trying to chop the sketch so that I get just the time output from the ds1307 (I don’t need to set the time) any pointers?

  46. Rob Smith said,

    August 10, 2010 @ 6:51 am

    please ignore the above comment, I have rtfm and sorted my foolish error!

  47. Lee said,

    October 18, 2010 @ 9:16 pm

    Many Thanks for the code and info, got mine up and running with little trouble!

  48. maikll said,

    November 19, 2010 @ 2:11 pm

    I your real time clock RTC DS1307 working with arduino have problem and return all zero 00:00:00 0/0/2000 you should check your microcontroller (atmega168 or other) for correct pinout for SCL and SDA pins. for my very old arduino NG it was at analog pins 0 and 1. Not at pin 4 and 5 as expected by code by mattt and sjunnesson

  49. Overflo said,

    December 14, 2010 @ 7:43 pm

    thanks for sharing your code it saved my day :)

    for my current project i needed 12 hours regardless of AM/PM
    thats what i put in my code (works for me)

    void setDateDs1307
    ….
    Wire.send(decToBcd(hour) | _BV(6)); // set bit 6 for 12 hour mode

    void getDateDs1307:
    ….
    *hour = bcdToDec(Wire.receive() & 0x1f); // mask output for 12 hour mode

  50. Dzhus said,

    January 21, 2011 @ 9:11 am

    In case of problems when you get all zeros from DS1307, pluggin out the power for Arduino and the RTC really works.

  51. Fabio Varesano said,

    January 24, 2011 @ 3:06 am

    Hey, nice article!

    you may be interested in helping me pushing the high level writeTo & readFrom into Wire to avoid code repetition and wasting program memory when using different I2C devices with Arduino.

    See http://code.google.com/p/arduino/issues/detail?id=466

    Thank you,

    Fabio Varesano

  52. Ashen Randika said,

    March 2, 2011 @ 10:57 am

    Hello!
    Thanks for the artcle :) It saved my day

  53. hari said,

    March 5, 2011 @ 2:13 am

    *second = bcdToDec(Wire.receive() & 0x7f); why r u use this pointer name ,use another name like *sec

  54. Curt said,

    March 9, 2011 @ 10:41 am

    I’m total novice trying to get RTC 1307 module from Sparkfun working with Arduino Duemilanove and example code. LEDs indicate communication with the board.

    Nothing prints on the serial monitor unless…. I issue a Q1 or Q2 Command, the serial monitor shows stuff like : •2•ç—0•2—æ•æ—æ
    Am I correct in expecting the serial monitor to show the time (from the registers) when a Q2 command is sent ?

    Thanks,
    Curt

  55. Ray said,

    April 4, 2011 @ 12:43 pm

    Just wanted to thank you for the article/code, worked first time and I learned a lot.

    Cheers

    Ray

  56. Alvaro Justen said,

    April 23, 2011 @ 1:20 am

    Hello,
    I wrote an Arduino library to control ds1307 module. I think it is better (simple) than the code you post.

    More information at:
    - Discussion at Arduino Forum: http://arduino.cc/forum/index.php/topic,59256.0.html
    - Code at GitHub: https://github.com/turicas/DS1307/

    Please let me know if it works with your module. Thanks.

  57. angieb francis said,

    May 27, 2011 @ 10:45 am

    I’m total novice trying to get RTC 1307 module from Sparkfun working with Arduino Duemilanove and example code. LEDs indicate communication with the board.

  58. psypi said,

    August 12, 2011 @ 3:25 pm

    Thanks! I just copy-pasted the code and it worked right away! Leaving the RTC on backup battery for the night! Let’s see the time in the morning!
    Thanks again :)

  59. Blaise - French Riviera Wedding Photographer said,

    September 29, 2011 @ 3:22 pm

    Hi,

    Works perfectly, right out of the box. thanks!!! Next in my list with the DS1307 is finding how to store and retrieve data in the 56 remaining bytes (should be easy!)

    Blaise

  60. Messing with AVR Microcontrollers « Pointers Gone Wild said,

    October 4, 2011 @ 2:25 am

    [...] UART and got a serial terminal (GtkTerm) communicating with them, and finally, I interfaced with a DS1307 real-time-clock chip through the I2C bus. I decided it would be cool to perhaps make an advanced alarm clock [...]

  61. carter said,

    October 15, 2011 @ 11:02 pm

    hi everyone!!i’m try run this code on my arduino uno board..but it doesn’t seem to work for me.
    All I get back:

    0:0:0 0/0/0 Day_of_week:0
    0:0:0 0/0/0 Day_of_week:0
    0:0:0 0/0/0 Day_of_week:0
    0:0:0 0/0/0 Day_of_week:0
    0:0:0 0/0/0 Day_of_week:0
    0:0:0 0/0/0 Day_of_week:0
    0:0:0 0/0/0 Day_of_week:0

    it’s continue like that..is there any wrong?thanks for helping..

  62. husseinhazime said,

    October 23, 2011 @ 3:22 pm

    i’m lossing time after reconnecting the arduino ?????
    battry is connected and 100% delivering power to the ds1307.

  63. husseinhazime said,

    October 23, 2011 @ 3:23 pm

    i;m lossing data after disconnecting power the backup battery is installed and its working .

  64. mikeroo said,

    November 15, 2011 @ 5:23 pm

    I have the same trouble as husseinhazime.

    The time seems to be reset after disconnecting power, despite having a backup battery installed. (I removed the part of the sketch that sets the clock, so that’s not the problem). I thought that once I set the time on the real time clock module, it would be maintained.

  65. lsq1986 said,

    November 19, 2011 @ 3:11 pm

    kinda have small question or a small issue 0_0 , i wanted to know if its possible to set the time of the RTC to always display the time and not have to input the time with arduino.. yea maybe its only only possible with a small battery but it cant hurt to ask.

  66. Maurice Ribble said,

    November 19, 2011 @ 3:15 pm

    You either need a backup battery or need to not disconnect the power if you don’t want to have to reset the time.

  67. Reloj con el DS1307 | Electrónica práctica said,

    February 14, 2012 @ 11:01 am

    [...] ideas me lleva a poner un poco más de mi parte, creo. El código original, se puede descargar de este enlace, si usted lo desea puede compararlo con el siguiente código tiene [...]

  68. Roger said,

    February 15, 2012 @ 2:48 am

    RTC_working.cpp: In function ‘void setDateDs1307(byte, byte, byte, byte, byte, byte, byte)’:
    RTC_working:61: error: call of overloaded ‘write(int)’ is ambiguous
    E:\Software\Arduino\arduino-1.0-windows\arduino-1.0\libraries\Wire/Wire.h:55: note: candidates are: virtual size_t TwoWire::write(uint8_t)
    E:\Software\Arduino\arduino-1.0-windows\arduino-1.0\hardware\arduino\cores\arduino/Print.h:49: note: size_t Print::write(const char*)
    RTC_working.cpp: In function ‘void getDateDs1307(byte*, byte*, byte*, byte*, byte*, byte*, byte*)’:
    RTC_working:84: error: call of overloaded ‘write(int)’ is ambiguous
    E:\Software\Arduino\arduino-1.0-windows\arduino-1.0\libraries\Wire/Wire.h:55: note: candidates are: virtual size_t TwoWire::write(uint8_t)
    E:\Software\Arduino\arduino-1.0-windows\arduino-1.0\hardware\arduino\cores\arduino/Print.h:49: note: size_t Print::write(const char*)

    Hi !! i am getting the above problem i dont know how to debug it. i am using Arduino with atmega 328p-Pu

  69. Madison said,

    March 19, 2012 @ 12:54 am

    Roger,

    I’m having the same problem. Did you ever figure it out?

  70. Chris said,

    April 13, 2012 @ 4:42 am

    I fixed the code problems by changing all
    Wire.receive to Wire.read
    and
    Wire.send to Wire.write

    And where its saying the code is ambiguous you have
    Wire.Write(0);

    Change too
    int i = 0;
    Wire.write(i);

    This is because it doesn’t know how to handle 0, you have to give it a int type first, strangely casting it to Wire.write((int)0); doesn’t work, anyone know why?

    Not sure how right all that code is but it works for me. YMMV

  71. Maurice Ribble said,

    April 13, 2012 @ 5:26 am

    Thanks for the explaining the fixes. This is required if you want to use Arduino 1.0 or newer. I was fixing some other libs I use and I think they changed these names so they could inherit more stuff in the Wire class to inherit behavior from some of the Arduino base classes.

    I also ran into that 0 issue. You can also fix it by type casting the 0 to a byte. The reason for this is because of how c++ handles function overloading. It can’t tell if 0 is a valid string pointer and a valid byte so the compiler can’t figure out which overloaded function to choose and gives you the error.

  72. red_car said,

    September 25, 2012 @ 3:44 am

    Very useful.. even after 4.5 years… helped a lot. Nice simple examples are always the best.

    One thing I noticed.. there is no point in trying to to set the Day of Week register (0×03). It seems to be determined automatically by the DS1307 based on the date set… which makes sense I guess.

  73. limchonghan said,

    November 14, 2012 @ 4:24 am

    [...] correction for DS1307 on Arduino.cc Forum DS1307 RTC Tutorial at Ladyada DS1307 RTC at bildr Blog An I2C Bus Example Using the DS1307 Real-Time Clock DS1307 [...]

  74. Ajit Nayak said,

    February 27, 2013 @ 1:24 am

    can some tell me how did we assigned this address:#define DS1307_I2C_ADDRESS 0×68 . how we get this I2c address

    how they assigned as 68 .

  75. Respecto said,

    May 2, 2013 @ 8:18 pm

    re:how we get this l2c assress

    this may help
    http://playground.arduino.cc//Main/I2cScanner

  76. Nixon said,

    July 7, 2013 @ 8:25 pm

    is there a way we can stop the time from counting until it has been enable? i wanted to set time using a switch.

  77. Ismael said,

    August 24, 2013 @ 10:01 am

    Nice tutorial, everything’s working fine !

RSS feed for comments on this post