Arduino + DS1307

By harald, October 28, 2016

Description

A Real Time Clock (RTC) is basically just like a watch – it runs on a battery and keeps time for you even when there is a power outage.  Using an RTC, you can keep track of long timelines, even if you reprogram your microcontroller or disconnect it from USB or a power plug.

The microcontroller on an Arduino board has a built-in timekeeper called millis() that counts the milliseconds since the Arduino was last powered.  An Arduino doesn’t know that it’s ‘Tuesday’ or ‘March 8th’, all it can tell is ‘It’s been 14,000 milliseconds since I was last turned on’.

To keep accurate track of time, even if the Arduino is powered down, we can use a separate clock module.

TinyRTC, DS1307 and DS3231

DS1307 is a Real Time Clock (RTC) module.  It consists of a time keeping chip using a frequency oscillator circuit, crystal and 3V lithium metal coin cell battery.  Often this chip is placed on a board together with a small I2C EEPROM memory chip (24LC08B) and (often) a thermometer chip ( DS18B20) for you to use.  The board is named “TinyRTC”.

arduino_rtc02

There is also a DS3231 High Precision Real-Time Clock Module.  There are two main differences between the ICs on the real-time clock modules, which is the accuracy of the time-keeping. The DS1307 used in the first module works very well, however the external temperature can affect the frequency of the oscillator circuit which drives the DS1307’s internal counter.  This will usually result with the clock being off by around five or so minutes per month. The DS3231 is more accurate, as it has an internal oscillator which isn’t affected by external factors – and thus is accurate down to a few minutes per year at the most.  The DS3231 uses the same I2C protocol and can be used in place of a DS1307 chip without a need to make changes to your code.

I2C

The RTC is an I2C device, which means it uses a 2 wire bus to communicate. The I2C bus consists of signal clock (SCL) and signal data (SDA) lines to communicate.  The bus is unidirectional, meaning only one chip can speak at the same time.  The I2C protocol allows chips to send and receive information.  In this case, the I2C wires are used to set the time and retrieve it. On the Arduino UNO, these pins are wired to the Analog 4 and 5 pins.

Hardware Required

arduino_rtc01 arduino_rtc05

Pinout

BAT Battery voltage To monitor the battery voltage, or not connected
GND Ground Ground
VCC 5V supply Power the module and charge the battery
SDA I2C data I2C data for the RTC
SCL I2C clock I2C clock for the RTC
DS DS18B20 Temp. Sensor output One wire inteface
SQ Square wave output Normally not used

Note: The CR2032 button battery is rechargeable and is trickle charged using Vcc.

Schematic (TinyRTC)

arduino_rtc04

Circuit

arduino_rtc03

Code

Example 1

// Date and time functions using a DS1307 RTC connected via I2C and Wire lib

#include <Wire.h>
#include <RTClib.h>

RTC_DS1307 RTC;

void setup () {
    Serial.begin(57600);
    Wire.begin();
    RTC.begin();
    
    // Enable the next line of code ONCE to program the current time into the DS1307 RTC chip:
    //RTC.adjust(DateTime(__DATE__, __TIME__));
}

void loop () {
    DateTime now = RTC.now();
    
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
    
    delay(3000);
}

Example 2

You can use pushbuttons and an I2C connected 2×16 LCD character display to display the time and set the current date/time:

/*
:Project:Clock_Set_Date_Time
:Author: Tiziano Bianchettin
:Date: 13/01/2017
:Revision: 1
:License: Public Domain
thanks to:
  http://arduinoenonsolo.blogspot.it/2012/12/orologio-con-arduino-e-il-ds1307.html
  http://www.mauroalfieri.it/
  http://www.danielealberti.it/
  http://www.maffucci.it/
  My electronics laboratory professor "Perito Carli"  
*/
//************libraries**************//
#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>

//************************************//
LiquidCrystal_I2C lcd(0x3F,16,2); // Display  I2C 16 x 2
RTC_DS1307 RTC;

//************Button*****************//
int P1=6; // Button SET MENU'
int P2=7; // Button +
int P3=8; // Button -

//************Variables**************//
int hourupg;
int minupg;
int yearupg;
int monthupg;
int dayupg;
int menu =0;

void setup()
{

  lcd.begin();
  lcd.backlight();
  lcd.clear();

  pinMode(P1,INPUT);
  pinMode(P2,INPUT);
  pinMode(P3,INPUT);

  Serial.begin(9600);
  Wire.begin();
  RTC.begin();

  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // Set the date and time at compile time
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  // RTC.adjust(DateTime(__DATE__, __TIME__)); //removing "//" to adjust the time
    // The default display shows the date and time
  int menu=0;
}
 
