Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
shivakumarj1995
Published © GPL3+

RTC Based Clock

A cool digital clock which sports the 7 segment display. With its bright red display will make sure you like to keep an eye at the time.

BeginnerFull instructions provided24,003
RTC Based Clock

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
Real Time Clock (RTC)
Real Time Clock (RTC)
I used the RTC module based on ds1307. Makes the job a lot easier. But you could make one yourself its very easy.
×1
4 digit seven segment led display
×1
female header single row
×3
perforated board
get this if you want to solder this project and make it presentable. To make soldering easy get s solder board that has traces like a bread board.
×1
Jumper wires (generic)
Jumper wires (generic)
×25
Male Header 40 Position 1 Row (0.1")
Male Header 40 Position 1 Row (0.1")
×1

Software apps and online services

Arduino IDE
Arduino IDE
Arduino Fritzing

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
multimeter
Every project needs a multimeter. So invest on a standard pair, it will work for at least 4 years and may be much more if you know how to repair it. You will be needing this to check for the connectivity of your soldering and to check the current drawn in by the circuit.

Story

Read more

Schematics

Clock Schematic

This is the schematic of the project.

Code

Clock Code

Arduino
The code uses the RTC library and the I2C library. You need these libraries for the program to execute. This program is for Common Anode type display.
#include <Wire.h>
#include<EEPROM.h>
#include <RTClib.h>
RTC_DS1307 RTC;
int temp, inc, hours1, minut, add = 11;
int HOUR, MINUT, SECOND;
int latchPin = 3; //pin 12 on the 595 o3 3
int dataPin = 4; //pin 14 on the 595 or 4
int clockPin = 2; //pin 11 on the 595 or 2
int shift = 256;
int units, tens, hundreds, thousands;
int x;
int y;
const int alarmHour = 17;
const int alarmMinute = 26;

void setup() {
  Serial.begin(9600);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(13, OUTPUT);
  Wire.begin();
  RTC.begin();
  if (!RTC.isrunning())
  {
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
}

void loop() {
  int temp = 0, val = 1, temp4;
  DateTime now = RTC.now();
  HOUR = now.hour();
  MINUT = now.minute();
  //Serial.println(MINUT);
  if (HOUR < 10)
  {
    hundreds = HOUR;
    thousands  = HOUR/10;
  }
  else if (HOUR >=  10 && HOUR < 24)
  {
    hundreds = HOUR % 10;
    thousands = HOUR / 10;
  }
  if (MINUT <= 9)
  {
    units = MINUT;
    tens = MINUT/10;
  }

  else if (MINUT > 9 && MINUT <= 60)
  {
    units = MINUT % 10;
    tens = MINUT / 10;
  }

  switch (units)
  {
    case 0:
      //0
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8  >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8 + 192 );
      digitalWrite(latchPin, HIGH);
      break;
    case 1:
      //1
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8  >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8 + 249);
      digitalWrite(latchPin, HIGH);
      break;
    case 2:
      //2
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8  >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8 + 164);
      digitalWrite(latchPin, HIGH);
      break;
    case 3:
      //3
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8 >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8 + 176);
      digitalWrite(latchPin, HIGH);
      break;
    case 4:
      //4
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8 >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8 + 153);
      digitalWrite(latchPin, HIGH);
      break;
    case 5:
      //5
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8 >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8 + 146);
      digitalWrite(latchPin, HIGH);
      break;
    case 6:
      //6
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8   >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8 + 130);
      digitalWrite(latchPin, HIGH);
      break;
    case 7:
      //7
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8  >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8 + 248);
      digitalWrite(latchPin, HIGH);
      break;
    case 8:
      //8
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8  >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8 + 128);
      digitalWrite(latchPin, HIGH);
      break;
    case 9:
      //9
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8  >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 8 + 144);
      digitalWrite(latchPin, HIGH);
      break;
  }
  delay(1);


  switch (tens)
  {
    case 0:
      //0
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 4  >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 4 + 192 );
      digitalWrite(latchPin, HIGH);
      break;
    case 1:
      //1
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 4   >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 4 + 249);
      digitalWrite(latchPin, HIGH);
      break;
    case 2:
      //2
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 4   >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 4 + 164);
      digitalWrite(latchPin, HIGH);
      break;
    case 3:
      //3
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 4   >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 4 + 176);
      digitalWrite(latchPin, HIGH);
      break;
    case 4:
      //4
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 4 >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 4 + 153);
      digitalWrite(latchPin, HIGH);
      break;
    case 5:
      //5
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 4   >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 4 + 146);
      digitalWrite(latchPin, HIGH);
      break;
    
  }
  delay(1);

  switch (hundreds)
  {
    case 0:
      //0
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2  >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2 + 64 );
      digitalWrite(latchPin, HIGH);
      break;
    case 1:
      //1
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2  >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2 + 121);
      digitalWrite(latchPin, HIGH);

      break;
    case 2:
      //2
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2  >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2 + 36);
      digitalWrite(latchPin, HIGH);
      break;
    case 3:
      //3
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2 >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2 + 48);
      digitalWrite(latchPin, HIGH);
      break;
    case 4:
      //4
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2 >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2 + 25);
      digitalWrite(latchPin, HIGH);
      break;
    case 5:
      //5
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2   >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2 + 18);
      digitalWrite(latchPin, HIGH);
      break;
    case 6:
      //6
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2   >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2 + 2);
      digitalWrite(latchPin, HIGH);
      break;
    case 7:
      //7
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2  >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2 + 120);
      digitalWrite(latchPin, HIGH);
      break;
    case 8:
      //8
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2  >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2 + 0);
      digitalWrite(latchPin, HIGH);
      break;
    case 9:
      //9
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2  >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift * 2 + 16);
      digitalWrite(latchPin, HIGH);
      break;

  }
  delay(1);
 
  switch (thousands)
  {
    case 0:
      //0
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift   >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift  + 192 );
      digitalWrite(latchPin, HIGH);
      //delay(500);
      break;
    case 1:
      //1
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift   >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift  + 249);
      digitalWrite(latchPin, HIGH);
      //delay(500);
      break;
    case 2:
      //2
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift   >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift  + 164);
      digitalWrite(latchPin, HIGH);
      //delay(500);
      break;
    case 3:
      //3
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift  >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift  + 176);
      digitalWrite(latchPin, HIGH);
      //delay(500);
      break;
    case 4:
      //4
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift  >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift  + 153);
      digitalWrite(latchPin, HIGH);
      //delay(500);
      break;
    case 5:
      //5
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift    >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift  + 146);
      digitalWrite(latchPin, HIGH);
      //delay(500);
      break;
    case 6:
      //6
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift    >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift  + 130);
      digitalWrite(latchPin, HIGH);
      //delay(500);
      break;
    case 7:
      //7
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift   >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift  + 248);
      digitalWrite(latchPin, HIGH);
      //delay(500);
      break;
    case 8:
      //8
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift   >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift  + 128);
      digitalWrite(latchPin, HIGH);

      break;
    case 9:
      //9
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, shift   >> 8 );
      shiftOut(dataPin, clockPin, MSBFIRST, shift  + 152);
      digitalWrite(latchPin, HIGH);
      break;
  }
  delay(1);
  //alarm section
  if (HOUR == alarmHour && MINUT == alarmMinute)
  {
    digitalWrite(13, HIGH);
  }
  else
  {
    digitalWrite(13, LOW);
  }

}

Set the time

