In the last post I built an Arduino based real time clock using DS1307 RTC and SSD1306 OLED and in this project I’m going to show how to build a real time clock with temperature monitor using Arduino, DS3231 RTC chip and SSD1306 OLED (128×64 pixel).
The DS3231 is more accurate than the DS1307 due to its built-in temperature sensor. It also (the DS3231) keeps the time running if the main power source is down. It also uses I2C interface to communicate with the master device which is in this case the Arduino. That means the DS3231 and the SSD1306 OLED screen share the same I2C bus. Even they share the same bus but at any time the microcontroller ‘speaks’ with 1 device only depending on the address sent. The DS3231 RTC address is 0x68 (the same address with the DS1307) and the SSD1306 OLED address is 0x3D.
In the circuit there are two push buttons for setting time and date of the real time clock.
Related Projects:
Arduino and DS3231 real time clock
Interfacing Arduino with SSD1306 OLED display
Arduino real time clock using DS1307 and SSD1306 OLED
Hardware Required:
- Arduino board
- DS3231 board — DS3231 RTC datasheet
- SSD1306 OLED (I2C mode)
- 2 x push button
- 3V coin cell battery
- Breadboard
- Jumper wires
The SSD1306 OLED used in this project is configured to work in I2C mode, some SSD1306 OLED boards may require a small hardware modifications (to select between SPI mode or I2C mode) such as soldering, placing jumpers …
In this project I used Adafruit SSD1306 OLED driver and Adafruit GFX library. Both libraries can be downloaded through Arduino IDE Library Manager of manually from the links below (after downloading, unzip the folders and place them in Arduino libraries folder, for example C:\Program Files\Arduino\libraries)
Adafruit SSD1306 OLED library — direct link
Adafruit GFX library — direct link
Project circuit:
Project circuit diagram is shown below.
(All grounded terminals are connected together)
The two push buttons B1 and B2 are for setting time and date.
Arduino Code:
SSD1306 OLED and DS3231 RTC share the same I2C bus and the Arduino communicates only with 1 device at a time depending on the address (sent by the Arduino), the SSD1306 address is 0x3D and the DS3231 address is 0x68.
The Arduino code below uses Adafruit SSD1306 OLED driver and Adafruit GFX library. It doesn’t use any library for the DS3231 RTC.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | // Arduino real time clock and temperature monitor with DS3231 and SSD1306 OLED #include <Wire.h> // Include Wire library (required for I2C devices) #include <Adafruit_GFX.h> // Include Adafruit graphics library #include <Adafruit_SSD1306.h> // Include Adafruit SSD1306 OLED driver #define OLED_RESET 4 Adafruit_SSD1306 display(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, 0x3D); // initialize with the I2C addr 0x3D (for the 128x64) // init done // Clear the display buffer. display.clearDisplay(); display.display(); display.setTextColor(WHITE, BLACK); display.drawRect(117, 56, 3, 3, WHITE); // Put degree symbol ( ° ) draw_text(0, 56, "TEMPERATURE =", 1); draw_text(122, 56, "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(40, 0, " SUNDAY ", 1); break; case 2: draw_text(40, 0, " MONDAY ", 1); break; case 3: draw_text(40, 0, " TUESDAY ", 1); break; case 4: draw_text(40, 0, "WEDNESDAY", 1); break; case 5: draw_text(40, 0, "THURSDAY ", 1); break; case 6: draw_text(40, 0, " FRIDAY ", 1); break; default: draw_text(40, 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(4, 14, Calendar, 2); // Display the date (format: dd/mm/yyyy) draw_text(16, 35, Time, 2); // Display the time draw_text(80, 56, 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, 2); delay(200); // Wait 200ms } draw_text(x_pos, y_pos, " ", 2); blink_parameter(); draw_text(x_pos, y_pos, text, 2); 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(40, 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; } date = edit(4, 14, date); // Edit date month = edit(40, 14, month); // Edit month year = edit(100, 14, year); // Edit year hour = edit(16, 35, hour); // Edit hours minute = edit(52, 35, 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 } // End of code. |
The small video below shows a simple hardware circuit of the project:
and the one below shows the simulation of the project with Proteus (the simulation circuit is not the same as the hardware circuit, the hardware circuit diagram is shown above).
Proteus simulation file download (for version 8.6 or higher):
Arduino + SSD1306 OLED + DS3231
Discover more from Simple Circuit
Subscribe to get the latest posts sent to your email.
bonjour a tous j ai assembler le schema il na pas fonctionner que la date est l annee. j ai modifier sont les recommandation super sa a marcher avec un ecran 4 broches, ensuite j ai changer les jours en langue francaise, le atmega 328 fonctionner a16 mhz externe ,jai modifier a 8mhz interne maintenant j ai une belle horloge oled…
il reste la temperature qui est pas bonne plus2 degree…mais la je sais pas faire Merci a tous ,
paie a vous
Dear Madam, Mister,
We have included a led for the time you change the date/time.
// Arduino real time clock and temperature monitor with DS3231 and SSD1306 OLED
}
// End of code.
Very cool project. I live in the USA and I was able to change the time to 12 hr format (and added “PM”) and I changed temp to Fahrenheit without much trouble. I am a beginner and just followed the help guide and reference code they included.with the Arduino compiler.
Como mostra na tela Temperatura e umidade se não tem sensor DHT no projeto?
No changes made to the code.
Nice project.
I tried it but it displays only day of week and date.
I don’t know how to see the time amd temperature.
Can you explain please?
If your display is 128×64 pixel (width=128 pixel, height=64 pixel) then everything should be ok!
I tried it to an 0.96″ SSD1306 OLED 128X64
As i told the first and only screen i get is the day of week with small font and the date in big font.
The switces works perfect.I can adjust day and date.
Make sure that you didn’t do any change to the code especially for the “void DS3231_display()” function!
I had same problem, also used 4 pin OLED screen, managed to fix it by changing top part of the code (lines 3-24) to below:
#include
#include
#include
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
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() {
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128×64
for(;;); // Don’t proceed, loop forever
}
pinMode(button1, INPUT_PULLUP);
pinMode(button2, INPUT_PULLUP);
delay(1000);
// init done
// Clear the display buffer.
display.clearDisplay();
Não vai conseguir ver Temperatura nem Umidade pois não tem nenhum sensor DHT no projeto.
Hi,
I copied the code and flashed it. The font is not the same as your pictures. Could you explasin hoe to modify the fonts to come out as you have them displayed please?
ArduinoNano+DS3231clock modul+DHT22 temperature modul+0.96OLED I2C display with 4 pins +2 buttons use. Code how to modifyed? How it use plese?! Can you help me?
Try to mix this project with the following one:
Arduino with SSD1306 OLED and DHT11/DHT22 sensor
The difficulty is that the video and the wiring diagram are other options than
reality for me. 128×64 pin 0.96 ”OLED display on video and circuit diagram
is not the same as the OLED version I want to use.
Both the video and the wiring diagram show a 7 pin model, but my OLED display has only 4 terminals.
Terminal 7 is CS, DC, RST, D1, D0, VCC, GND. In contrast, the 4 terminals on the display are SDA, SCL, VCC, GND.
I do not know the reason why this difference is described. New type, new development? What is the reason for the change?
Can the two types be used interchangeably despite the different designs?
What changes should be made to this in the circuits and encoding,
library usage?
How do I use the 4 pin OLED display instead of the 7 pin OLED display?
I would like to get directions for modifying the wiring diagram and modifying the encoding,
why and how to get started.
The 7-pin module can work with either SPI and I2C modes, the 4-pin module can work with I2C mode only!
The I2C slave address of the 7-pin module is 0x3D when the DC pin is connected to VDD (3.3V or 5V depending on system voltage) and it’s 0x3C when the DC pin is connected to GND.
The I2C slave address of the 4-pin module is also 0x3D or 0x3C where you can select between the two using a jumper located in the back of the module (may require soldering).
Hello, This is a very beautiful project and I must have it, I have plans on placing several of these throughout my little world but I built this project today and there is no display showing on the oled, nothing shows up. I have changed the display 3 times, I have tried 4 different Arduino Uno’s, I have replaced the hookup wiring with each different Arduino, I tried 3 different DS3231’s. I have even tried 4 different breadboards with each different Arduino. I noticed that the video shows a different hookup than the Fritzig and I hooked it up both ways still nothing showing up on the display. I am wondering if there is anything missing from the code. I am relatively new to these Arduino devices so I would not recognize anything missing. Can you offer any advice that might help because I believe this to be the perfect clock for my needs. Thank you
Please contact me via the contact form!
bet your bottom dollar, the address of oled is wrong, most of the time you may find change the address from 0x3D to 0x3C and that will light up your skies.
If not, find and run a sketch(google for one) to find I2C loads on your board that will tell you what addresses yours is running on
Thank You Simple Project for providing the code i just needed the blink_parameter part which is now perfectly working for my project.
I am going to build this real time clock and temperature monitor maybe this weekend (with or without the Chicken sound effects) but I can not read the metrics is there a way to convert them to American English?
If you mean mm-dd-yyyy arrangement of the calendar, yes you can do that, few modifications to the code are required.
hi….can you some code to change deg C to deg F….thx
°F = (°C x 9/5) + 32
thx for the reply…where do i insert this into the project cide
Are you able to share the modifications for that change?
Hi everyone, I have a big question, can it works with a ds1302 instead a ds1306? And if the case is correct, how can I do it?
I’m new in all these and I don’t know how to do it, or change it.
Thanks in advice.
If you mean DS1302 instead of DS3231 (not DS1306 or SSD1306), no you can’t, because the DS3231 uses I2C protocol (2-wire interface) whereas the DS1302 does use 3-wire interface.
write_text was not declared in this scope is I am getting all the time (case days of the week)
Hi tired this out but i get warnings “warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings”
and I see only the day (which is small) .and dd/mm/yyyy which is very large I do not see time or TEMPERATURE.
I’m using the same pcs but my OLED is only blue.
I can chage the day Monday etc and the dd/mm/yyyy.
I’m looking but cann’t find the answer ( i’m new to arduino)
Thanks for any help
i just neglecting the write to RTC code. just read and display mainly, since there was no delay(xxx) how the display update correctly in each second?
The DS3231 when powered it directly starts incrementing seconds which is then read and displayed by the Arduino.