Arduino OLED digital Clock using DS3231 RTC.

Arduino OLED digital Clock using DS3231 RTC.
In my previous tutorials I showed how the DS3231 rtc and SSD1306 OLED modules work and how they can be interfaced to Arduino. In this tutorial I’ll show how these two devices can be combined to make a simple digital clock. Before you proceed you should check out these posts for reference:
  • DS3231 RTC interfacing with Arduino.
  • Interfacing OLED I2C Display with Arduino.
  • The first setup for the DS3231 OLED clock we shall just simply connect the OLED and the RTC to Arduino so that we can display time and temperature.The schematic of the setup is as shown below. Since both the SSD1306 OLED and the DS3231 RTC are I2C devices we just connect the corresponding pins as;
  • SCL to Arduino analog pin A5
  • SDA to Arduino analog pin A4
  • GND to Arduino GROUND
  • VCC to Arduino 5V
  • The main components for this project can be bought from these links.
    MakerFocus 4pcs I2C OLED 0.96 Inch OLED Display Module IIC SSD1306 128 64 LCD White with Du-pont Wire 40-Pin Female to Female for Ar duino UNO R3 STM
    WayinTop 2pcs DS3231 AT24C32 IIC RTC Clock Module Real Time Clock Module for Arduino
    Arduino Uno REV3 [A000066]
    Product
    4pcs I2C OLED 0.96 Inch OLED Display Module IIC SSD1306 128 64 LCD
    2pcs DS3231 AT24C32 IIC RTC Clock Module for Arduino
    ARDUINO UNO R3 [A000066]
    Price
    $18.99
    $7.99
    $21.10
    MakerFocus 4pcs I2C OLED 0.96 Inch OLED Display Module IIC SSD1306 128 64 LCD White with Du-pont Wire 40-Pin Female to Female for Ar duino UNO R3 STM
    Product
    4pcs I2C OLED 0.96 Inch OLED Display Module IIC SSD1306 128 64 LCD
    Price
    $18.99
    Buy Now
    WayinTop 2pcs DS3231 AT24C32 IIC RTC Clock Module Real Time Clock Module for Arduino
    Product
    2pcs DS3231 AT24C32 IIC RTC Clock Module for Arduino
    Price
    $7.99
    Buy Now
    Arduino Uno REV3 [A000066]
    Product
    ARDUINO UNO R3 [A000066]
    Price
    $21.10
    Buy Now

    Last update on 2021-06-17 / Affiliate links / Images from Amazon Product Advertising API

    Code for DS3231 OLED Clock.

    The code is almost the same as was used in the previous tutorials only that this time we add the part for the OLED. In this case the date , time and temperature will be automatically updated and displayed on the OLED.
    #include <SPI.h>
    #include <Wire.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_SSD1306.h>
    #include "RTClib.h"
    
    RTC_DS3231 rtc;
    char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
    
    #define SCREEN_WIDTH 128 // OLED display width, in pixels
    #define SCREEN_HEIGHT 32 // OLED display height, in pixels
    
    #define OLED_RESET 4
    Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
    
    void setup() {
      Serial.begin(9600);
      delay(3000); // wait for console opening
    
      if (! rtc.begin()) {
        Serial.println("Couldn't find RTC");
        while (1);
      }
    
      if (rtc.lostPower()) {
        Serial.println("RTC lost power, lets set the time!");
        // following line sets the RTC to the date & time this sketch was compiled
        rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
        // This line sets the RTC with an explicit date & time, for example to set
        // January 21, 2014 at 3am you would call:
        // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
      }
      
      display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32)// Check your I2C address and enter it here, in Our case address is 0x3C
      display.clearDisplay();
      display.display(); // this command will display all the data which is in buffer
      display.setTextColor(WHITE, BLACK);
      display.drawRect(117, 25, 3, 3, WHITE);     // Put degree symbol ( ° )
      draw_text(0, 25, "TEMPERATURE =", 1);
      draw_text(122, 25, "C", 1);
    }
    
    void loop() {
      DateTime now = rtc.now();
      /*============Display Date=================*/
    display.setTextSize(1);
    display.setCursor(0,0);
    display.print(daysOfTheWeek[now.dayOfTheWeek()]);
    
    char currentDate [16];
    uint8_t thisDay, thisMonth ;
    thisDay = now.day();
    thisMonth = now.month();
    sprintf (currentDate, "%02d/%02d/", thisDay, thisMonth); //add leading zeros to the day and month
    
    display.setTextSize(1);
    display.setCursor(62,0);
    display.print(currentDate);
    
    display.setTextSize(1);
    display.setCursor(102,0);
    display.print(now.year(), DEC);
    
    
    /*================Display Time================*/ 
    char buffer [16];
    uint8_t thisSec, thisMin, thisHour;
    thisSec = now.second();
    thisMin = now.minute();
    thisHour = now.hour();
    sprintf (buffer, "%02d:%02d:%02d", thisHour, thisMin, thisSec);
    
    display.setTextSize(2);
    display.setCursor(15,9);
    display.print(buffer);
    
    
    /*=============Display Temperature=====================*/
    display.setTextSize(1);
    display.setCursor(82,25);
    display.print(rtc.getTemperature());
    
    display.display(); 
    
    }
    
    void draw_text(byte x_pos, byte y_pos, char *text, byte text_size) {
      display.setCursor(x_pos, y_pos);
      display.setTextSize(text_size);
      display.print(text);
      display.display();
    }
    
    NOTE: The display depends on the size of the OLED you are using. The above code is for a 128×32 display. You have to adjust the declaration of the width and height of the OLED and the parameters in the setCursor() function depending on the size of the display being used.
    In the next setup of the DS32331 OLED clock we are going to use the memory storage capacity of the DS3231 RTC. We are going to include buttons to enable manual adjustment of the date and time which is written to the EEPROM of the rtc module. The shematic for this setup is shown below.
    arduino oled clock with buttons

    CODE

    #include <SPI.h>
    #include <Wire.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_SSD1306.h>
    
    #define SCREEN_WIDTH 128 // OLED display width, in pixels
    #define SCREEN_HEIGHT 32 // OLED display height, in pixels
     
    #define OLED_RESET 4
    Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
     
    #define button1    9                       // Button B1 is connected to Arduino pin 9
    #define button2    8                       // Button B2 is connected to Arduino pin 8
     
    void setup(void) {
      pinMode(button1, INPUT_PULLUP);
      pinMode(button2, INPUT_PULLUP);
      delay(1000);
     
      // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
      display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 
      // init done
     
      // Clear the display buffer.
      display.clearDisplay();
      display.display();
     
      display.setTextColor(WHITE, BLACK);
      display.drawRect(117, 25, 3, 3, WHITE);     // Put degree symbol ( ° )
      draw_text(0, 25, "TEMPERATURE =", 1);
      draw_text(122, 25, "C", 1);
    }
     
    char Time[]     = "  :  :  ";
    char Calendar[] = "  /  /20  ";
    char temperature[] = " 00.00";
    char temperature_msb;
    byte i, second, minute, hour, day, date, month, year, temperature_lsb;
     
    void display_day(){
      switch(day){
        case 1:  draw_text(0, 0, " SUNDAY  ", 1); break;
        case 2:  draw_text(0, 0, " MONDAY  ", 1); break;
        case 3:  draw_text(0, 0, " TUESDAY ", 1); break;
        case 4:  draw_text(0, 0, "WEDNESDAY", 1); break;
        case 5:  draw_text(0, 0, "THURSDAY ", 1); break;
        case 6:  draw_text(0, 0, " FRIDAY  ", 1); break;
        default: draw_text(0, 0, "SATURDAY ", 1);
      }
    }
     
    void DS3231_display(){
      // Convert BCD to decimal
      second = (second >> 4) * 10 + (second & 0x0F);
      minute = (minute >> 4) * 10 + (minute & 0x0F);
      hour   = (hour >> 4)   * 10 + (hour & 0x0F);
      date   = (date >> 4)   * 10 + (date & 0x0F);
      month  = (month >> 4)  * 10 + (month & 0x0F);
      year   = (year >> 4)   * 10 + (year & 0x0F);
      // End conversion
     
      Time[7]     = second % 10 + 48;
      Time[6]     = second / 10 + 48;
      Time[4]     = minute % 10 + 48;
      Time[3]     = minute / 10 + 48;
      Time[1]     = hour   % 10 + 48;
      Time[0]     = hour   / 10 + 48;
      Calendar[9] = year   % 10 + 48;
      Calendar[8] = year   / 10 + 48;
      Calendar[4] = month  % 10 + 48;
      Calendar[3] = month  / 10 + 48;
      Calendar[1] = date   % 10 + 48;
      Calendar[0] = date   / 10 + 48;
      if(temperature_msb < 0){
        temperature_msb = abs(temperature_msb);
        temperature[0] = '-';
      }
      else
        temperature[0] = ' ';
      temperature_lsb >>= 6;
      temperature[2] = temperature_msb % 10  + 48;
      temperature[1] = temperature_msb / 10  + 48;
      if(temperature_lsb == 0 || temperature_lsb == 2){
        temperature[5] = '0';
        if(temperature_lsb == 0) temperature[4] = '0';
        else                     temperature[4] = '5';
      }
      if(temperature_lsb == 1 || temperature_lsb == 3){
        temperature[5] = '5';
        if(temperature_lsb == 1) temperature[4] = '2';
        else                     temperature[4] = '7';
      }
     
      draw_text(60,  0, Calendar, 1);                     // Display the date (format: dd/mm/yyyy)
      draw_text(10, 9, Time, 2);                         // Display the time
      draw_text(75, 25, temperature, 1);                  // Display the temperature
    }
     
    void blink_parameter(){
      byte j = 0;
      while(j < 10 && digitalRead(button1) && digitalRead(button2)){
        j++;
        delay(25);
      }
    }
     
    byte edit(byte x_pos, byte y_pos, byte parameter){
      char text[3];
      sprintf(text,"%02u", parameter);
      while(!digitalRead(button1));                      // Wait until button B1 released
      while(true){
        while(!digitalRead(button2)){                    // If button B2 is pressed
          parameter++;
          if(i == 0 && parameter > 31)                   // If date > 31 ==> date = 1
            parameter = 1;
          if(i == 1 && parameter > 12)                   // If month > 12 ==> month = 1
            parameter = 1;
          if(i == 2 && parameter > 99)                   // If year > 99 ==> year = 0
            parameter = 0;
          if(i == 3 && parameter > 23)                   // If hours > 23 ==> hours = 0
            parameter = 0;
          if(i == 4 && parameter > 59)                   // If minutes > 59 ==> minutes = 0
            parameter = 0;
          sprintf(text,"%02u", parameter);
          draw_text(x_pos, y_pos, text, 1);
          delay(200);                                    // Wait 200ms
        }
        draw_text(x_pos, y_pos, "  ", 1);
        blink_parameter();
        draw_text(x_pos, y_pos, text, 1);
        blink_parameter();
        if(!digitalRead(button1)){                       // If button B1 is pressed
          i++;                                           // Increament 'i' for the next parameter
          return parameter;                              // Return parameter value and exit
        }
      }
    }
     
    void draw_text(byte x_pos, byte y_pos, char *text, byte text_size) {
      display.setCursor(x_pos, y_pos);
      display.setTextSize(text_size);
      display.print(text);
      display.display();
    }
     
    void loop() {
     
      if(!digitalRead(button1)){                         // If button B1 is pressed
        i = 0;
        while(!digitalRead(button1));                    // Wait for button B1 release
        while(true){
          while(!digitalRead(button2)){                  // While button B2 pressed
            day++;                                       // Increment day
            if(day > 7) day = 1;
            display_day();                               // Call display_day function
            delay(200);                                  // Wait 200 ms
          }
          draw_text(0, 0, "         ", 1);
          blink_parameter();                             // Call blink_parameter function
          display_day();                                 // Call display_day function
          blink_parameter();                             // Call blink_parameter function
          if(!digitalRead(button1))                      // If button B1 is pressed
            break;
        }
        //set position of text when editing on button press
        date   = edit(60, 0, date);                      // Edit date
        month  = edit(80, 0, month);                    // Edit month
        year   = edit(110,0, year);                    // Edit year
        hour   = edit(14, 9, hour);                     // Edit hours
        minute = edit(50, 9, minute);                   // Edit minutes
     
        // Convert decimal to BCD
        minute = ((minute / 10) << 4) + (minute % 10);
        hour = ((hour / 10)  << 4) + (hour % 10);
        date = ((date / 10) <<  4) + (date % 10);
        month = ((month / 10)  << 4) + (month % 10);
        year = ((year / 10)  << 4) + (year % 10);
        // End conversion
     
        // Write data to DS3231 RTC
        Wire.beginTransmission(0x68);               // Start I2C protocol with DS3231 address
        Wire.write(0);                              // Send register address
        Wire.write(0);                              // Reset sesonds and start oscillator
        Wire.write(minute);                         // Write minute
        Wire.write(hour);                           // Write hour
        Wire.write(day);                            // Write day
        Wire.write(date);                           // Write date
        Wire.write(month);                          // Write month
        Wire.write(year);                           // Write year
        Wire.endTransmission();                     // Stop transmission and release the I2C bus
        delay(200);                                 // Wait 200ms
      }
     
      Wire.beginTransmission(0x68);                 // Start I2C protocol with DS3231 address
      Wire.write(0);                                // Send register address
      Wire.endTransmission(false);                  // I2C restart
      Wire.requestFrom(0x68, 7);                    // Request 7 bytes from DS3231 and release I2C bus at end of reading
      second = Wire.read();                         // Read seconds from register 0
      minute = Wire.read();                         // Read minuts from register 1
      hour   = Wire.read();                         // Read hour from register 2
      day    = Wire.read();                         // Read day from register 3
      date   = Wire.read();                         // Read date from register 4
      month  = Wire.read();                         // Read month from register 5
      year   = Wire.read();                         // Read year from register 6
      Wire.beginTransmission(0x68);                 // Start I2C protocol with DS3231 address
      Wire.write(0x11);                             // Send register address
      Wire.endTransmission(false);                  // I2C restart
      Wire.requestFrom(0x68, 2);                    // Request 2 bytes from DS3231 and release I2C bus at end of reading
      temperature_msb = Wire.read();                // Read temperature MSB
      temperature_lsb = Wire.read();                // Read temperature LSB
     
      display_day();
      DS3231_display();                             // Diaplay time & calendar
     
      delay(50);                                    // Wait 50ms 
    }
    
    When this code is uploaded to the Arduino board, you can use the buttons to set the time and date which will be stored by the RTC and can keep accurately this set time even when the power supply to the microcontroller is turned off.The OLED will display the set time, date and temperature.

    7 thoughts on “Arduino OLED digital Clock using DS3231 RTC.

    1. Hello!
      Build the clock with a 128 by 64 1306 0,96 oled display and it works great!
      Since it was planned using a bigger display, replaced the 0,96′ 1306 oled with a 1,3′ 1306.
      Aaaand it’s not working properly. 😉 Seems that the display driver is not compatible with the adafruit library!
      Do you have any workaround or help for me cause i have to use the bigger one. (Already build the case, smaller one doesn’t fit in).
      Big Thanks for helping me out
      Andreas

      1. hello i am using 128by64 oled display, could anyone tell me the exact cod for the display, I uploaded the cod, but the text size doesn’t clear

    2. Just built this and it is doing exactly what it is supposed to. Looks great. I am including the temp as shown in the second set of code.
      Can anyone tell me where exactly to insert the line(s) to display the temp in Fahrenheit? I know the usual equation for the conversion but not where it goes. Thanks

    3. The usage of the variable “now” is problematic if you include the time.h library. The Arduino IDE won’t throw an error but you’ll see very odd behavior.

    4. hi. its a very nice project. how can i convert to 12hours setting? thanks

    Comments are closed.

    Back to top