Arduino
since the ds1307 is susceptible to drift away from the correct time. This program allows you to set the time through the Serial Monitor. When you see that the time is not correct simply plugin the rtc module into the arduino and upload this program. Then enter the Serial Monitor and then set the correct date, month, year, time. Then simply upload the other program and the correct time will be displayed on the 7 segment display.
/*
  RealTimeClockDS1307 - library to control a DS1307 RTC module
  Copyright (c) 2011 David H. Brown. All rights reserved
  
  Much thanks to John Waters and Maurice Ribble for their
  earlier and very helpful work (even if I didn't wind up
  using any of their code):
   - http://combustory.com/wiki/index.php/RTC1307_-_Real_Time_Clock
   - http://www.glacialwanderer.com/hobbyrobotics/?p=12

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/


#include <Wire.h>
#include <RealTimeClockDS1307.h>

//RealTimeClock RTC;//=new RealTimeClock();

#define Display_Clock_Every_N_Seconds 1
#define Display_ShortHelp_Every_N_Seconds 25
//#define TEST_Squarewave
//#define TEST_StopStart
//#define TEST_1224Switch

int count=0;
char formatted[] = "00-00-00 00:00:00x";

void setup() {
//  Wire.begin();
  Serial.begin(9600);
}
 
void loop() {
  if(Serial.available())
  {
    processCommand();
  }
  delay(1000);
  RTC.readClock();
  count++;
  if(count % Display_Clock_Every_N_Seconds == 0){
    Serial.print(count);
    Serial.print(": ");
    RTC.getFormatted(formatted);
    Serial.print(formatted);
    Serial.println();
  }
  
  if(count % Display_ShortHelp_Every_N_Seconds == 0) {
    Serial.println("Send ? for a list of commands.");
  }
#ifdef TEST_Squarewave
if(count%10 == 0)
{
  switch(count/10 % 6)
  {
    case 0:
    Serial.print("Squarewave disabled (low impedance): ");
    RTC.sqwDisable(0);
    Serial.println((int) RTC.readData(7));
    break;
    case 1:
    Serial.print("Squarewave disabled (high impedance): ");
    RTC.sqwDisable(1);
    Serial.println((int) RTC.readData(7));
    break;
    case 2:
    Serial.println("Squarewave enabled at 1 Hz");
    RTC.sqwEnable(RTC.SQW_1Hz);
    break;
    case 3:
    Serial.println("Squarewave enabled at 4.096 kHz");
    RTC.sqwEnable(RTC.SQW_4kHz);
    break;
    case 4:
    Serial.println("Squarewave enabled at 8.192 kHz");
    RTC.sqwEnable(RTC.SQW_8kHz);
    break;
    case 5:
    Serial.println("Squarewave enabled at 32.768 kHz");
    RTC.sqwEnable(RTC.SQW_32kHz);
    break;
    default:
    Serial.println("Squarewave test not defined");
  }//switch
}
#endif

#ifdef TEST_StopStart
if(count%10 == 0)
{
  if(!RTC.isStopped()) 
  {
    if(RTC.getSeconds() < 45) 
    {
      Serial.println("Stopping clock for 10 seconds");
      RTC.stop();
    }//if we have enough time
  } else {
    RTC.setSeconds(RTC.getSeconds()+11);
    RTC.start();
    Serial.println("Adding 11 seconds and restarting clock");
  }
}//if on a multiple of 10 counts
#endif

#ifdef TEST_1224Switch  
  if(count%10 == 0)
  {
    if(count %20 == 0)
    {
      Serial.println("switching to 12-hour time");
      RTC.switchTo12h();
      RTC.setClock();
    }
    else
    {
      Serial.println("switching to 24-hour time");
      RTC.switchTo24h();
      RTC.setClock();
    }
  }
#endif
}

void processCommand() {
  if(!Serial.available()) { return; }
  char command = Serial.read();
  int in,in2;
  switch(command)
  {
    case 'H':
    case 'h':
    in=SerialReadPosInt();
    RTC.setHours(in);
    RTC.setClock();
    Serial.print("Setting hours to ");
    Serial.println(in);
    break;
    case 'I':
    case 'i':
    in=SerialReadPosInt();
    RTC.setMinutes(in);
    RTC.setClock();
    Serial.print("Setting minutes to ");
    Serial.println(in);
    break;
    case 'S':
    case 's':
    in=SerialReadPosInt();
    RTC.setSeconds(in);
    RTC.setClock();
    Serial.print("Setting seconds to ");
    Serial.println(in);
    break;
    case 'Y':
    case 'y':
    in=SerialReadPosInt();
    RTC.setYear(in);
    RTC.setClock();
    Serial.print("Setting year to ");
    Serial.println(in);
    break;
    case 'M':
    case 'm':
    in=SerialReadPosInt();
    RTC.setMonth(in);
    RTC.setClock();
    Serial.print("Setting month to ");
    Serial.println(in);
    break;
    case 'D':
    case 'd':
    in=SerialReadPosInt();
    RTC.setDate(in);
    RTC.setClock();
    Serial.print("Setting date to ");
    Serial.println(in);
    break;
    case 'W':
    Serial.print("Day of week is ");
    Serial.println((int) RTC.getDayOfWeek());
    break;
    case 'w':
    in=SerialReadPosInt();
    RTC.setDayOfWeek(in);
    RTC.setClock();
    Serial.print("Setting day of week to ");
    Serial.println(in);
    break;
    
    case 't':
    case 'T':
    if(RTC.is12hour()) {
      RTC.switchTo24h();
      Serial.println("Switching to 24-hour clock.");
    } else {
      RTC.switchTo12h();
      Serial.println("Switching to 12-hour clock.");
    }
    RTC.setClock();
    break;
    
    case 'A':
    case 'a':
    if(RTC.is12hour()) {
      RTC.setAM();
      RTC.setClock();
      Serial.println("Set AM.");
    } else {
      Serial.println("(Set hours only in 24-hour mode.)");
    }
    break;
    
    case 'P':
    case 'p':
    if(RTC.is12hour()) {
      RTC.setPM();
      RTC.setClock();
      Serial.println("Set PM.");
    } else {
      Serial.println("(Set hours only in 24-hour mode.)");
    }
    break;

    case 'q':
    RTC.sqwEnable(RTC.SQW_1Hz);
    Serial.println("Square wave output set to 1Hz");
    break;
    case 'Q':
    RTC.sqwDisable(0);
    Serial.println("Square wave output disabled (low)");
    break;
    
    case 'z':
    RTC.start();
    Serial.println("Clock oscillator started.");
    break;
    case 'Z':
    RTC.stop();
    Serial.println("Clock oscillator stopped.");
    break;
    
    case '>':
    in=SerialReadPosInt();
    in2=SerialReadPosInt();
    RTC.writeData(in, in2);
    Serial.print("Write to register ");
    Serial.print(in);
    Serial.print(" the value ");
    Serial.println(in2);
    break;    
    case '<':
    in=SerialReadPosInt();
    in2=RTC.readData(in);
    Serial.print("Read from register ");
    Serial.print(in);
    Serial.print(" the value ");
    Serial.println(in2);
    break;

    default:
    Serial.println("Unknown command. Try these:");
    Serial.println(" h## - set Hours       d## - set Date");
    Serial.println(" i## - set mInutes     m## - set Month");
    Serial.println(" s## - set Seconds     y## - set Year");
    Serial.println(" w## - set arbitrary day of Week");
    Serial.println(" t   - toggle 24-hour mode");
    Serial.println(" a   - set AM          p   - set PM");
    Serial.println();
    Serial.println(" z   - start clock     Z   - stop clock");
    Serial.println(" q   - SQW/OUT = 1Hz   Q   - stop SQW/OUT");
    Serial.println();
    Serial.println(" >##,###  - write to register ## the value ###");
    Serial.println(" <##      - read the value in register ##");
    
  }//switch on command
  
}

//read in numeric characters until something else
//or no more data is available on serial.
int SerialReadPosInt() {
  int i = 0;
  boolean done=false;
  while(Serial.available() && !done)
  {
    char c = Serial.read();
    if (c >= '0' && c <='9')
    {
      i = i * 10 + (c-'0');
    }
    else 
    {
      done = true;
    }
  }
  return i;
}

RealTimeClockDS1307.cpp

C/C++
This is one of the library files of the real time clock. Create a folder named "RealTimeClockDS1307" and copy this into this folder. That's all you got to do. No need to compile it.
/*
  RealTimeClockDS1307 - library to control a DS1307 RTC module
  Copyright (c) 2011 David H. Brown. All rights reserved

  v0.92 Updated for Arduino 1.00; not re-tested on earlier versions
  
  Much thanks to John Waters and Maurice Ribble for their
  earlier and very helpful work (even if I didn't wind up
  using any of their code):
   - http://combustory.com/wiki/index.php/RTC1307_-_Real_Time_Clock
   - http://www.glacialwanderer.com/hobbyrobotics/?p=12

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
 
/******************************************************************************
 * Includes
 ******************************************************************************/

#include "RealTimeClockDS1307.h"
#include <Wire.h>

/******************************************************************************
 * Definitions
 ******************************************************************************/

#define DS1307_I2C_ADDRESS 0x68  // This is the I2C address

/******************************************************************************
 * Constructors
 ******************************************************************************/

RealTimeClockDS1307::RealTimeClockDS1307()
{
  Wire.begin();
  //must NOT attempt to read the clock before
  //Wire.begin() has not been called; readClock() will hang.
  //Fortunately, it seems that you can call Wire.begin()
  //multiple times with no adverse effect).
} 

/******************************************************************************
 * User API
 ******************************************************************************/

/***** CHIP READ/WRITE ******/

void RealTimeClockDS1307::readClock()
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write((uint8_t) 0x00);
  Wire.endTransmission();
 
  Wire.requestFrom(DS1307_I2C_ADDRESS, 8);
  _reg0_sec = Wire.read();
  _reg1_min = Wire.read();
  _reg2_hour = Wire.read();
  _reg3_day = Wire.read();
  _reg4_date = Wire.read();
  _reg5_month = Wire.read();
  _reg6_year = Wire.read();
  _reg7_sqw = Wire.read();
}

void RealTimeClockDS1307::setClock()
{
  //to be paranoid, we're going to first stop the clock
  //to ensure we don't have rollovers while we're
  //writing:
  writeData(0,0x80);
  //now, we'll write everything *except* the second
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write((uint8_t) 0x01);
  Wire.write(_reg1_min);
  Wire.write(_reg2_hour);
  Wire.write(_reg3_day);
  Wire.write(_reg4_date);
  Wire.write(_reg5_month);
  Wire.write(_reg6_year);
  Wire.endTransmission();
  //now, we'll write the seconds; we didn't have to keep
  //track of whether the clock was already running, because
  //_reg0_sec already knows what we want it to be. This
  //will restart the clock as it writes the new seconds value.
  writeData(0,_reg0_sec); 
}

void RealTimeClockDS1307::stop()
{
  //"Bit 7 of register 0 is the clock halt (CH) bit. 
  //When this bit is set to a 1, the oscillator is disabled."
  _reg0_sec = _reg0_sec | 0x80;
  writeData(0,_reg0_sec);
}
void RealTimeClockDS1307::start()
{
  //"Bit 7 of register 0 is the clock halt (CH) bit. 
  //When this bit is set to a 1, the oscillator is disabled."
  _reg0_sec = _reg0_sec & ~0x80;
  writeData(0,_reg0_sec);
}

void RealTimeClockDS1307::writeData(byte regNo, byte value)
{
  if(regNo > 0x3F) { return; }
   Wire.beginTransmission(DS1307_I2C_ADDRESS);
   Wire.write(regNo);
   Wire.write(value);
   Wire.endTransmission();
}

void RealTimeClockDS1307::writeData(byte regNo, void * source, int length)
{
  char * p = (char*) source;
  if(regNo > 0x3F || length > 0x3F) { return; }
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(regNo);
  for(int i=0; i<length; i++) {
    Wire.write(*p);
    p++;
  }
  Wire.endTransmission();
}

byte RealTimeClockDS1307::readData(byte regNo)
{
  if(regNo > 0x3F) { return 0xff; }
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(regNo);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_I2C_ADDRESS, 1);
  return Wire.read();
}

void RealTimeClockDS1307::readData(byte regNo, void * dest, int length)
{
  char * p = (char*) dest;
  if(regNo > 0x3F || length > 0x3F) { return; }
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(regNo);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_I2C_ADDRESS, length);
  for(int i=0; i<length; i++) {
    *p=Wire.read();
    p++;
  }
}


void RealTimeClockDS1307::sqwEnable(byte frequency)
{
  if(frequency > 3) { return; }
  //bit 4 is enable (0x10);
  //bit 7 is current output state if disabled
  _reg7_sqw = _reg7_sqw & 0x80 | 0x10 | frequency;
  writeData(0x07, _reg7_sqw);
}

