Table of Contents
In this post we will have a look at RTC with Arduino – DS1307 and DS3231. We will see how to connect them to the Arduino and the code as well.
Lets take an example. Say you want to switch on your geyser everyday at 6 AM. You can make an MCU circuit or Arduino based circuit to switch it ON. But the problem lies in knowing the time. How will the circuit know the time? This is where RTCs come to the rescue.
If you have ever opened a PC cabinet, you will find that there is a small coin cell on the motherboard. This cell powers the onboard RTC. The RTC helps the computer remember the time even after it has been off for a long time.
RTC or Real Time Clock modules are devices that remember TIME and DATE. They also have a battery connected to them which keep counting the time in case of power failures. This keeps the TIME and DATE up to date. So we can have accurate TIME and DATE from RTC module whenever we want. This makes them really useful in systems where we need to know the time.
RTC Modules
There are two very popular RTC modules – DS1307 and DS3231.
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 may sound like a problem, however will usually result with the clock being off by around five or so minutes per month.
The DS3231 is much 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.
DS1307 module
If you have the DS1307 module you will need to solder the wires to the board, or solder on some inline header pins so you can use jumper wires. Then connect the SCL and SDA pins to your Arduino, and the Vcc pin to the 5V pin and GND to GND.
DS3231 module
Connecting this module is easy as header pins are installed on the board at the factory. You can simply run jumper wires again from SCL and SDA to the Arduino and again from the module’s Vcc and GND pins to your board’s 5V or 3.3.V and GND. However these are duplicated on the other side for soldering your own wires.
Both of these modules have the required pull-up resistors, so you don’t need to add your own. Like all devices connected to the I2C bus, try and keep the length of the SDA and SCL wires to a minimum. With both of the modules, a backup battery is not installed when you receive them – it’s a good idea to buy a new CR2032 battery and fit it to the module.
Along with keeping track of the time and date, these modules also have a small EEPROM, an alarm function (DS3231 only) and the ability to generate a square-wave of various frequencies – all of which we will discuss later.
Connecting your RTC module to an Arduino
Both modules use the I2C bus, which makes connection very easy. First, we will need to identify which pins on your Arduino or compatible boards are used for the I2C bus – these will be knows as SDA (or data) and SCL (or clock).
- On Arduino Uno or compatible boards, these pins are A4 and A5 for data and clock;
- On the Arduino Mega the pins are D20 and D21 for data and clock;
- And if you’re using a Pro Mini-compatible the pins are A4 and A5 for data and clock, which are parallel to the main pins.
Reading and writing the time from RTC with Arduino
Once you have wired up your RTC module. enter and upload the following sketch. Although the notes and functions in the sketch refer only to the DS3231, the code also works with the DS1307.
#include "Wire.h" #define DS3231_I2C_ADDRESS 0x68 // Convert normal decimal numbers to binary coded decimal byte decToBcd(byte val) { return( (val/10*16) + (val%10) ); } // Convert binary coded decimal to normal decimal numbers byte bcdToDec(byte val) { return( (val/16*10) + (val%16) ); } void setup() { Wire.begin(); Serial.begin(9600); // set the initial time here: // DS3231 seconds, minutes, hours, day, date, month, year // setDS3231time(30,42,21,7,16,10,21); } void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year) { // sets time and date data to DS3231 Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); // set next input to start at the seconds register Wire.write(decToBcd(second)); // set seconds Wire.write(decToBcd(minute)); // set minutes Wire.write(decToBcd(hour)); // set hours Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday) Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31) Wire.write(decToBcd(month)); // set month Wire.write(decToBcd(year)); // set year (0 to 99) Wire.endTransmission(); } void readDS3231time(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year) { Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); // set DS3231 register pointer to 00h Wire.endTransmission(); Wire.requestFrom(DS3231_I2C_ADDRESS, 7); // request seven bytes of data from DS3231 starting from register 00h *second = bcdToDec(Wire.read() & 0x7f); *minute = bcdToDec(Wire.read()); *hour = bcdToDec(Wire.read() & 0x3f); *dayOfWeek = bcdToDec(Wire.read()); *dayOfMonth = bcdToDec(Wire.read()); *month = bcdToDec(Wire.read()); *year = bcdToDec(Wire.read()); } void displayTime() { byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; // retrieve data from DS3231 readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // send it to the serial monitor Serial.print(hour, DEC); // convert the byte variable to a decimal number when displayed Serial.print(":"); if (minute<10) { Serial.print("0"); } Serial.print(minute, DEC); Serial.print(":"); if (second<10) { Serial.print("0"); } Serial.print(second, DEC); Serial.print(" "); Serial.print(dayOfMonth, DEC); Serial.print("/"); Serial.print(month, DEC); Serial.print("/"); Serial.print(year, DEC); Serial.print(" Day of week: "); switch(dayOfWeek){ case 1: Serial.println("Sunday"); break; case 2: Serial.println("Monday"); break; case 3: Serial.println("Tuesday"); break; case 4: Serial.println("Wednesday"); break; case 5: Serial.println("Thursday"); break; case 6: Serial.println("Friday"); break; case 7: Serial.println("Saturday"); break; } } void loop() { displayTime(); // display the real-time clock data on the Serial Monitor, delay(1000); // every second }
Code Explanation
There may be a lot of code, however it breaks down well into manageable parts.
- It first includes the Wire library, which is used for I2C bus communication.
- Then we define the bus address for the RTC as 0x68.
- Next, we have two functions that convert decimal numbers to BCD (binary-coded decimal) and vice versa. These are necessary as the RTC ICs work in BCD not decimal.
Setting Time in RTC with Arduino
The function setDS3231time() is used to set the clock. Using it is very easy, simple insert the values from year down to second, and the RTC will start from that time. For example if you want to set the following date and time – Saturday October 16, 2021 and 9:42 pm and 30 seconds – you would use:
setDS3231time(30,42,21,7,16,10,21);
Note that the time is set using 24-hour time, and the fourth paramter is the “day of week”. This falls between 1 and 7 which is Sunday to Saturday respectively. These parameters are byte values if you are subsituting your own variables. Once you have run the function once it’s wise to prefix it with // and upload your code again, so it will not reset the time once the power has been cycled or micrcontroller reset.
Reading Time from RTC with Arduino
Reading the time from the RTC is very simple, in fact the process can be followed neatly inside the function displayTime().
You will need to define seven byte variables to store the data from the RTC, and these are then inserted in the function readDS3231time(). For example if your variables are:
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
… you would refresh them with the current data from the RTC by using:
readDS3232time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
Then you can use the variables as you see fit, from sending the time and date to the serial monitor as the example sketch does – to converting the data into a suitable form for all sorts of output devices.
Just to check everything is working, enter the appropriate time and date into the demonstration sketch, upload it, comment out the setDS3231time() function and upload it again. Then open the serial monitor, and you should be provided with a running display of the current time and date.
Now, we can use it in some projects, such as the Temperature Logger with Arduino. In this project, we read the temperature every 15 minutes and store it in the SD card with a time stamp. We read the time stamp using an RTC or a Real Time Clock as discussed in this post.
Hi, I’m Vivek, a Senior Embedded Innovation Specialist. I have been working on Embedded Systems and IoT for the past 11 years. I love to share my knowledge and train those who are interested. Nerdyelectronics.com was started out of this interest. You can read my full profile in this link.
I have a arduino project that uses the following text in the sketch. when I try to compile the sketch void readDS3231time(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year) I get an compile error was not declared in this scope.
I found some text with this sketch but no further info. Any help appreciated. thanks