Real Time Clock and Temperature Monitor using DS3231 Module

Emmanuel Odunlade   emmaodunlade@gmail.com     
426
Project tested

Hi guys welcome to this tutorial. One of the most important thing everyone wants to keep track of daily is, time and with easy to use platforms like the arduino it is very easy to create your own timepiece and in the case of this tutorial add a temperature monitor to it.

For this tutorial, we will be creating a real time clock and temperature monitor using the simple and easy to use DS3231 module.

Introduction

DS3231 Real Time Clock Module

The DS3231 is a very low power RTC chip, it has the ability to keep time with incredible accuracy such that even after power has been disconnected from your product, it can run for years on a connected coin cell battery. This module has the ability to communicate via I2C or SPI but for this tutorial we will be using the I2C mode for communications between our arduino and the DS3231. The module also comes with a quite accurate temperature sensor which we will be using to get temperature readings. The collected temperature and clock data is then displayed on the 16×2 LCD via the Arduino.

LCD Keypad Shield

Required Components

The following components will be needed for this tutorial. They can be purchased via the links attached.

1. DS3231 module 
2. 16×2 LCD module or shield
3. Arduino Mega, or any other variation
4. Jumper wires
5. Potentiometer (if not using an LCD shield)
6. Small Breadboard 

 

Schematics

Connect all components as shown in the Fritzing schematics below, kindly note the LCD connection will not be needed if using the shield.

Since the DS3231 is going to communicate via I2C then its I2C pins will be connected to the arduino’s I2C (SDA and SCL) pins which on the mega are located on pin A0 and A1 or pin 20 (SDA) and 21 (SCL) of the arduino mega.

RTC - Arduino MEGA
SDA - Pin 20(SDA)
SCL - Pin 21(SCL)
VCC - 5v
GND - GND

Next connection is between the LCD and the Arduino. If you are using the screen and keypad shield whose link is attached above, all you will just need to do is plug it in to your arduino as shown below.

LCD Keypad shield Mounted on the Arduino

If not then you can connect it as described in the schematics and illustrated below.

LCD - ARDUINO
pin 1 - GND
pin 2 - 5v
pin 3 - Middle pin of the Potentiometer(check Schematics)
pin 4 - D8
Pin 5 - GND
pin 6 - D9
pin 7-10 - GND or nothing
pin 11 - D10
pin 12 - D11
pin 13 - D12
pin 14 - D13
pin 15 - VCC
pin 16 - GND

 

Schematics

 

Code

With the connections done, lets jump into writing the code.

The first thing we need to do is to download the arduino library for the ds3231 RTC. The library can be found here and is also attached at the end of this project. Rename the library to “RTC” and install it, by copying and pasting into the Arduino libraries folder.

Launch the Arduino IDE and copy in the Attached code.

To do a break down of the code, the first thing we do in the code is to include the libraries that carry some of the dependencies needed for our code to run. The Libraries include wire.h to enable I2C communication, Ds3231.h and rtc_ds3231.h to enable the RTC to work and the Liquidcrystal.h which makes it easy for us to work with the LCD.

#include <Wire.h>
#include "ds3231.h"
#include "rtc_ds3231.h"
#include <LiquidCrystal.h>

The next thing is to declare the LCD pins and move into the setup function

LiquidCrystal lcd(8,9,4,5,6,7);

The code is a modified version of the example found in the arduino library. The first thing we will be doing with the code is setting the time of the ds3231. The time is set using this line under the setup section.

    Serial.println("Setting time");
    parse_cmd("T302911604102014",16);

2014 is the year,
10 is the month
04 is the day of the month
6 is the day of the week
11 is hour of the day (its 11 am here)
29 is the minute
30 is the seconds

you can change this to match your current date when setting the time.

The device does not come with time preset but after setting it once, the action will no longer be needed.

The next thing after this is to move into the loop function. The loop function displays the time and temperature on the LCD after querying the DS3231 module.