void RealTimeClockDS1307::sqwDisable(boolean outputLevel)
{
  //bit 7 0x80 output + bit 4 0x10 enable both to zero, 
  //the OR with the boolean shifted up to bit 7
  _reg7_sqw = _reg7_sqw & ~0x90 | (outputLevel << 7);
  writeData(0x07, _reg7_sqw);
  //note: per the data sheet, "OUT (Output control): This bit controls 
  //the output level of the SQW/OUT pin when the square wave
  //output is disabled. If SQWE = 0, the logic level on the 
  //SQW/OUT pin is 1 if OUT = 1 and is 0 if OUT = 0."
  //"The SQW/OUT pin is open drain and requires an external 
  //pull-up resistor."
  //It is worth mentioning that on the Sparkfun breakout board,
  //BOB-00099, a LED connected to the SQW pin through a resistor to
  //Vcc+5V illuminated when OUT=0 and was dark when OUT=1, the 
  //opposite of what I expected until I remembered that it is 
  //an open drain (google it if you need to). Basically, they don't
  //so much mean a logic level (e.g., +3.3V rel Gnd) as they mean 
  //high or low *impeadance* to ground (drain). So High is basically
  //an open switch. Low connects to ground.
}


/***** GETTERS ******/

boolean RealTimeClockDS1307::is12hour() 
{
  //12-hour mode has bit 6 of the hour register set high
  return ((_reg2_hour & 0x40) == 0x40);
}
boolean RealTimeClockDS1307::isPM()
{
  //if in 12-hour mode, but 5 of the hour register indicates PM
  if(is12hour()) {
    return ((_reg2_hour & 0x20) == 0x20);
  }
  //otherwise, let's consider any time with the hour >11 to be PM:
  return (getHours() > 11);
}
boolean RealTimeClockDS1307::isStopped()
{
  //bit 7 of the seconds register stopps the clock when high
  return ((_reg0_sec & 0x80) == 0x80);
}

int RealTimeClockDS1307::getHours()
{
  if(is12hour()) { 
    //do not include bit 5, the am/pm indicator
    return bcdToDec(_reg2_hour & 0x1f);
  }
  //bits 4-5 are tens of hours
  return bcdToDec(_reg2_hour & 0x3f);
}
int RealTimeClockDS1307::getMinutes()
{
  //could mask with 0x7f but shouldn't need to
  return bcdToDec(_reg1_min);
}
int RealTimeClockDS1307::getSeconds()
{
  //need to mask oscillator start/stop bit 7
  return bcdToDec(_reg0_sec & 0x7f);
}
int RealTimeClockDS1307::getYear()
{
  return bcdToDec(_reg6_year);
}
int RealTimeClockDS1307::getMonth()
{
  //could mask with 0x1f but shouldn't need to
  return bcdToDec(_reg5_month);
}
int RealTimeClockDS1307::getDate()
{
  //could mask with 0x3f but shouldn't need to
  return bcdToDec(_reg4_date);
}
int RealTimeClockDS1307::getDay()
{
  return getDate();
}
int RealTimeClockDS1307::getDayOfWeek()
{
  //could mask with 0x07 but shouldn't need to
  return bcdToDec(_reg3_day);
}

void RealTimeClockDS1307::getFormatted(char * buffer)
{
  int i=0;
  //target string format: YY-MM-DD HH:II:SS
  buffer[i++]=highNybbleToASCII(_reg6_year);
  buffer[i++]=lowNybbleToASCII(_reg6_year);
  buffer[i++]='-';
  buffer[i++]=highNybbleToASCII(_reg5_month & 0x1f);
  buffer[i++]=lowNybbleToASCII(_reg5_month);
  buffer[i++]='-';
  buffer[i++]=highNybbleToASCII(_reg4_date & 0x3f);
  buffer[i++]=lowNybbleToASCII(_reg4_date);
  buffer[i++]=' ';
  if(is12hour()) {
    buffer[i++]=highNybbleToASCII(_reg2_hour & 0x1f);
  } else {
    buffer[i++]=highNybbleToASCII(_reg2_hour & 0x3f);
  }
  buffer[i++]=lowNybbleToASCII(_reg2_hour);
  buffer[i++]=':';
  buffer[i++]=highNybbleToASCII(_reg1_min & 0x7f);
  buffer[i++]=lowNybbleToASCII(_reg1_min);
  buffer[i++]=':';
  buffer[i++]=highNybbleToASCII(_reg0_sec & 0x7f);
  buffer[i++]=lowNybbleToASCII(_reg0_sec);
  if(is12hour()) {
    if(isPM()) {
      buffer[i++]='P';
    } else {
      buffer[i++]='A';
    }
  }
  buffer[i++]=0x00;
}

void RealTimeClockDS1307::getFormatted2k(char * buffer)
{
  buffer[0]='2';
  buffer[1]='0';
  getFormatted(&buffer[2]);
}

/**** SETTERS *****/

void RealTimeClockDS1307::setSeconds(int s)
{
  if (s < 60 && s >=0)
  {
    //need to preserve oscillator bit
    _reg0_sec = decToBcd(s) | (_reg0_sec & 0x80);
  }
}
void RealTimeClockDS1307::setMinutes(int m)
{
  if (m < 60 && m >=0)
  {
    _reg1_min = decToBcd(m);
  }
}
void RealTimeClockDS1307::setHours(int h)
{
  if (is12hour())
  {
    if (h >= 1 && h <=12)
    {
      //preserve 12/24 and AM/PM bits
      _reg2_hour = decToBcd(h) | (_reg2_hour & 0x60);
    }
  } else {
    if (h >= 0 && h <=24)
   {
      //preserve 12/24 bit
      _reg2_hour = decToBcd(h) | (_reg2_hour & 0x40);
   }
  }//else
}//setHours

void RealTimeClockDS1307::set24h()
{
  //"Bit 6 of the hours register is defined as the
  //"12- or 24-hour mode select bit.
  //"When high, the 12-hour mode is selected"
  //So, mask the curent value with the complement turn off that bit:
  _reg2_hour = _reg2_hour & ~0x40; 
}
void RealTimeClockDS1307::setAM()
{
  //"In the 12-hour mode, bit 5 is the AM/PM bit with logic high being PM"
  //so we need to OR with 0x40 to set 12-hour mode and also
  //turn off the PM bit by masking with the complement
  _reg2_hour = _reg2_hour & ~0x20 | 0x40;
}
void RealTimeClockDS1307::setPM()
{
  //"In the 12-hour mode, bit 5 is the AM/PM bit with logic high being PM"
  //so we need to OR with 0x40 and 0x20 to set 12-hour mode and also
  //turn on the PM bit:
  _reg2_hour = _reg2_hour | 0x60;
}

void RealTimeClockDS1307::switchTo12h()
{
  if(is12hour()) { return; }
  int h = getHours();
  if (h < 12) {
    setAM();
  } else {
    h = h-12;
    setPM();
  }
  if (h==0)
  {
    h=12;
  }
  setHours(h);
}
void RealTimeClockDS1307::switchTo24h()
{
  if(!is12hour()) { return ; }
  int h = getHours();
  if(h==12) {//12 PM is just 12; 12 AM is 0 hours.
    h = 0;
  }
  if (isPM())
  {//if it was 12 PM, then h=0 above and so we're back to 12:
    h = h+12;
  }
  set24h();
  setHours(h);
}

void RealTimeClockDS1307::setDayOfWeek(int d)
{
  if (d > 0 && d < 8)
  {
    _reg3_day = decToBcd(d);
  }
}

void RealTimeClockDS1307::setDate(int d)
{
  if (d > 0 && d < 32)
  {
    _reg4_date = decToBcd(d);
  }
}
void RealTimeClockDS1307::setDay(int d)
{
  setDate(d);
}

void RealTimeClockDS1307::setMonth(int m)
{
  if (m > 0 && m < 13)
  {
    _reg5_month = decToBcd(m);
  }
}
void RealTimeClockDS1307::setYear(int y)
{
  if (y >= 0 && y <100)
  {
    _reg6_year = decToBcd(y);
  }
}



/*****************************************
 * Private methods
 *****************************************/
