This STM32 tutorial shows how to build a real time clock using STM32 Blue Pill board and DS3231 RTC module where time & date are printed on SSD1306 OLED display with 128×64 pixel resolution.
Two push buttons connected to the STM32 Blue Pill board used to set time and date.
To see how to interface the STM32 Blue Pill board with SSD1306 OLED display, go to this post:
Interface SSD1306 OLED Display with STM32 Blue Pill Board
Abbreviations:
OLED: Organic light Emitting Diode.
I2C: Inter-Integrated Circuit.
TWI: Tow Wire Interface.
SPI: Serial Peripheral Interface.
IoT: Internet of things.
RTC: Real Time Clock.
The DS3231 RTC Module:
The DS3231 is an extremely accurate real time clock (RTC) chip provides timekeeping in hours, minutes, and seconds, as well as day, month, and year. The high accuracy of the DS3231 RTC is maintained by a built-in temperature-compensated crystal oscillator (TCXO).
Benefits and Features of the DS3231 Module:
Here are some key features of the DS3231 RTC module.
- High Accuracy: The integrated temperature-compensated crystal oscillator (TCXO) reduces time drift, achieving an accuracy of ±2ppm from 0°C to +40°C, and ±3.5ppm from -40°C to +85°C.
- I²C Communication: Communicates with master device (microcontrollers, development boards …) via the I²C (TWI) serial interface protocol with support of Fast (400kHz) I2C Interface.
- Timekeeping Registers: Real time clock counts Seconds, Minutes, Hours, Day of the Week, Date of the Month, Month, and Year with automatic Leap-Year compensation valid up to 2100.
- Battery Backup: Includes a slot for a CR2032 coin cell battery for continuous timekeeping during power outages.
- Alarm Functionality: Supports two programmable alarms with interrupt signal output.
- Built-in Temperature Sensor: Measures chip temperature with an accuracy of ±3°C and a resolution of 0.25°C.
- Square Wave Output: Provides a programmable square wave output signal.
- EEPROM (Commonly AT24C32 or AT24C64): The DS3231 RTC module with an integrated EEPROM adds non-volatile storage to the already powerful real-time clock functionalities of the DS3231 chip with 4kB or 8kB memory capacity. It communicates also via I²C and shares the SDA and SCL lines with the RTC chip.
The DS3231 RTC module used in this project is the one shown below:
DS3231 RTC Module Pinout:
Generally, the DS3231 RTC module comes with a set of pins, depending on the module, for connecting to master device. Below is a detailed description of each pin.
- 32K: Outputs a clock signal with frequency of 32.768 kHz clock signal, it’s an open drain output and requires a pull-up resistor.
- INT/SQW: This pin provides an active-low interrupt signal or square wave with programmable frequency of 1 Hz, 4 kHz, 8 kHz, or 32 kHz. This pin is an open drain output and requires a pull-up resistor.
- SCL: Serial Clock Line for the I²C communication. Connected to the SCL pin of the master device.
- SDA: Serial Data Line for the I²C communication. Connected to the SDA pin of the master device.
- VCC: Power supply for the module. Typically connected to +3.3V to +5V.
- GND: Ground pin of the module. Connected to circuit ground (0V).
The DS3231 RTC board uses I2C interface for the communication with the microcontroller. The default I2C address for the DS3231 chip is 0x68 (7-bit address).
The integrated EEPROM chip has a configurable I2C address with a default address of 0x57.
The three jumpers A0, A1, and A2 are used to change the I2C address of the EEPROM from the default one according to the following combination (The R/W bit not shown):
1 | 0 | 1 | 0 | A2 | A1 | A0 |
For example, if the three jumpers left open then the I2C address is 0x57 (default). If the three jumpers are closed then the I2C address becomes 0x50. Closing any jumper changes its state from 1 to 0.
Interfacing DS3231 Precision RTC Module with STM32 Blue Pill Board:
The circuit schematic diagram below shows the wiring of the STM32 board with DS3231 RTC module and SSD1306 OLED display.
The SSD1306 OLED is configured to work in I2C mode and it shares the same I2C bus with the DS3231 RTC.
In this project hardware I2C2 (2nd hardware module) interface is used with SDA line mapped at pin PB11 and SCL line mapped at pin PB10. Both the DS3231 RTC chip and the SSD1306 OLED display are slave devices, whereas the STM32 Blue Pill microcontroller, STM32F103C8T6, is the master device.
The good thing in this circuit is that there are two push buttons, Button1 and Button2, used to set time & date of the real time clock. These push buttons are respectively connected to the STM32 Blue Pill board pins B4 and B5.
Hardware Required:
This is a summary of the parts required to build this project.
- STM32 Blue Pill board —> STM32F103C8T6 32-bit Arm Cortex-M3 MCU datasheet
- DS3231 RTC module —> DS3231 datasheet
- SSD1306 OLED display module
- 2 x Push button
- Bread board & Jumper wires
- STM32 Microcontroller programmer (ST-Link, USB-to-Serial converter…)
Interfacing DS3231 Precision RTC Module with STM32 Blue Pill Board Code:
Arduino IDE (Integrated Development Environment) is used to write project code, the STM32 Blue Pill board has to be added to the IDE before compiling the code.
The STM32 Blue Pill board can be installed using Arduino IDE Boards Manager.
Programming the STM32F103C8T6 microcontroller is done with the FT232RL USB to serial UART converter, Arduino IDE supports the ST-LINK V2 programmer as well.
To be able to compile project Arduino code, three libraries from Adafruit Industries are required:
The first library is a driver for the SSD1306 OLED display and it can be installed from Arduino IDE library manager (Sketch —> Include Library —> Manage Libraries…, in the search box write “ssd1306” and install the one published by Adafruit).
The second library is Adafruit graphics library which can be installed from Arduino IDE library manager.
The last library is Adafruit RTC library and it is a library for the DS3231 RTC. It can be installed also from Arduino IDE library manager.
During the installation of any of the mentioned libraries, Arduino IDE may ask for installing some other libraries form Adafruit Industries (dependencies).
Project code was tested with the following library versions:
Adafruit GFX Library: Version 1.11.11.
Adafruit SSD1306 OLED Display Library: Version 2.5.13.
Adafruit RTC Library: Version 2.1.4.
Adafruit BusIO: Version 1.17.0.
Programming Hints:
The used libraries are included in the Arduino code as shown below:
1 2 3 4 | #include <Wire.h> // Include Wire library (required for I2C) #include <Adafruit_GFX.h> // Include Adafruit graphics library #include <Adafruit_SSD1306.h> // Include Adafruit SSD1306 display library #include "RTClib.h" // Include Adafruit RTC library |
I2C2 Hardware peripheral is used for I2C protocol communication and it is initialized in the software as shown below:
1 2 | // Use I2C2 hardware module, SCL & SDA pins respectively at PB10 & PB11 TwoWire Wire2(2, I2C_FAST_MODE); |
The SSD1306 OLED display library is initialized as shown below. The display is connected to the previously initialized I2C (Wire) interface with address of 0x3C, if the display does not work then try with slave address 0x3D.
-1 Is passed as there is no reset line connected between the display and the microcontroller.
1 2 3 | // Declaration for an SSD1306 display connected to I2C2 (Wire2) #define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D, or 0x3C Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire2, -1); |
Screen width and height is previously defined in the code as 128 and 64, respectively.
The push buttons which are used to set time & date of the real time clock, they’re connected to the STM32 Blue Pill board B4 and B5 and are defined in the code as:
1 2 3 | // Setting buttons definition #define Button1 PB4 #define Button2 PB5 |
These push buttons are configured as inputs with internal pull-up enabled so that no external pull-up resistors are required.
Rest of code is described through comments.
Project Arduino Code:
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 | /****************************************************************************** * Interfacing STM32 Blue Pill board with DS3231 Real Time Clock (RTC) module * and SSD1306 OLED monochrome display. * The SSD1306 OLED is configured to work in I2C mode with address 0x3C (0x78). * Time & Date can be set with two push buttons connected to pins PB4 & PB5. * This is a free software with NO WARRANTY. * https://simple-circuit.com/ /*******************************************************************************/ #include <Wire.h> // Include Wire library (required for I2C) #include <Adafruit_GFX.h> // Include Adafruit graphics library #include <Adafruit_SSD1306.h> // Include Adafruit SSD1306 display library #include "RTClib.h" // Include Adafruit RTC library #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Use I2C2 hardware module, SCL & SDA pins respectively at PB10 & PB11 TwoWire Wire2(2, I2C_FAST_MODE); // Declaration for an SSD1306 display connected to I2C2 (Wire2) #define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D, or 0x3C Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire2, -1); // Initialize RTC library RTC_DS3231 rtc; DateTime now; // Setting buttons definition #define Button1 PB4 #define Button2 PB5 void setup() { Serial1.begin(9600); delay(1000); // Pause for 1 second pinMode(Button1, INPUT_PULLUP); pinMode(Button2, INPUT_PULLUP); // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS); rtc.begin(&Wire2); // Initialize RTC chip with hardware I2C2 module, SCL & SDA pins respectively at PB10 & PB11 display.clearDisplay(); // Clear the display buffer display.setTextColor(WHITE, BLACK); display.setTextSize(1); display.drawRect(117, 56, 3, 3, WHITE); // Print degree symbol ( ° ) display.setCursor(0, 56); display.print("TEMPERATURE ="); display.setCursor(122, 56); display.print("C"); display.display(); // Update the screen } char Time[] = "HH:MM:SS"; char Date[11] = "DD-MM-YYYY"; char Temperature[] = "00.00"; char dow_matrix[7][10] = {"SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"}; uint8_t dow_Xpos[7] = {29, 29, 23, 11, 17, 29, 17}; // a small function for button1 (B1) debounce bool debounce () { byte count = 0; for(byte i = 0; i < 5; i++) { if ( !digitalRead(Button1) ) count++; delay(10); } if(count > 2) return true; else return false; } uint8_t RTC_Set(uint8_t p) { char txt[3]; static uint8_t i = 0; uint8_t y_pos, x_pos[5] = {18, 54, 4, 40, 100}; if(i < 2) y_pos = 19; else y_pos = 38; while( debounce() ); // call debounce function (wait for B1 to be released) while(true) { while( !digitalRead(Button2) ) { // while B2 is pressed p++; if(i == 0 && p > 23) // if day > 31 ==> day = 1 p = 0; if(i == 1 && p > 59) // if month > 12 ==> month = 1 p = 0; if(i == 2 && p > 31) // if year > 99 ==> year = 0 p = 1; if(i == 3 && p > 12) // if hours > 23 ==> hours = 0 p = 1; if(i == 4 && p > 99) // if minutes > 59 ==> minutes = 0 p = 0; sprintf( txt, "%02u", p ); display.setCursor(x_pos[i], y_pos); display.print(txt); display.display(); // update the screen delay(200); // wait 200ms } display.fillRect(x_pos[i], y_pos, 22, 16, BLACK); display.display(); // update the screen uint32_t previous_m = millis(); while( (millis() - previous_m < 250) && digitalRead(Button1) && digitalRead(Button2)) ; sprintf( txt, "%02u", p ); display.setCursor(x_pos[i], y_pos); display.print(txt); display.display(); // update the screen previous_m = millis(); while( (millis() - previous_m < 250) && digitalRead(Button1) && digitalRead(Button2)) ; if( !digitalRead(Button1) ) { // if button B1 is pressed i = (i + 1) % 5; // increment 'i' for the next parameter return p; // return parameter value and exit } } } // Main loop function void loop() { if( !digitalRead(Button1) ) // if B1 button is pressed if( debounce() ) // call debounce function (make sure that B1 is pressed) { while( debounce() ); // call debounce function (wait for B1 to be released) display.setTextSize(2); uint8_t hour = RTC_Set( now.hour() ); // edit hours uint8_t minute = RTC_Set( now.minute() ); // edit minutes uint8_t day = RTC_Set( now.day() ); // edit date uint8_t month = RTC_Set( now.month() ); // edit month uint8_t year = RTC_Set( (uint8_t)(now.year() - 2000U) ); // edit year // write time & date data to the RTC chip rtc.adjust(DateTime(2000U + year, month, day, hour, minute, 0)); while(debounce()); // call debounce function (wait for button B1 to be released) } // Read current time and date from the RTC chip now = rtc.now(); // Print day of the week display.setTextSize(2); static uint8_t previous_dow = 7; if( previous_dow != now.dayOfTheWeek() ) { previous_dow = now.dayOfTheWeek(); display.fillRect(0, 0, SCREEN_WIDTH, 16, BLACK); display.setCursor(dow_Xpos[now.dayOfTheWeek()], 0); display.print( dow_matrix[now.dayOfTheWeek()] ); } // Update time array sprintf( Time, "%02u:%02u:%02u", now.hour(), now.minute(), now.second() ); // Update date array sprintf( Date, "%02u-%02u-%04u", now.day(), now.month(), now.year() ); // Print Time display.setCursor(18, 19); display.print(Time); // Print Date display.setCursor(4, 38); display.print(Date); // Print temperature, every 1 minute static uint8_t previous_min = 60; if( previous_min != now.minute() ) { previous_min = now.minute(); int16_t temp = rtc.getTemperature() * 100; // Update temperature array sprintf( Temperature, "%02u.%02u", temp/100, temp%100 ); display.setTextSize(1); display.setCursor(86, 56); display.print(Temperature); } // Update the display display.display(); delay(200); // Wait 200 ms } // End of code. // https://simple-circuit.com/ |
Interfacing DS3231 Precision RTC Module with STM32 Blue Pill Video:
The video below shows my protoboard circuit of the interfacing of the STM32 Blue Pill board with DS3231 RTC module and SSD1306 OLED display.
Discover more from Simple Circuit
Subscribe to get the latest posts sent to your email.