void loop()
{ 

// check if you press the SET button and increase the menu index
  if(digitalRead(P1))
  {
   menu=menu+1;
  }
// in which subroutine should we go?
  if (menu==0)
    {
     DisplayDateTime(); // void DisplayDateTime

    }
  if (menu==1)
    {
    DisplaySetHour();
    }
  if (menu==2)
    {
    DisplaySetMinute();
    }
  if (menu==3)
    {
    DisplaySetYear();
    }
  if (menu==4)
    {
    DisplaySetMonth();
    }
  if (menu==5)
    {
    DisplaySetDay();
    }
  if (menu==6)
    {
    StoreAgg(); 
    delay(500);
    menu=0;
    }
    delay(100);
}

void DisplayDateTime ()
{
// We show the current date and time
  DateTime now = RTC.now();

  lcd.setCursor(0, 1);
  lcd.print("Hour:");
  if (now.hour()<=9)
  {
    lcd.print("0");
  }
  lcd.print(now.hour(), DEC);
  hourupg=now.hour();
  lcd.print(":");
  if (now.minute()<=9)
  {
    lcd.print("0");
  }
  lcd.print(now.minute(), DEC);
  minupg=now.minute();
  lcd.print(":");
  if (now.second()<=9)
  {
    lcd.print("0");
  }
  lcd.print(now.second(), DEC);

  lcd.setCursor(0, 0);
  lcd.print("Date: ");
  if (now.day()<=9)
  {
    lcd.print("0");
  }
  lcd.print(now.day(), DEC);
  dayupg=now.day();
  lcd.print("/");
  if (now.month()<=9)
  {
    lcd.print("0");
  }
  lcd.print(now.month(), DEC);
  monthupg=now.month();
  lcd.print("/");
  lcd.print(now.year(), DEC);
  yearupg=now.year();
}

void DisplaySetHour()
{
// time setting
  lcd.clear();
  DateTime now = RTC.now();
  if(digitalRead(P2)==HIGH)
  {
    if(hourupg==23)
    {
      hourupg=0;
    }
    else
    {
      hourupg=hourupg+1;
    }
  }
   if(digitalRead(P3)==HIGH)
  {
    if(hourupg==0)
    {
      hourupg=23;
    }
    else
    {
      hourupg=hourupg-1;
    }
  }
  lcd.setCursor(0,0);
  lcd.print("Set time:");
  lcd.setCursor(0,1);
  lcd.print(hourupg,DEC);
  delay(200);
}

void DisplaySetMinute()
{
// Setting the minutes
  lcd.clear();
  if(digitalRead(P2)==HIGH)
  {
    if (minupg==59)
    {
      minupg=0;
    }
    else
    {
      minupg=minupg+1;
    }
  }
   if(digitalRead(P3)==HIGH)
  {
    if (minupg==0)
    {
      minupg=59;
    }
    else
    {
      minupg=minupg-1;
    }
  }
  lcd.setCursor(0,0);
  lcd.print("Set Minutes:");
  lcd.setCursor(0,1);
  lcd.print(minupg,DEC);
  delay(200);
}
  
void DisplaySetYear()
{
// setting the year
  lcd.clear();
  if(digitalRead(P2)==HIGH)
  {    
    yearupg=yearupg+1;
  }
   if(digitalRead(P3)==HIGH)
  {
    yearupg=yearupg-1;
  }
  lcd.setCursor(0,0);
  lcd.print("Set Year:");
  lcd.setCursor(0,1);
  lcd.print(yearupg,DEC);
  delay(200);
}

void DisplaySetMonth()
{
// Setting the month
  lcd.clear();
  if(digitalRead(P2)==HIGH)
  {
    if (monthupg==12)
    {
      monthupg=1;
    }
    else
    {
      monthupg=monthupg+1;
    }
  }
   if(digitalRead(P3)==HIGH)
  {
    if (monthupg==1)
    {
      monthupg=12;
    }
    else
    {
      monthupg=monthupg-1;
    }
  }
  lcd.setCursor(0,0);
  lcd.print("Set Month:");
  lcd.setCursor(0,1);
  lcd.print(monthupg,DEC);
  delay(200);
}

void DisplaySetDay()
{
// Setting the day
  lcd.clear();
  if(digitalRead(P2)==HIGH)
  {
    if (dayupg==31)
    {
      dayupg=1;
    }
    else
    {
      dayupg=dayupg+1;
    }
  }
   if(digitalRead(P3)==HIGH)
  {
    if (dayupg==1)
    {
      dayupg=31;
    }
    else
    {
      dayupg=dayupg-1;
    }
  }
  lcd.setCursor(0,0);
  lcd.print("Set Day:");
  lcd.setCursor(0,1);
  lcd.print(dayupg,DEC);
  delay(200);
}

void StoreAgg()
{
// Variable saving
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("SAVING IN");
  lcd.setCursor(0,1);
  lcd.print("PROGRESS");
  RTC.adjust(DateTime(yearupg,monthupg,dayupg,hourupg,minupg,0));
  delay(200);
}