byte RealTimeClockDS1307::decToBcd(byte b)
{
  return ( ((b/10) << 4) + (b%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte RealTimeClockDS1307::bcdToDec(byte b)
{
  return ( ((b >> 4)*10) + (b%16) );
}

char RealTimeClockDS1307::lowNybbleToASCII(byte b) 
{
  b = b & 0x0f;
  if(b < 10) {
    //0 is ASCII 48
    return 48+b;
  }
  //A is ASCII 55
  return 55+b;
}
char RealTimeClockDS1307::highNybbleToASCII(byte b)
{
  return lowNybbleToASCII(b >> 4);
}

/***** INSTANCE *******/

RealTimeClockDS1307 RTC = RealTimeClockDS1307();

Readme

Clojure
Copy this also into the same folder you created named "RealTimeClockDS1307".
My goal in creating yet another DS1307 library was to provide
easy access to some of the other functions I needed from the chip,
specifically its square wave output and its battery-backed RAM.

## Documentation
@todo Mostly comments in `RealTimeClockDS1307.h`

## Examples (in /examples folder)

- `RealTimeClockDS1307_Test.pde` allow you to turn the clock on/off,
set date/time, set 12/24h, [de]activate the square wave, and
read/write memory from the Serial Monitor.

- `RealTimeClockDS1307.fz` is a Fritzing breadboard layout showing
the basic hookup of the Sparkfun RTC module to an Arduino. Included
is an optional resistor+LED to show the square wave (note that it's
an open drain, so you hook up to it rather differently than, say, 
pin 13).

## Changelog

##### Version 0.95
* Reverse renaming of getDate() and setDate(), now getDay() is calling getDate() and setDay() is calling setDate()
* Readme improvements

##### Version 0.94
* changed getDate() to getDay() and setDate() to setDay()
* updated keywords.txt
* updated example

##### Version 0.93
* added keywords.txt for syntax highlighting

##### Version 0.92 RC
* Updated for Arduino 1.00; testing with Andreas Giemza (hurik)

##### Version 0.91
* added multi-byte read/write

##### Version 0.9 RC
* initial release

## Future
 - web page documentation

## Credits

Much thanks to John Waters and Maurice Ribble for their
earlier and very helpful work (even if I didn't wind up
using any of their code):

- [http://combustory.com/wiki/index.php/RTC1307_-_Real_Time_Clock](http://combustory.com/wiki/index.php/RTC1307_-_Real_Time_Clock)
- [http://www.glacialwanderer.com/hobbyrobotics/?p=12](http://www.glacialwanderer.com/hobbyrobotics/?p=12)

## Copyright

RealTimeClockDS1307 - library to control a DS1307 RTC module
Copyright (c) 2011 David H. Brown. All rights reserved

## License

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

RealTimeClockDS1307.h

C/C++
This is the main header file of the real time clock. Copy this also into the folder you previously created named "RealTimeClockDS1307". Now you have all the files for the Real Time Clock. Enter the arduino ide and under the 'Sketch' menu click on the 'include library' option and then search your folder under the 'Add .ZIP Library". This will do the trick and you will now be able to set the time in the RTC module.
/*
  RealTimeClockDS1307 - library to control a DS1307 RTC module
  Copyright (c) 2011 David H. Brown. All rights reserved

  v0.92 Updated for Arduino 1.00; not re-tested on earlier versions
  
  Much thanks to John Waters and Maurice Ribble for their
  earlier and very helpful work (even if I didn't wind up
  using any of their code):
   - http://combustory.com/wiki/index.php/RTC1307_-_Real_Time_Clock
   - http://www.glacialwanderer.com/hobbyrobotics/?p=12

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef RealTimeClockDS1307_h
#define RealTimeClockDS1307_h

  #if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
  #else
  #include "WProgram.h"
  #endif

//#include <HardwareSerial.h>
//#include <WConstants.h> //need/want 'boolean' and 'byte' types used by Arduino
//#undef round is required to avoid a compile-time
//"expected unqualified-id before 'double'" error in math.h
//see: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1247924528/3
#undef round 
#include <Wire.h>

#define ARDUINO_PIN_T uint8_t

class RealTimeClockDS1307
{
  private:
    byte _reg0_sec;
    byte _reg1_min;
    byte _reg2_hour;
    byte _reg3_day;
    byte _reg4_date;
    byte _reg5_month;
    byte _reg6_year;
    byte _reg7_sqw;
    byte decToBcd(byte);
    byte bcdToDec(byte);
    char lowNybbleToASCII(byte);
    char highNybbleToASCII(byte);
  public:
    RealTimeClockDS1307();
    void readClock();//read registers (incl sqw) to local store
    void setClock();//update clock registers from local store
    void stop();//immediate; does not require setClock();
    void start();//immediate; does not require setClock();
    void sqwEnable(byte);//enable the square wave with the specified frequency
    void sqwDisable(boolean);//disable the square wave, setting output either high or low
    void writeData(byte, byte);//write a single value to a register
    void writeData(byte, void *, int);//write several values consecutively
    byte readData(byte);//read a single value from a register
    void readData(byte, void *, int);//read several values into a buffer

    int getHours();
    int getMinutes();
    int getSeconds();
    int getYear();
    int getMonth();
    int getDate();
    int getDay();
    int getDayOfWeek();
    boolean is12hour();
    boolean isPM();
    boolean isStopped();
    //getFormatted writes into a char array provided by you. Format is:
    // YY-MM-DD HH:II:SS   ... plus "A" or "P" if in 12-hour mode
    //and of course a NULL terminator. So, [18] for 24h or [19] for 12h
    void getFormatted(char *);//see comment above
    void getFormatted2k(char *);//as getFormatted, but with "20" prepended

    //must also call setClock() after any of these
    //before next readClock(). Note that invalid dates are not
    //corrected by the clock. All the clock knows is when it should 
    //roll over to the next month rather than the next date in the same month.
    void setSeconds(int);
    void setMinutes(int);
    //setHours rejects values out of range for the current 12/24 mode
    void setHours(int);
    void setAM();//does not consider hours; see switchTo24()
    void setPM();//does not consider hours; see switchTo24()
    void set24h();//does not consider hours; see switchTo24()
    void switchTo24h();//returns immediately if already 24h
    void switchTo12h();//returns immediately if already 12h
    void setDayOfWeek(int);//incremented at midnight; not set by date (no fixed meaning)
    void setDate(int);//allows 1-31 for *all* months.
    void setDay(int);
    void setMonth(int);
    void setYear(int);

    //squarewave frequencies:
    static const byte SQW_1Hz=0x00;
    static const byte SQW_4kHz=0x01;//actually 4.096kHz
    static const byte SQW_8kHz=0x02;//actually 8.192kHz
    static const byte SQW_32kHz=0x03;//actually 32.768kHz
};

extern RealTimeClockDS1307 RTC;

#endif

another file

C/C++
add this to the 'RealTimeClockDS1307' folder.
#########################################
# Syntax Coloring Map RealTimeClockDS1307
#########################################


#######################################
# Instances (KEYWORD2)
#######################################
RTC	KEYWORD2

#########################################
# Methods and Functions (KEYWORD2)
#########################################
readClock	KEYWORD2
setClock	KEYWORD2
stop	KEYWORD2
start	KEYWORD2
sqwEnable	KEYWORD2
sqwDisable	KEYWORD2
writeData	KEYWORD2
readData	KEYWORD2

getHours	KEYWORD2
getMinutes	KEYWORD2
getSeconds	KEYWORD2
getYear	KEYWORD2
getMonth	KEYWORD2
getDate	KEYWORD2
getDay	KEYWORD2
getDayOfWeek	KEYWORD2
is12hour	KEYWORD2
isPM	KEYWORD2
isStopped	KEYWORD2
getFormatted	KEYWORD2
getFormatted2k	KEYWORD2

setSeconds	KEYWORD2
setMinutes	KEYWORD2
setHours	KEYWORD2
setAM	KEYWORD2
setPM	KEYWORD2
set24h	KEYWORD2
switchTo24h	KEYWORD2
switchTo12h	KEYWORD2
setDayOfWeek	KEYWORD2
setDate	KEYWORD2
setDay	KEYWORD2
setMonth	KEYWORD2
setYear	KEYWORD2

#########################################
# Constants (LITERAL1)
#########################################
SQW_1Hz	LITERAL1
SQW_4kHz	LITERAL1
SQW_8kHz	LITERAL1
SQW_32kHz	LITERAL1

RTClib files

C#
create a folder named 'RTClib' and add the following files into it
#########################################
# Syntax Coloring Map RealTimeClockDS1307
#########################################


#######################################
# Instances (KEYWORD2)
#######################################
RTC	KEYWORD2

#########################################
# Methods and Functions (KEYWORD2)
#########################################
readClock	KEYWORD2
setClock	KEYWORD2
stop	KEYWORD2
start	KEYWORD2
sqwEnable	KEYWORD2
sqwDisable	KEYWORD2
writeData	KEYWORD2
readData	KEYWORD2

getHours	KEYWORD2
getMinutes	KEYWORD2
getSeconds	KEYWORD2
getYear	KEYWORD2
getMonth	KEYWORD2
getDate	KEYWORD2
getDay	KEYWORD2
getDayOfWeek	KEYWORD2
is12hour	KEYWORD2
isPM	KEYWORD2
isStopped	KEYWORD2
getFormatted	KEYWORD2
getFormatted2k	KEYWORD2

setSeconds	KEYWORD2
setMinutes	KEYWORD2
setHours	KEYWORD2
setAM	KEYWORD2
setPM	KEYWORD2
set24h	KEYWORD2
switchTo24h	KEYWORD2
switchTo12h	KEYWORD2
setDayOfWeek	KEYWORD2
setDate	KEYWORD2
setDay	KEYWORD2
setMonth	KEYWORD2
setYear	KEYWORD2

#########################################
# Constants (LITERAL1)
#########################################
SQW_1Hz	LITERAL1
SQW_4kHz	LITERAL1
SQW_8kHz	LITERAL1
SQW_32kHz	LITERAL1

library.properties(name)

C/C++
add this to the RTClib folder
My goal in creating yet another DS1307 library was to provide
easy access to some of the other functions I needed from the chip,
specifically its square wave output and its battery-backed RAM.

## Documentation
@todo Mostly comments in `RealTimeClockDS1307.h`

## Examples (in /examples folder)

- `RealTimeClockDS1307_Test.pde` allow you to turn the clock on/off,
set date/time, set 12/24h, [de]activate the square wave, and
read/write memory from the Serial Monitor.

- `RealTimeClockDS1307.fz` is a Fritzing breadboard layout showing
the basic hookup of the Sparkfun RTC module to an Arduino. Included
is an optional resistor+LED to show the square wave (note that it's
an open drain, so you hook up to it rather differently than, say, 
pin 13).

## Changelog

##### Version 0.95
* Reverse renaming of getDate() and setDate(), now getDay() is calling getDate() and setDay() is calling setDate()
* Readme improvements

##### Version 0.94
* changed getDate() to getDay() and setDate() to setDay()
* updated keywords.txt
* updated example

##### Version 0.93
* added keywords.txt for syntax highlighting

##### Version 0.92 RC
* Updated for Arduino 1.00; testing with Andreas Giemza (hurik)

##### Version 0.91
* added multi-byte read/write

##### Version 0.9 RC
* initial release

## Future
 - web page documentation

## Credits

Much thanks to John Waters and Maurice Ribble for their
earlier and very helpful work (even if I didn't wind up
using any of their code):

- [http://combustory.com/wiki/index.php/RTC1307_-_Real_Time_Clock](http://combustory.com/wiki/index.php/RTC1307_-_Real_Time_Clock)
- [http://www.glacialwanderer.com/hobbyrobotics/?p=12](http://www.glacialwanderer.com/hobbyrobotics/?p=12)

## Copyright

RealTimeClockDS1307 - library to control a DS1307 RTC module
Copyright (c) 2011 David H. Brown. All rights reserved

## License

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

RTClib

C/C++
add this to the RTClib folder
/*
  RealTimeClockDS1307 - library to control a DS1307 RTC module
  Copyright (c) 2011 David H. Brown. All rights reserved

  v0.92 Updated for Arduino 1.00; not re-tested on earlier versions
  
  Much thanks to John Waters and Maurice Ribble for their
  earlier and very helpful work (even if I didn't wind up
  using any of their code):
   - http://combustory.com/wiki/index.php/RTC1307_-_Real_Time_Clock
   - http://www.glacialwanderer.com/hobbyrobotics/?p=12

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
 
/******************************************************************************
 * Includes
 ******************************************************************************/

#include "RealTimeClockDS1307.h"
#include <Wire.h>

/******************************************************************************
 * Definitions
 ******************************************************************************/

#define DS1307_I2C_ADDRESS 0x68  // This is the I2C address

/******************************************************************************
 * Constructors
 ******************************************************************************/

RealTimeClockDS1307::RealTimeClockDS1307()
{
  Wire.begin();
  //must NOT attempt to read the clock before
  //Wire.begin() has not been called; readClock() will hang.
  //Fortunately, it seems that you can call Wire.begin()
  //multiple times with no adverse effect).
} 

/******************************************************************************
 * User API
 ******************************************************************************/

/***** CHIP READ/WRITE ******/

void RealTimeClockDS1307::readClock()
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write((uint8_t) 0x00);
  Wire.endTransmission();
 
  Wire.requestFrom(DS1307_I2C_ADDRESS, 8);
  _reg0_sec = Wire.read();
  _reg1_min = Wire.read();
  _reg2_hour = Wire.read();
  _reg3_day = Wire.read();
  _reg4_date = Wire.read();
  _reg5_month = Wire.read();
  _reg6_year = Wire.read();
  _reg7_sqw = Wire.read();
}

void RealTimeClockDS1307::setClock()
{
  //to be paranoid, we're going to first stop the clock
  //to ensure we don't have rollovers while we're
  //writing:
  writeData(0,0x80);
  //now, we'll write everything *except* the second
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write((uint8_t) 0x01);
  Wire.write(_reg1_min);
  Wire.write(_reg2_hour);
  Wire.write(_reg3_day);
  Wire.write(_reg4_date);
  Wire.write(_reg5_month);
  Wire.write(_reg6_year);
  Wire.endTransmission();
  //now, we'll write the seconds; we didn't have to keep
  //track of whether the clock was already running, because
  //_reg0_sec already knows what we want it to be. This
  //will restart the clock as it writes the new seconds value.
  writeData(0,_reg0_sec); 
}

void RealTimeClockDS1307::stop()
{
  //"Bit 7 of register 0 is the clock halt (CH) bit. 
  //When this bit is set to a 1, the oscillator is disabled."
  _reg0_sec = _reg0_sec | 0x80;
  writeData(0,_reg0_sec);
}
void RealTimeClockDS1307::start()
{
  //"Bit 7 of register 0 is the clock halt (CH) bit. 
  //When this bit is set to a 1, the oscillator is disabled."
  _reg0_sec = _reg0_sec & ~0x80;
  writeData(0,_reg0_sec);
}

void RealTimeClockDS1307::writeData(byte regNo, byte value)
{
  if(regNo > 0x3F) { return; }
   Wire.beginTransmission(DS1307_I2C_ADDRESS);
   Wire.write(regNo);
   Wire.write(value);
   Wire.endTransmission();
}

void RealTimeClockDS1307::writeData(byte regNo, void * source, int length)
{
  char * p = (char*) source;
  if(regNo > 0x3F || length > 0x3F) { return; }
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(regNo);
  for(int i=0; i<length; i++) {
    Wire.write(*p);
    p++;
  }
  Wire.endTransmission();
}

byte RealTimeClockDS1307::readData(byte regNo)
{
  if(regNo > 0x3F) { return 0xff; }
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(regNo);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_I2C_ADDRESS, 1);
  return Wire.read();
}

void RealTimeClockDS1307::readData(byte regNo, void * dest, int length)
{
  char * p = (char*) dest;
  if(regNo > 0x3F || length > 0x3F) { return; }
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(regNo);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_I2C_ADDRESS, length);
  for(int i=0; i<length; i++) {
    *p=Wire.read();
    p++;
  }
}


void RealTimeClockDS1307::sqwEnable(byte frequency)
{
  if(frequency > 3) { return; }
  //bit 4 is enable (0x10);
  //bit 7 is current output state if disabled
  _reg7_sqw = _reg7_sqw & 0x80 | 0x10 | frequency;
  writeData(0x07, _reg7_sqw);
}

void RealTimeClockDS1307::sqwDisable(boolean outputLevel)
{
  //bit 7 0x80 output + bit 4 0x10 enable both to zero, 
  //the OR with the boolean shifted up to bit 7
  _reg7_sqw = _reg7_sqw & ~0x90 | (outputLevel << 7);
  writeData(0x07, _reg7_sqw);
  //note: per the data sheet, "OUT (Output control): This bit controls 
  //the output level of the SQW/OUT pin when the square wave
  //output is disabled. If SQWE = 0, the logic level on the 
  //SQW/OUT pin is 1 if OUT = 1 and is 0 if OUT = 0."
  //"The SQW/OUT pin is open drain and requires an external 
  //pull-up resistor."
  //It is worth mentioning that on the Sparkfun breakout board,
  //BOB-00099, a LED connected to the SQW pin through a resistor to
  //Vcc+5V illuminated when OUT=0 and was dark when OUT=1, the 
  //opposite of what I expected until I remembered that it is 
  //an open drain (google it if you need to). Basically, they don't
  //so much mean a logic level (e.g., +3.3V rel Gnd) as they mean 
  //high or low *impeadance* to ground (drain). So High is basically
  //an open switch. Low connects to ground.
}


/***** GETTERS ******/

boolean RealTimeClockDS1307::is12hour() 
{
  //12-hour mode has bit 6 of the hour register set high
  return ((_reg2_hour & 0x40) == 0x40);
}
boolean RealTimeClockDS1307::isPM()
{
  //if in 12-hour mode, but 5 of the hour register indicates PM
  if(is12hour()) {
    return ((_reg2_hour & 0x20) == 0x20);
  }
  //otherwise, let's consider any time with the hour >11 to be PM:
  return (getHours() > 11);
}
boolean RealTimeClockDS1307::isStopped()
{
  //bit 7 of the seconds register stopps the clock when high
  return ((_reg0_sec & 0x80) == 0x80);
}

int RealTimeClockDS1307::getHours()
{
  if(is12hour()) { 
    //do not include bit 5, the am/pm indicator
    return bcdToDec(_reg2_hour & 0x1f);
  }
  //bits 4-5 are tens of hours
  return bcdToDec(_reg2_hour & 0x3f);
}
int RealTimeClockDS1307::getMinutes()
{
  //could mask with 0x7f but shouldn't need to
  return bcdToDec(_reg1_min);
}
int RealTimeClockDS1307::getSeconds()
{
  //need to mask oscillator start/stop bit 7
  return bcdToDec(_reg0_sec & 0x7f);
}
int RealTimeClockDS1307::getYear()
{
  return bcdToDec(_reg6_year);
}
int RealTimeClockDS1307::getMonth()
{
  //could mask with 0x1f but shouldn't need to
  return bcdToDec(_reg5_month);
}
int RealTimeClockDS1307::getDate()
{
  //could mask with 0x3f but shouldn't need to
  return bcdToDec(_reg4_date);
}
int RealTimeClockDS1307::getDay()
{
  return getDate();
}
int RealTimeClockDS1307::getDayOfWeek()
{
  //could mask with 0x07 but shouldn't need to
  return bcdToDec(_reg3_day);
}

void RealTimeClockDS1307::getFormatted(char * buffer)
{
  int i=0;
  //target string format: YY-MM-DD HH:II:SS
  buffer[i++]=highNybbleToASCII(_reg6_year);
  buffer[i++]=lowNybbleToASCII(_reg6_year);
  buffer[i++]='-';
  buffer[i++]=highNybbleToASCII(_reg5_month & 0x1f);
  buffer[i++]=lowNybbleToASCII(_reg5_month);
  buffer[i++]='-';
  buffer[i++]=highNybbleToASCII(_reg4_date & 0x3f);
  buffer[i++]=lowNybbleToASCII(_reg4_date);
  buffer[i++]=' ';
  if(is12hour()) {
    buffer[i++]=highNybbleToASCII(_reg2_hour & 0x1f);
  } else {
    buffer[i++]=highNybbleToASCII(_reg2_hour & 0x3f);
  }
  buffer[i++]=lowNybbleToASCII(_reg2_hour);
  buffer[i++]=':';
  buffer[i++]=highNybbleToASCII(_reg1_min & 0x7f);
  buffer[i++]=lowNybbleToASCII(_reg1_min);
  buffer[i++]=':';
  buffer[i++]=highNybbleToASCII(_reg0_sec & 0x7f);
  buffer[i++]=lowNybbleToASCII(_reg0_sec);
  if(is12hour()) {
    if(isPM()) {
      buffer[i++]='P';
    } else {
      buffer[i++]='A';
    }
  }
  buffer[i++]=0x00;
}

void RealTimeClockDS1307::getFormatted2k(char * buffer)
{
  buffer[0]='2';
  buffer[1]='0';
  getFormatted(&buffer[2]);
}

/**** SETTERS *****/

void RealTimeClockDS1307::setSeconds(int s)
{
  if (s < 60 && s >=0)
  {
    //need to preserve oscillator bit
    _reg0_sec = decToBcd(s) | (_reg0_sec & 0x80);
  }
}
void RealTimeClockDS1307::setMinutes(int m)
{
  if (m < 60 && m >=0)
  {
    _reg1_min = decToBcd(m);
  }
}
void RealTimeClockDS1307::setHours(int h)
{
  if (is12hour())
  {
    if (h >= 1 && h <=12)
    {
      //preserve 12/24 and AM/PM bits
      _reg2_hour = decToBcd(h) | (_reg2_hour & 0x60);
    }
  } else {
    if (h >= 0 && h <=24)
   {
      //preserve 12/24 bit
      _reg2_hour = decToBcd(h) | (_reg2_hour & 0x40);
   }
  }//else
}//setHours

void RealTimeClockDS1307::set24h()
{
  //"Bit 6 of the hours register is defined as the
  //"12- or 24-hour mode select bit.
  //"When high, the 12-hour mode is selected"
  //So, mask the curent value with the complement turn off that bit:
  _reg2_hour = _reg2_hour & ~0x40; 
}
void RealTimeClockDS1307::setAM()
{
  //"In the 12-hour mode, bit 5 is the AM/PM bit with logic high being PM"
  //so we need to OR with 0x40 to set 12-hour mode and also
  //turn off the PM bit by masking with the complement
  _reg2_hour = _reg2_hour & ~0x20 | 0x40;
}
void RealTimeClockDS1307::setPM()
{
  //"In the 12-hour mode, bit 5 is the AM/PM bit with logic high being PM"
  //so we need to OR with 0x40 and 0x20 to set 12-hour mode and also
  //turn on the PM bit:
  _reg2_hour = _reg2_hour | 0x60;
}

void RealTimeClockDS1307::switchTo12h()
{
  if(is12hour()) { return; }
  int h = getHours();
  if (h < 12) {
    setAM();
  } else {
    h = h-12;
    setPM();
  }
  if (h==0)
  {
    h=12;
  }
  setHours(h);
}
void RealTimeClockDS1307::switchTo24h()
{
  if(!is12hour()) { return ; }
  int h = getHours();
  if(h==12) {//12 PM is just 12; 12 AM is 0 hours.
    h = 0;
  }
  if (isPM())
  {//if it was 12 PM, then h=0 above and so we're back to 12:
    h = h+12;
  }
  set24h();
  setHours(h);
}

void RealTimeClockDS1307::setDayOfWeek(int d)
{
  if (d > 0 && d < 8)
  {
    _reg3_day = decToBcd(d);
  }
}

void RealTimeClockDS1307::setDate(int d)
{
  if (d > 0 && d < 32)
  {
    _reg4_date = decToBcd(d);
  }
}
void RealTimeClockDS1307::setDay(int d)
{
  setDate(d);
}

void RealTimeClockDS1307::setMonth(int m)
{
  if (m > 0 && m < 13)
  {
    _reg5_month = decToBcd(m);
  }
}
void RealTimeClockDS1307::setYear(int y)
{
  if (y >= 0 && y <100)
  {
    _reg6_year = decToBcd(y);
  }
}



/*****************************************
 * Private methods
 *****************************************/
byte RealTimeClockDS1307::decToBcd(byte b)
{
  return ( ((b/10) << 4) + (b%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte RealTimeClockDS1307::bcdToDec(byte b)
{
  return ( ((b >> 4)*10) + (b%16) );
}

char RealTimeClockDS1307::lowNybbleToASCII(byte b) 
{
  b = b & 0x0f;
  if(b < 10) {
    //0 is ASCII 48
    return 48+b;
  }
  //A is ASCII 55
  return 55+b;
}
char RealTimeClockDS1307::highNybbleToASCII(byte b)
{
  return lowNybbleToASCII(b >> 4);
}

/***** INSTANCE *******/

RealTimeClockDS1307 RTC = RealTimeClockDS1307();

RTClib

C/C++
add this to the RTClib folder. Now you have all the necessary files for the RTClib. Now do the same as I told you with the 'RealTimeClockDS1307' library file.
/*
  RealTimeClockDS1307 - library to control a DS1307 RTC module
  Copyright (c) 2011 David H. Brown. All rights reserved

  v0.92 Updated for Arduino 1.00; not re-tested on earlier versions
  
  Much thanks to John Waters and Maurice Ribble for their
  earlier and very helpful work (even if I didn't wind up
  using any of their code):
   - http://combustory.com/wiki/index.php/RTC1307_-_Real_Time_Clock
   - http://www.glacialwanderer.com/hobbyrobotics/?p=12

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef RealTimeClockDS1307_h
#define RealTimeClockDS1307_h

  #if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
  #else
  #include "WProgram.h"
  #endif

//#include <HardwareSerial.h>
//#include <WConstants.h> //need/want 'boolean' and 'byte' types used by Arduino
//#undef round is required to avoid a compile-time
//"expected unqualified-id before 'double'" error in math.h
//see: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1247924528/3
#undef round 
#include <Wire.h>

#define ARDUINO_PIN_T uint8_t

class RealTimeClockDS1307
{
  private:
    byte _reg0_sec;
    byte _reg1_min;
    byte _reg2_hour;
    byte _reg3_day;
    byte _reg4_date;
    byte _reg5_month;
    byte _reg6_year;
    byte _reg7_sqw;
    byte decToBcd(byte);
    byte bcdToDec(byte);
    char lowNybbleToASCII(byte);
    char highNybbleToASCII(byte);
  public:
    RealTimeClockDS1307();
    void readClock();//read registers (incl sqw) to local store
    void setClock();//update clock registers from local store
    void stop();//immediate; does not require setClock();
    void start();//immediate; does not require setClock();
    void sqwEnable(byte);//enable the square wave with the specified frequency
    void sqwDisable(boolean);//disable the square wave, setting output either high or low
    void writeData(byte, byte);//write a single value to a register
    void writeData(byte, void *, int);//write several values consecutively
    byte readData(byte);//read a single value from a register
    void readData(byte, void *, int);//read several values into a buffer

    int getHours();
    int getMinutes();
    int getSeconds();
    int getYear();
    int getMonth();
    int getDate();
    int getDay();
    int getDayOfWeek();
    boolean is12hour();
    boolean isPM();
    boolean isStopped();
    //getFormatted writes into a char array provided by you. Format is:
    // YY-MM-DD HH:II:SS   ... plus "A" or "P" if in 12-hour mode
    //and of course a NULL terminator. So, [18] for 24h or [19] for 12h
    void getFormatted(char *);//see comment above
    void getFormatted2k(char *);//as getFormatted, but with "20" prepended

    //must also call setClock() after any of these
    //before next readClock(). Note that invalid dates are not
    //corrected by the clock. All the clock knows is when it should 
    //roll over to the next month rather than the next date in the same month.
    void setSeconds(int);
    void setMinutes(int);
    //setHours rejects values out of range for the current 12/24 mode
    void setHours(int);
    void setAM();//does not consider hours; see switchTo24()
    void setPM();//does not consider hours; see switchTo24()
    void set24h();//does not consider hours; see switchTo24()
    void switchTo24h();//returns immediately if already 24h
    void switchTo12h();//returns immediately if already 12h
    void setDayOfWeek(int);//incremented at midnight; not set by date (no fixed meaning)
    void setDate(int);//allows 1-31 for *all* months.
    void setDay(int);
    void setMonth(int);
    void setYear(int);

    //squarewave frequencies:
    static const byte SQW_1Hz=0x00;
    static const byte SQW_4kHz=0x01;//actually 4.096kHz
    static const byte SQW_8kHz=0x02;//actually 8.192kHz
    static const byte SQW_32kHz=0x03;//actually 32.768kHz
};

extern RealTimeClockDS1307 RTC;

#endif

README.md

C/C++
add this to the RTClib library
This is a fork of JeeLab's fantastic real time clock library for Arduino.

For details on using this library with an RTC module like the DS1307, see the guide at: https://learn.adafruit.com/ds1307-real-time-clock-breakout-board-kit/overview

To download. click the DOWNLOADS button to the right, and rename the uncompressed folder RTClib.

Place the RTClib folder in your *arduinosketchfolder*/libraries/ folder. 
You may need to create the libraries subfolder if its your first library. Restart the IDE.

<!-- START COMPATIBILITY TABLE -->

## Compatibility

MCU                | Tested Works | Doesn't Work | Not Tested  | Notes
------------------ | :----------: | :----------: | :---------: | -----
Atmega328 @ 16MHz  |      X       |             |            | 
Atmega328 @ 12MHz  |      X       |             |            | 
Atmega32u4 @ 16MHz |      X       |             |            | Use SDA/SCL on pins D3 &amp; D2
Atmega32u4 @ 8MHz  |      X       |             |            | Use SDA/SCL on pins D3 &amp; D2
ESP8266            |      X       |             |            | SDA/SCL default to pins 4 &amp; 5 but any two pins can be assigned as SDA/SCL using Wire.begin(SDA,SCL)
Atmega2560 @ 16MHz |      X       |             |            | Use SDA/SCL on Pins 20 &amp; 21
ATSAM3X8E          |      X       |             |            | Use SDA1 and SCL1
ATSAM21D           |      X       |             |            | 
ATtiny85 @ 16MHz   |      X       |             |            | 
ATtiny85 @ 8MHz    |      X       |             |            | 
Intel Curie @ 32MHz |             |             |     X       | 
STM32F2            |             |             |     X       | 

  * ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini
  * ATmega328 @ 12MHz : Adafruit Pro Trinket 3V
  * ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0
  * ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro
  * ESP8266 : Adafruit Huzzah
  * ATmega2560 @ 16MHz : Arduino Mega
  * ATSAM3X8E : Arduino Due
  * ATSAM21D : Arduino Zero, M0 Pro
  * ATtiny85 @ 16MHz : Adafruit Trinket 5V
  * ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V

<!-- END COMPATIBILITY TABLE -->

RTClib.cpp

C/C++
name it as above and add it to the RTClib library
// Code by JeeLabs http://news.jeelabs.org/code/
// Released to the public domain! Enjoy!

#include <Wire.h>
#include "RTClib.h"
#ifdef __AVR__
 #include <avr/pgmspace.h>
#elif defined(ESP8266)
 #include <pgmspace.h>
#elif defined(ARDUINO_ARCH_SAMD)
// nothing special needed
#elif defined(ARDUINO_SAM_DUE)
 #define PROGMEM
 #define pgm_read_byte(addr) (*(const unsigned char *)(addr))
 #define Wire Wire1
#endif



#if (ARDUINO >= 100)
 #include <Arduino.h> // capital A so it is error prone on case-sensitive filesystems
 // Macro to deal with the difference in I2C write functions from old and new Arduino versions.
 #define _I2C_WRITE write
 #define _I2C_READ  read
#else
 #include <WProgram.h>
 #define _I2C_WRITE send
 #define _I2C_READ  receive
#endif


static uint8_t read_i2c_register(uint8_t addr, uint8_t reg) {
  Wire.beginTransmission(addr);
  Wire._I2C_WRITE((byte)reg);
  Wire.endTransmission();

  Wire.requestFrom(addr, (byte)1);
  return Wire._I2C_READ();
}

static void write_i2c_register(uint8_t addr, uint8_t reg, uint8_t val) {
  Wire.beginTransmission(addr);
  Wire._I2C_WRITE((byte)reg);
  Wire._I2C_WRITE((byte)val);
  Wire.endTransmission();
}


////////////////////////////////////////////////////////////////////////////////
// utility code, some of this could be exposed in the DateTime API if needed

const uint8_t daysInMonth [] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 };

// number of days since 2000/01/01, valid for 2001..2099
static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) {
    if (y >= 2000)
        y -= 2000;
    uint16_t days = d;
    for (uint8_t i = 1; i < m; ++i)
        days += pgm_read_byte(daysInMonth + i - 1);
    if (m > 2 && y % 4 == 0)
        ++days;
    return days + 365 * y + (y + 3) / 4 - 1;
}

static long time2long(uint16_t days, uint8_t h, uint8_t m, uint8_t s) {
    return ((days * 24L + h) * 60 + m) * 60 + s;
}

////////////////////////////////////////////////////////////////////////////////
// DateTime implementation - ignores time zones and DST changes
// NOTE: also ignores leap seconds, see http://en.wikipedia.org/wiki/Leap_second

DateTime::DateTime (uint32_t t) {
  t -= SECONDS_FROM_1970_TO_2000;    // bring to 2000 timestamp from 1970

    ss = t % 60;
    t /= 60;
    mm = t % 60;
    t /= 60;
    hh = t % 24;
    uint16_t days = t / 24;
    uint8_t leap;
    for (yOff = 0; ; ++yOff) {
        leap = yOff % 4 == 0;
        if (days < 365 + leap)
            break;
        days -= 365 + leap;
    }
    for (m = 1; ; ++m) {
        uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1);
        if (leap && m == 2)
            ++daysPerMonth;
        if (days < daysPerMonth)
            break;
        days -= daysPerMonth;
    }
    d = days + 1;
}

DateTime::DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) {
    if (year >= 2000)
        year -= 2000;
    yOff = year;
    m = month;
    d = day;
    hh = hour;
    mm = min;
    ss = sec;
}

DateTime::DateTime (const DateTime& copy):
  yOff(copy.yOff),
  m(copy.m),
  d(copy.d),
  hh(copy.hh),
  mm(copy.mm),
  ss(copy.ss)
{}

static uint8_t conv2d(const char* p) {
    uint8_t v = 0;
    if ('0' <= *p && *p <= '9')
        v = *p - '0';
    return 10 * v + *++p - '0';
}

// A convenient constructor for using "the compiler's time":
//   DateTime now (__DATE__, __TIME__);
// NOTE: using F() would further reduce the RAM footprint, see below.
DateTime::DateTime (const char* date, const char* time) {
    // sample input: date = "Dec 26 2009", time = "12:34:56"
    yOff = conv2d(date + 9);
    // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec 
    switch (date[0]) {
        case 'J': m = date[1] == 'a' ? 1 : m = date[2] == 'n' ? 6 : 7; break;
        case 'F': m = 2; break;
        case 'A': m = date[2] == 'r' ? 4 : 8; break;
        case 'M': m = date[2] == 'r' ? 3 : 5; break;
        case 'S': m = 9; break;
        case 'O': m = 10; break;
        case 'N': m = 11; break;
        case 'D': m = 12; break;
    }
    d = conv2d(date + 4);
    hh = conv2d(time);
    mm = conv2d(time + 3);
    ss = conv2d(time + 6);
}

// A convenient constructor for using "the compiler's time":
// This version will save RAM by using PROGMEM to store it by using the F macro.
//   DateTime now (F(__DATE__), F(__TIME__));
DateTime::DateTime (const __FlashStringHelper* date, const __FlashStringHelper* time) {
    // sample input: date = "Dec 26 2009", time = "12:34:56"
    char buff[11];
    memcpy_P(buff, date, 11);
    yOff = conv2d(buff + 9);
    // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    switch (buff[0]) {
        case 'J': m = buff[1] == 'a' ? 1 : m = buff[2] == 'n' ? 6 : 7; break;
        case 'F': m = 2; break;
        case 'A': m = buff[2] == 'r' ? 4 : 8; break;
        case 'M': m = buff[2] == 'r' ? 3 : 5; break;
        case 'S': m = 9; break;
        case 'O': m = 10; break;
        case 'N': m = 11; break;
        case 'D': m = 12; break;
    }
    d = conv2d(buff + 4);
    memcpy_P(buff, time, 8);
    hh = conv2d(buff);
    mm = conv2d(buff + 3);
    ss = conv2d(buff + 6);
}