void loop()
{
    char in;
    char tempF[6]; 
    float temperature;
    char buff[BUFF_MAX];
    unsigned long now = millis();
    struct ts t;

    // show time once in a while
    if ((now - prev > interval) && (Serial.available() <= 0)) {
        DS3231_get(&t); //Get time
        parse_cmd("C",1);
        temperature = DS3231_get_treg(); //Get temperature
        dtostrf(temperature, 5, 1, tempF);

        lcd.clear();
        lcd.setCursor(1,0);
        
        lcd.print(t.mday);
        
        printMonth(t.mon);
        
        lcd.print(t.year);
        
        lcd.setCursor(0,1); //Go to second line of the LCD Screen
        lcd.print(t.hour);
        lcd.print(":");
        if(t.min<10)
        {
          lcd.print("0");
        }
        lcd.print(t.min);
        lcd.print(":");
        if(t.sec<10)
        {
          lcd.print("0");
        }
        lcd.print(t.sec);
        
        lcd.print(' ');
        lcd.print(tempF);
        lcd.print((char)223);
        lcd.print("C ");
        prev = now;
    }

    
    if (Serial.available() > 0) {
        in = Serial.read();

        if ((in == 10 || in == 13) && (recv_size > 0)) {
            parse_cmd(recv, recv_size);
            recv_size = 0;
            recv[0] = 0;
        } else if (in < 48 || in > 122) {;       // ignore ~[0-9A-Za-z]
        } else if (recv_size > BUFF_MAX - 2) {   // drop lines that are too long
            // drop
            recv_size = 0;
            recv[0] = 0;
        } else if (recv_size < BUFF_MAX - 2) {
            recv[recv_size] = in;
            recv[recv_size + 1] = 0;
            recv_size += 1;
        }

    }
}

The next block of code is the parse_cmd function that was used to set the time.

void parse_cmd(char *cmd, int cmdsize)
{
    uint8_t i;
    uint8_t reg_val;
    char buff[BUFF_MAX];
    struct ts t;

    //snprintf(buff, BUFF_MAX, "cmd was '%s' %d\n", cmd, cmdsize);
    //Serial.print(buff);

    // TssmmhhWDDMMYYYY aka set time
    if (cmd[0] == 84 && cmdsize == 16) {
        //T355720619112011
        t.sec = inp2toi(cmd, 1);
        t.min = inp2toi(cmd, 3);
        t.hour = inp2toi(cmd, 5);
        t.wday = inp2toi(cmd, 7);
        t.mday = inp2toi(cmd, 8);
        t.mon = inp2toi(cmd, 10);
        t.year = inp2toi(cmd, 12) * 100 + inp2toi(cmd, 14);
        DS3231_set(t);
        Serial.println("OK");
    } else if (cmd[0] == 49 && cmdsize == 1) {  // "1" get alarm 1
        DS3231_get_a1(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 50 && cmdsize == 1) {  // "2" get alarm 1
        DS3231_get_a2(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 51 && cmdsize == 1) {  // "3" get aging register
        Serial.print("aging reg is ");
        Serial.println(DS3231_get_aging(), DEC);
    } else if (cmd[0] == 65 && cmdsize == 9) {  // "A" set alarm 1
        DS3231_set_creg(DS3231_INTCN | DS3231_A1IE);
        //ASSMMHHDD
        for (i = 0; i < 4; i++) {
            time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // ss, mm, hh, dd
        }
        boolean flags[5] = { 0, 0, 0, 0, 0 };
        DS3231_set_a1(time[0], time[1], time[2], time[3], flags);
        DS3231_get_a1(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 66 && cmdsize == 7) {  // "B" Set Alarm 2
        DS3231_set_creg(DS3231_INTCN | DS3231_A2IE);
        //BMMHHDD
        for (i = 0; i < 4; i++) {
            time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // mm, hh, dd
        }
        boolean flags[5] = { 0, 0, 0, 0 };
        DS3231_set_a2(time[0], time[1], time[2], flags);
        DS3231_get_a2(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 67 && cmdsize == 1) {  // "C" - get temperature register
        Serial.print("temperature reg is ");
        Serial.println(DS3231_get_treg(), DEC);
    } else if (cmd[0] == 68 && cmdsize == 1) {  // "D" - reset status register alarm flags
        reg_val = DS3231_get_sreg();
        reg_val &= B11111100;
        DS3231_set_sreg(reg_val);
    } else if (cmd[0] == 70 && cmdsize == 1) {  // "F" - custom fct
        reg_val = DS3231_get_addr(0x5);
        Serial.print("orig ");
        Serial.print(reg_val,DEC);
        Serial.print("month is ");
        Serial.println(bcdtodec(reg_val & 0x1F),DEC);
    } else if (cmd[0] == 71 && cmdsize == 1) {  // "G" - set aging status register
        DS3231_set_aging(0);
    } else if (cmd[0] == 83 && cmdsize == 1) {  // "S" - get status register
        Serial.print("status reg is ");
        Serial.println(DS3231_get_sreg(), DEC);
    } else {
        Serial.print("unknown command prefix ");
        Serial.println(cmd[0]);
        Serial.println(cmd[0], DEC);
    }
}

After uploading the code for the first time, the time setting part in the setup() is then commented out and the code can be uploaded again.

You should then see something like the image below.

Time and Temperature displayed on LCD

A youtube video on how the project works can be found here. The video tutorial is created by educ8s.tv channel

The source code, library and other files can be downloaded from here RTCCODE

That’s it guys!, let me know if you have any questions, I will be glad to help.

Download

Leave a Reply