DS1307 RTC clock module Set and Read Time using Arduino
RTC or Real-time clock is an electric device that tracks time which is useful for many embedded system projects that include Date&Time like time-based alarms, timer applications, calendars, scheduled operations, etc.
An RTC module is similar to a digital watch or clock which has a Date and Time with seconds, minutes, hours, day, date, month, and year, also with a 12-hour format with AM/PM or 24-hour format. It can adjust the calendar date of each month irrespective of 30 days or 31 days, including the leap year (February 29; it is valid up to the year 2100).
The main component of the RTC module is the DS1307 chip. A 32khz quartz crystal oscillator, which provides the frequency signal for the precise movement of the clock.
The RTC module also has a backup battery that consists of a 3V Coin Cell battery; suitable for the (usually CR2032) battery holder in the module. The power consumption will be very lower during the battery backup mode, thus giving a long-lasting battery backup.
The precision and time backup is the main reason which makes the use of RTC a necessity compared to using the internal timer of a microcontroller.
RTC module Arduino connection
The RTC DS1307 module uses the I2C protocol for communication. So, connect the SDA and SCL pins of the module to the A4 and A5 pins of the Arduino UNO respectively. Also, connect the Vcc to 5V and GND to GND.
Install the RTC library,
Download: https://github.com/PaulStoffregen/DS1307RTC, add the ZIP file by, Sketch > Include Library > Add.ZIP Library. Or Sketch > Include Library > Manage Libraries > search DS1307RTC library by PaulStoffregen and install it.
The below sketches for set time and read time are same available from file > examples > DS1307RTC > SetTime & ReadTest.
Set time of RTC
Here the compiler time is the time used for setting the initial time, which is the current system time. Just upload the sketch and open the serial monitor.
#include <Wire.h> #include <TimeLib.h> #include <DS1307RTC.h> const char *monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; tmElements_t tm; void setup() { bool parse = false; bool config = false; // get the date and time the compiler was run if (getDate(__DATE__) && getTime(__TIME__)) { parse = true; // and configure the RTC with this info if (RTC.write(tm)) { config = true; } } Serial.begin(9600); while (!Serial) ; // wait for Arduino Serial Monitor delay(200); if (parse && config) { Serial.print("DS1307 configured Time="); Serial.print(__TIME__); Serial.print(", Date="); Serial.println(__DATE__); } else if (parse) { Serial.println("DS1307 Communication Error :-{"); Serial.println("Please check your circuitry"); } else { Serial.print("Could not parse info from the compiler, Time=\""); Serial.print(__TIME__); Serial.print("\", Date=\""); Serial.print(__DATE__); Serial.println("\""); } } void loop() { } bool getTime(const char *str) { int Hour, Min, Sec; if (sscanf(str, "%d:%d:%d", &Hour, &Min, &Sec) != 3) return false; tm.Hour = Hour; tm.Minute = Min; tm.Second = Sec; return true; } bool getDate(const char *str) { char Month[12]; int Day, Year; uint8_t monthIndex; if (sscanf(str, "%s %d %d", Month, &Day, &Year) != 3) return false; for (monthIndex = 0; monthIndex < 12; monthIndex++) { if (strcmp(Month, monthName[monthIndex]) == 0) break; } if (monthIndex >= 12) return false; tm.Day = Day; tm.Month = monthIndex + 1; tm.Year = CalendarYrToTm(Year); return true; }
Read time from RTC
Once the set time code had run, now the RTC module has the current time value. The below code can be used to read the time and date from the module.
#include <Wire.h> #include <TimeLib.h> #include <DS1307RTC.h> const char *Weekday[7] = {"Thursday", "Friday", "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday"}; void setup() { Serial.begin(9600); while (!Serial) ; // wait for serial delay(200); Serial.println("DS1307RTC Read Test"); Serial.println("-------------------"); } void loop() { tmElements_t tm; if (RTC.read(tm)) { Serial.print("Time = "); //Hours:Minutes:Seconds print2digits(tm.Hour); // Returns Hours read from RTC Serial.write(':'); print2digits(tm.Minute); // Minutes Serial.write(':'); print2digits(tm.Second); // Seconds Serial.print(" | Date = "); //Day_of_week Day-Month-Year Serial.print(Weekday[(tm.Wday - 1)])//Day of week Serial.print(", "); print2digits(tm.Day); // Day Serial.write('/'); print2digits(tm.Month); // Month Serial.write('/'); Serial.print(tmYearToCalendar(tm.Year)); //unix epoch to current year. Serial.println(); } else { if (RTC.chipPresent()) { Serial.println("The DS1307 is stopped. Please run the SetTime"); Serial.println(); } else { Serial.println("DS1307 read error! Please check the circuitry."); Serial.println(); } delay(9000); } delay(1000); } void print2digits(int number) { if (number >= 0 && number < 10) { Serial.write('0'); } Serial.print(number); }
The format of the time and date can be arranged by changing the order of each function and other text or characters.
The RTC time is Unix / Epoch time. Unix time or Epoch time is a system for describing a point in time, it is defined as the number of seconds that have elapsed since 00:00:00 UTC on Thursday, 1 January 1970.
In the code, the function “tm.Year” returns the years passed since 1970 which is then converted to the current year using the function “tmYearToCalendar”; tm.Year + 1970.
Also, the function “tm.Wday” returns a number for the day of the week, which is from 1 to 7 respectively in the order with Thursday as the starting day to end the day on Wednesday. The name of the respective day is then called from the array “Weekday”. The day of the week can be obtained by taking every seventh day after 1 January 1970 is Thursday and days of the week follows.
In the above code, the time is showing in 24hours format, if required the below codes can be added to display time in 12hours format with periods AM and PM.
Add the below function definition and insert function call “hr12format(tm.Hour)” instead of “print2digits(tm.Hour);” to convert and display 24hrs to 12hrs clock.
//24hrs to 12hrs format void hr12format(int hours) { if ((hours % 12) != 0) { print2digits(hours % 12); } else { print2digits(hours); } }
Add below function definition and insert function call after seconds “AM_PM(tm.Hour)” to add AM/PM.
//12-hour clock AM/PM void AM_PM(int hours) { if (hours < 12) { lcd.print(" AM"); } else { lcd.print(" PM"); } }
RTC clock with LCD display
Here instead of a serial monitor, a 16×2 LCD is used to display the time and date. In this circuit, the LCD is connected to the Arduino via an I2C serial interface adapter. So, both the LCD display and RTC module are interfaced through a common I2C bus.
Refer LCD interface with the Arduino – Tutorial; the LCD display can be connected to the Arduino with or without an I2C adapter, both methods are described in the tutorial.
Code
#include <Wire.h> #include <TimeLib.h> #include <DS1307RTC.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27, 16, 2); //16x2 display const char *Weekday[7] = {"Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed"}; void setup() { lcd.init();// initialize the lcd lcd.backlight();// Backlight ON } void loop() { tmElements_t tm; if (RTC.read(tm)) { lcd.setCursor(3, 0); //Hours:Minutes:Seconds AM/PM hr12format(tm.Hour); lcd.print(':'); print2digits(tm.Minute); lcd.print(':'); print2digits(tm.Second); AM_PM(tm.Hour); lcd.setCursor(0, 1); // Day_of_week Day-Month-Year lcd.print(Weekday[(tm.Wday - 1)]); lcd.print(" "); print2digits(tm.Day); lcd.print('-'); print2digits(tm.Month); lcd.print('-'); lcd.print(tmYearToCalendar(tm.Year)); } else { lcd.clear(); lcd.setCursor(0, 0); if (RTC.chipPresent()) { lcd.print("Time not set"); } else { lcd.print("DS1307 read error!."); } delay(3000); } delay(500); } //print as 2 digits, eg: 1 -> 01 void print2digits(int digit) { if (digit >= 0 && digit < 10) { lcd.print('0'); } lcd.print(digit); } //24hrs to 12hrs format void hr12format(int hours) { if ((hours % 12) != 0) { print2digits(hours % 12); } else { print2digits(hours); } } //12-hour clock AM/PM void AM_PM(int hours) { if (hours < 12) { lcd.print(" AM"); } else { lcd.print(" PM"); } }