uint8_t DateTime::dayOfTheWeek() const {    
    uint16_t day = date2days(yOff, m, d);
    return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6
}

uint32_t DateTime::unixtime(void) const {
  uint32_t t;
  uint16_t days = date2days(yOff, m, d);
  t = time2long(days, hh, mm, ss);
  t += SECONDS_FROM_1970_TO_2000;  // seconds from 1970 to 2000

  return t;
}

long DateTime::secondstime(void) const {
  long t;
  uint16_t days = date2days(yOff, m, d);
  t = time2long(days, hh, mm, ss);
  return t;
}

DateTime DateTime::operator+(const TimeSpan& span) {
  return DateTime(unixtime()+span.totalseconds());
}

DateTime DateTime::operator-(const TimeSpan& span) {
  return DateTime(unixtime()-span.totalseconds());
}

TimeSpan DateTime::operator-(const DateTime& right) {
  return TimeSpan(unixtime()-right.unixtime());
}

////////////////////////////////////////////////////////////////////////////////
// TimeSpan implementation

TimeSpan::TimeSpan (int32_t seconds):
  _seconds(seconds)
{}

TimeSpan::TimeSpan (int16_t days, int8_t hours, int8_t minutes, int8_t seconds):
  _seconds((int32_t)days*86400L + (int32_t)hours*3600 + (int32_t)minutes*60 + seconds)
{}

TimeSpan::TimeSpan (const TimeSpan& copy):
  _seconds(copy._seconds)
{}

TimeSpan TimeSpan::operator+(const TimeSpan& right) {
  return TimeSpan(_seconds+right._seconds);
}

TimeSpan TimeSpan::operator-(const TimeSpan& right) {
  return TimeSpan(_seconds-right._seconds);
}

////////////////////////////////////////////////////////////////////////////////
// RTC_DS1307 implementation

static uint8_t bcd2bin (uint8_t val) { return val - 6 * (val >> 4); }
static uint8_t bin2bcd (uint8_t val) { return val + 6 * (val / 10); }

boolean RTC_DS1307::begin(void) {
  Wire.begin();
  return true;
}

uint8_t RTC_DS1307::isrunning(void) {
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire._I2C_WRITE((byte)0);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 1);
  uint8_t ss = Wire._I2C_READ();
  return !(ss>>7);
}

void RTC_DS1307::adjust(const DateTime& dt) {
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire._I2C_WRITE((byte)0); // start at location 0
  Wire._I2C_WRITE(bin2bcd(dt.second()));
  Wire._I2C_WRITE(bin2bcd(dt.minute()));
  Wire._I2C_WRITE(bin2bcd(dt.hour()));
  Wire._I2C_WRITE(bin2bcd(0));
  Wire._I2C_WRITE(bin2bcd(dt.day()));
  Wire._I2C_WRITE(bin2bcd(dt.month()));
  Wire._I2C_WRITE(bin2bcd(dt.year() - 2000));
  Wire.endTransmission();
}

DateTime RTC_DS1307::now() {
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire._I2C_WRITE((byte)0);	
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);
  uint8_t ss = bcd2bin(Wire._I2C_READ() & 0x7F);
  uint8_t mm = bcd2bin(Wire._I2C_READ());
  uint8_t hh = bcd2bin(Wire._I2C_READ());
  Wire._I2C_READ();
  uint8_t d = bcd2bin(Wire._I2C_READ());
  uint8_t m = bcd2bin(Wire._I2C_READ());
  uint16_t y = bcd2bin(Wire._I2C_READ()) + 2000;
  
  return DateTime (y, m, d, hh, mm, ss);
}

Ds1307SqwPinMode RTC_DS1307::readSqwPinMode() {
  int mode;

  Wire.beginTransmission(DS1307_ADDRESS);
  Wire._I2C_WRITE(DS1307_CONTROL);
  Wire.endTransmission();
  
  Wire.requestFrom((uint8_t)DS1307_ADDRESS, (uint8_t)1);
  mode = Wire._I2C_READ();

  mode &= 0x93;
  return static_cast<Ds1307SqwPinMode>(mode);
}

void RTC_DS1307::writeSqwPinMode(Ds1307SqwPinMode mode) {
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire._I2C_WRITE(DS1307_CONTROL);
  Wire._I2C_WRITE(mode);
  Wire.endTransmission();
}

void RTC_DS1307::readnvram(uint8_t* buf, uint8_t size, uint8_t address) {
  int addrByte = DS1307_NVRAM + address;
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire._I2C_WRITE(addrByte);
  Wire.endTransmission();
  
  Wire.requestFrom((uint8_t) DS1307_ADDRESS, size);
  for (uint8_t pos = 0; pos < size; ++pos) {
    buf[pos] = Wire._I2C_READ();
  }
}

void RTC_DS1307::writenvram(uint8_t address, uint8_t* buf, uint8_t size) {
  int addrByte = DS1307_NVRAM + address;
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire._I2C_WRITE(addrByte);
  for (uint8_t pos = 0; pos < size; ++pos) {
    Wire._I2C_WRITE(buf[pos]);
  }
  Wire.endTransmission();
}

uint8_t RTC_DS1307::readnvram(uint8_t address) {
  uint8_t data;
  readnvram(&data, 1, address);
  return data;
}

void RTC_DS1307::writenvram(uint8_t address, uint8_t data) {
  writenvram(address, &data, 1);
}

////////////////////////////////////////////////////////////////////////////////
// RTC_Millis implementation

long RTC_Millis::offset = 0;

void RTC_Millis::adjust(const DateTime& dt) {
    offset = dt.unixtime() - millis() / 1000;
}

DateTime RTC_Millis::now() {
  return (uint32_t)(offset + millis() / 1000);
}

////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// RTC_PCF8563 implementation

boolean RTC_PCF8523::begin(void) {
  Wire.begin();
  return true;
}

boolean RTC_PCF8523::initialized(void) {
  Wire.beginTransmission(PCF8523_ADDRESS);
  Wire._I2C_WRITE((byte)PCF8523_CONTROL_3);
  Wire.endTransmission();

  Wire.requestFrom(PCF8523_ADDRESS, 1);
  uint8_t ss = Wire._I2C_READ();
  return ((ss & 0xE0) != 0xE0);
}

void RTC_PCF8523::adjust(const DateTime& dt) {
  Wire.beginTransmission(PCF8523_ADDRESS);
  Wire._I2C_WRITE((byte)3); // start at location 3
  Wire._I2C_WRITE(bin2bcd(dt.second()));
  Wire._I2C_WRITE(bin2bcd(dt.minute()));
  Wire._I2C_WRITE(bin2bcd(dt.hour()));
  Wire._I2C_WRITE(bin2bcd(dt.day()));
  Wire._I2C_WRITE(bin2bcd(0)); // skip weekdays
  Wire._I2C_WRITE(bin2bcd(dt.month()));
  Wire._I2C_WRITE(bin2bcd(dt.year() - 2000));
  Wire.endTransmission();

  // set to battery switchover mode
  Wire.beginTransmission(PCF8523_ADDRESS);
  Wire._I2C_WRITE((byte)PCF8523_CONTROL_3);
  Wire._I2C_WRITE((byte)0x00);
  Wire.endTransmission();
}

DateTime RTC_PCF8523::now() {
  Wire.beginTransmission(PCF8523_ADDRESS);
  Wire._I2C_WRITE((byte)3);	
  Wire.endTransmission();

  Wire.requestFrom(PCF8523_ADDRESS, 7);
  uint8_t ss = bcd2bin(Wire._I2C_READ() & 0x7F);
  uint8_t mm = bcd2bin(Wire._I2C_READ());
  uint8_t hh = bcd2bin(Wire._I2C_READ());
  uint8_t d = bcd2bin(Wire._I2C_READ());
  Wire._I2C_READ();  // skip 'weekdays'
  uint8_t m = bcd2bin(Wire._I2C_READ());
  uint16_t y = bcd2bin(Wire._I2C_READ()) + 2000;
  
  return DateTime (y, m, d, hh, mm, ss);
}

Pcf8523SqwPinMode RTC_PCF8523::readSqwPinMode() {
  int mode;

  Wire.beginTransmission(PCF8523_ADDRESS);
  Wire._I2C_WRITE(PCF8523_CLKOUTCONTROL);
  Wire.endTransmission();
  
  Wire.requestFrom((uint8_t)PCF8523_ADDRESS, (uint8_t)1);
  mode = Wire._I2C_READ();

  mode >>= 3;
  mode &= 0x7;
  return static_cast<Pcf8523SqwPinMode>(mode);
}

void RTC_PCF8523::writeSqwPinMode(Pcf8523SqwPinMode mode) {
  Wire.beginTransmission(PCF8523_ADDRESS);
  Wire._I2C_WRITE(PCF8523_CLKOUTCONTROL);
  Wire._I2C_WRITE(mode << 3);
  Wire.endTransmission();
}




////////////////////////////////////////////////////////////////////////////////
// RTC_DS3231 implementation

boolean RTC_DS3231::begin(void) {
  Wire.begin();
  return true;
}

bool RTC_DS3231::lostPower(void) {
  return (read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG) >> 7);
}

void RTC_DS3231::adjust(const DateTime& dt) {
  Wire.beginTransmission(DS3231_ADDRESS);
  Wire._I2C_WRITE((byte)0); // start at location 0
  Wire._I2C_WRITE(bin2bcd(dt.second()));
  Wire._I2C_WRITE(bin2bcd(dt.minute()));
  Wire._I2C_WRITE(bin2bcd(dt.hour()));
  Wire._I2C_WRITE(bin2bcd(0));
  Wire._I2C_WRITE(bin2bcd(dt.day()));
  Wire._I2C_WRITE(bin2bcd(dt.month()));
  Wire._I2C_WRITE(bin2bcd(dt.year() - 2000));
  Wire.endTransmission();

  uint8_t statreg = read_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG);
  statreg &= ~0x80; // flip OSF bit
  write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, statreg);
}

DateTime RTC_DS3231::now() {
  Wire.beginTransmission(DS3231_ADDRESS);
  Wire._I2C_WRITE((byte)0);	
  Wire.endTransmission();

  Wire.requestFrom(DS3231_ADDRESS, 7);
  uint8_t ss = bcd2bin(Wire._I2C_READ() & 0x7F);
  uint8_t mm = bcd2bin(Wire._I2C_READ());
  uint8_t hh = bcd2bin(Wire._I2C_READ());
  Wire._I2C_READ();
  uint8_t d = bcd2bin(Wire._I2C_READ());
  uint8_t m = bcd2bin(Wire._I2C_READ());
  uint16_t y = bcd2bin(Wire._I2C_READ()) + 2000;
  
  return DateTime (y, m, d, hh, mm, ss);
}

Ds3231SqwPinMode RTC_DS3231::readSqwPinMode() {
  int mode;

  Wire.beginTransmission(DS3231_ADDRESS);
  Wire._I2C_WRITE(DS3231_CONTROL);
  Wire.endTransmission();
  
  Wire.requestFrom((uint8_t)DS3231_ADDRESS, (uint8_t)1);
  mode = Wire._I2C_READ();

  mode &= 0x93;
  return static_cast<Ds3231SqwPinMode>(mode);
}

void RTC_DS3231::writeSqwPinMode(Ds3231SqwPinMode mode) {
  uint8_t ctrl;
  ctrl = read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL);

  ctrl &= ~0x04; // turn off INTCON
  ctrl &= ~0x18; // set freq bits to 0

  if (mode == DS3231_OFF) {
    ctrl |= 0x04; // turn on INTCN
  } else {
    ctrl |= mode;
  } 
  write_i2c_register(DS3231_ADDRESS, DS3231_CONTROL, ctrl);

  //Serial.println( read_i2c_register(DS3231_ADDRESS, DS3231_CONTROL), HEX);
}

RTClib.h

C/C++
that's the name. add it to the RTClib library. Now you have all the files for the RTClib library. Do the same steps to add this to the arduino libraries.
// Code by JeeLabs http://news.jeelabs.org/code/
// Released to the public domain! Enjoy!

#ifndef _RTCLIB_H_
#define _RTCLIB_H_

#include <Arduino.h>
class TimeSpan;


#define PCF8523_ADDRESS       0x68
#define PCF8523_CLKOUTCONTROL 0x0F
#define PCF8523_CONTROL_3     0x02

#define DS1307_ADDRESS  0x68
#define DS1307_CONTROL  0x07
#define DS1307_NVRAM    0x08

#define DS3231_ADDRESS  0x68
#define DS3231_CONTROL  0x0E
#define DS3231_STATUSREG 0x0F

#define SECONDS_PER_DAY 86400L

#define SECONDS_FROM_1970_TO_2000 946684800



// Simple general-purpose date/time class (no TZ / DST / leap second handling!)
class DateTime {
public:
    DateTime (uint32_t t =0);
    DateTime (uint16_t year, uint8_t month, uint8_t day,
                uint8_t hour =0, uint8_t min =0, uint8_t sec =0);
    DateTime (const DateTime& copy);
    DateTime (const char* date, const char* time);
    DateTime (const __FlashStringHelper* date, const __FlashStringHelper* time);
    uint16_t year() const       { return 2000 + yOff; }
    uint8_t month() const       { return m; }
    uint8_t day() const         { return d; }
    uint8_t hour() const        { return hh; }
    uint8_t minute() const      { return mm; }
    uint8_t second() const      { return ss; }
    uint8_t dayOfTheWeek() const;

    // 32-bit times as seconds since 1/1/2000
    long secondstime() const;   
    // 32-bit times as seconds since 1/1/1970
    uint32_t unixtime(void) const;

    DateTime operator+(const TimeSpan& span);
    DateTime operator-(const TimeSpan& span);
    TimeSpan operator-(const DateTime& right);

protected:
    uint8_t yOff, m, d, hh, mm, ss;
};

// Timespan which can represent changes in time with seconds accuracy.
class TimeSpan {
public:
    TimeSpan (int32_t seconds = 0);
    TimeSpan (int16_t days, int8_t hours, int8_t minutes, int8_t seconds);
    TimeSpan (const TimeSpan& copy);
    int16_t days() const         { return _seconds / 86400L; }
    int8_t  hours() const        { return _seconds / 3600 % 24; }
    int8_t  minutes() const      { return _seconds / 60 % 60; }
    int8_t  seconds() const      { return _seconds % 60; }
    int32_t totalseconds() const { return _seconds; }

    TimeSpan operator+(const TimeSpan& right);
    TimeSpan operator-(const TimeSpan& right);

protected:
    int32_t _seconds;
};

// RTC based on the DS1307 chip connected via I2C and the Wire library
enum Ds1307SqwPinMode { OFF = 0x00, ON = 0x80, SquareWave1HZ = 0x10, SquareWave4kHz = 0x11, SquareWave8kHz = 0x12, SquareWave32kHz = 0x13 };

class RTC_DS1307 {
public:
    boolean begin(void);
    static void adjust(const DateTime& dt);
    uint8_t isrunning(void);
    static DateTime now();
    static Ds1307SqwPinMode readSqwPinMode();
    static void writeSqwPinMode(Ds1307SqwPinMode mode);
    uint8_t readnvram(uint8_t address);
    void readnvram(uint8_t* buf, uint8_t size, uint8_t address);
    void writenvram(uint8_t address, uint8_t data);
    void writenvram(uint8_t address, uint8_t* buf, uint8_t size);
};

// RTC based on the DS3231 chip connected via I2C and the Wire library
enum Ds3231SqwPinMode { DS3231_OFF = 0x01, DS3231_SquareWave1Hz = 0x00, DS3231_SquareWave1kHz = 0x08, DS3231_SquareWave4kHz = 0x10, DS3231_SquareWave8kHz = 0x18 };

class RTC_DS3231 {
public:
    boolean begin(void);
    static void adjust(const DateTime& dt);
    bool lostPower(void);
    static DateTime now();
    static Ds3231SqwPinMode readSqwPinMode();
    static void writeSqwPinMode(Ds3231SqwPinMode mode);
};


// RTC based on the PCF8523 chip connected via I2C and the Wire library
enum Pcf8523SqwPinMode { PCF8523_OFF = 7, PCF8523_SquareWave1HZ = 6, PCF8523_SquareWave32HZ = 5, PCF8523_SquareWave1kHz = 4, PCF8523_SquareWave4kHz = 3, PCF8523_SquareWave8kHz = 2, PCF8523_SquareWave16kHz = 1, PCF8523_SquareWave32kHz = 0 };

class RTC_PCF8523 {
public:
    boolean begin(void);
    void adjust(const DateTime& dt);
    boolean initialized(void);
    static DateTime now();

    Pcf8523SqwPinMode readSqwPinMode();
    void writeSqwPinMode(Pcf8523SqwPinMode mode);
};

// RTC using the internal millis() clock, has to be initialized before use
// NOTE: this clock won't be correct once the millis() timer rolls over (>49d?)
class RTC_Millis {
public:
    static void begin(const DateTime& dt) { adjust(dt); }
    static void adjust(const DateTime& dt);
    static DateTime now();

protected:
    static long offset;
};

#endif // _RTCLIB_H_

Credits

shivakumarj1995

shivakumarj1995

1 project • 5 followers

Comments