DS3231 Precisie RTC Module gebruiken met Arduino
We weten allemaal dat de meeste microcontrollers die wij binnen onze projecten gebruiken geen idee hebben van de tijd om zich heen. Met andere woorden, ze hebben geen referentie met de buitenwereld. Dat is voor de meeste projecten geen probleem, maar zo af en toe heb je toch een referentietijd nodig voor bijvoorbeeld het loggen van data, timestamps bijhouden, timers, alarmen en alle tijdsgerelateerde toepassingen die je verder nog kunt bedenken. De DS3231 RTC (Real Time Clock) module is hiervoor uitermate geschikt.
DS3231 RTC chip
Het hart van deze module is de low-cost, maar zéér accurate RTC chip van Maxim, namelijk de DS3231. Alle functies wat betreft het bijhouden van de tijd, genereren van alarmem e.d. kunnen via het I2C (two-wire) protocol aangesproken worden. Hierdoor kun je de DS3231 gebruiken met vrijwel elke microcontroller.
Het DS3231 IC houdt de huidige tijd bij van secondes, minuten, uren, dag, maand en jaar. Op het einde van de maand past het IC ook de dag aan bij maanden die minder dag 31 dagen tellen. Ook zit er een correctie in voor schrikkeljaren tot het jaar 2100.
Voor het tijdsformaat kun je kiezen uit het 24- of 12-uurs formaat met een AM/PM indicator. Ook kun je 2 alarmen programmeren die op een bepaalde dag en tijdsstip af kunnen gaan. Op die manier zou je bijvoorbeeld de Arduino elk uur (of elke dag) een seintje kunnen geven om deze uit slaapstand te halen.
Daarnaast zit er nog een multifunctionele, SQW, pin op het IC die een hele mooie blokgolf kan genereren van 1Hz, 4kHz, 8kHz of 32kHz. Ook kan deze pin gebruikt worden als interrupt om een alarm te genereren die je vervolgens aan de interrupt van een microcontroller of Arduino koppelt.
De DS3231 is uiterst precies in het bijhouden van de tijd
De meeste RTC modules moeten worden uitgevoerd met een extern klokkristal van 32.768Hz voor het bijhouden van de tijd. Echter is het probleem bij deze kristallen dat ze gevoelig zijn voor schommelingen in de omgevingstemperatuur, waardoor de frequentie kan afwijken. Deze afwijkende frequentie is heel klein, maar over verloop van dagen of maanden kan dat oplopen tot een aanzienlijke afwijking.
Om de temperatuurschommelingen te compenseren gebruikt de DS3231 chip een temperatuur gecompenseerd (TCXO) 32kHz kristal. Hierdoor is de frequentiedrift nihil.
Door de temperatuur van het kristal te meten bepaald de DS3231 zelf hoeveel klokslagen er bij of afgehaald moeten worden. Op deze manier kan er een nauwkeurigheid worden behaald van 1-2 minuten per jaar!
Als bonus is dat je ook de temperatuur van het DS3231 IC kunt uitlezen via de I2C bus, waardoor je dus de omgevingstemperatuur van jouw project kunt meten zonder extra sensor.
DS3231 vs DS1302
Het verschil tussen de DS3231 en de goedkopere tegenhanger DS1302 is de nauwkeurigheid van het bijhouden van de tijd.
De DS1302 is uitgevoerd met een extern 32kHz kristal voor het bijhouden van de tijd, en is dus onderhevig aan veranderingen in de klokfrequentie op basis van schommelingen in de omgevingstemperatuur. Dit resulteert in een afwijking van 5 tot 10 minuten per jaar. Dit zou je kunnen oplossen door elke maand de RTC te kalibreren, bijvoorbeeld via WiFi of een ander transmissieprotocol.
Echter, de DS3231 is een stuk accurater, aangezien deze is uitgevoerd met een temperatuur gecompenseerd kristal. Hierdoor is deze stand-alone zeer goed in te zetten.
Samenvatting: de DS1302 is ook een prima RTC, maar als een hogere nauwkeurigheid over een langere periode gewenst is, dan raden wij de DS3231 module aan.
Backup batterij
De DS3231 module is ook voorzien van een backup batterij in het geval als de vaste spanning onderbroken wordt. Hierdoor blijft de DS3231 gewoon doortellen en raakt deze niet uit synchronisatie van de werkelijke tijd.

In de DS3231 chip zit een voltage sensor die continue de vaste spanning in de gaten houdt, en zodra de vaste spanning wegvalt zal de DS3231 direct overschakelen op de batterij. Er is dus geen reden om je zorgen te maken over het wegvallen van de spanning en dus ook tijdssynchronisatie.
De batterij van het type CR2032 (of LIR2032) kan aan de onderkant van de module in de batterijhouder geplaatst worden.
Batterijlevensduur DS3231
Als we er van uit gaan dat de volle CR2032 batterij een capaciteit heeft van 220mAh, en de DS3231 gebruikt 3µAh, dan kan de RTC module ruim 8 jaar blijven draaien zonder externe 5V voeding.
Extra EEPROM opslag op de DS3231 module
Op de DS3231 RTC module hebben wij ook nog een externe EEPROM geplaatst met een opslagruimte van 32kb (4K x 8bits), goed voor het opslaan van 4096 bytes! Een EEPROM geheugen verliest zijn opgeslagen data niet na het wegvallen van de spanning, dus hier zou je bijvoorbeeld instellingen in kunnen opslaan, een datalog bijhouden of heel iets anders op opslaan.
De EEPROM 24C32 van Atmel die wij op de RTC module gebruiken staat erom bekend dat de EEPROM cellen minimaal 1 miljoen (!) keer herschreven kunnen worden. Op het uitlezen staat geen limiet.
Het 24C32 EEPROM geheugen is op dezelfde I2C bus aangesloten als de DS3231 maar heeft een ander adres. Het adres van de 24C32 kan ook nog eens geconfigureerd worden middels 3 soldeer jumpers: A0, A1 en A2. Deze instelbare adresbit worden als volgt in het adres verwerkt:

24C32 EEPROM Adres configureren
Standaard zijn de adreslijnen van het EEPROM geheugen met de massa verbonden, waardoor het standaardadres 0x50HEX, of 1010000XBINAIR is.
Door de jumpers te solderen kan het EEPROM geheugen op een ander adres worden gezet lopend van 0x50 .. 0x57. Onderstaande tabel geeft aan welk adres er softwarematig gebruikt dient te worden bij de verschillende jumper instellingen.
Adres | 0x50 | 0x51 | 0x52 | 0x53 | 0x54 | 0x55 | 0x56 | 0x57 |
---|---|---|---|---|---|---|---|---|
A0 | ||||||||
A1 | ||||||||
A2 |
= Jumper open, niet gesoldeerd
= Jumper gesloten, gesoldeerd
DS3231 RTC Module pinout
In totaal heeft de RTC module 7 pinnen beschikbaar waarmee deze voorzien kan worden van spanning en communicatie. Deze zijn als volgt:

GND pin sluit je aan op de massa
VCC pin wordt gebruikt om de module te voeden met een spanning van 3.3V tot 5.5V.
BAT pin kan gebruikt worden om de module met een externe batterij te voeden. Op de achterkant van de module kan ook een batterij worden geplaatst, waardoor deze pin dus de batterijspanning is.
SDA pin is de data pin voor de I2C communicatie.
SCL pin is de seriële clock pin voor de I2C communicatie.
INT pin kan een mooie blokgolf van 1Hz, 4kHz, 8kHz of 32kHz genereren, óf kan gebruikt worden als alarm signaal voor tijdskritieke applicaties.
32K pin kan gebruikt worden als stabiele (temperatuur gecompenseerde) referentie kloksignaal.
PU is een soldeerjumper om de aanwezige I2C pull up weerstanden aan of uit te zetten.
ADDR zijn soldeerjumpers om het I2C adres van de 24C32 EEPROM te wijzigen.
De DS3231 RTC module verbinden met een Arduino Uno
Het aansluiten van de RTC module aan een Arduino is erg eenvoudig, en voor de basisfunctionaliteit zijn er slechts 4 draden nodig.
Sluit als eerste de VCC pin aan op de 5V van de Arduino, en de GND pin op de GND van de Arduino.
Nu dien je de twee I2C pinnen, SDA en SCL, aan te sluiten op de Arduino. Bij de Arduino Uno zit de SCL pin op A5, en de SDA pin op A4. Vaak staan de SCL en SDA pinnen ook op de printplaat van de Arduino Uno gedrukt. Heb je een andere Arduino bordje, raadpleeg dan onderstaande tabel.
SCL | SDA | |
---|---|---|
Arduino Uno | A5 | A4 |
Arduino Nano | A5 | A4 |
Arduino Mega | 21 | 20 |
Arduino Leonardo Arduino Micro | 3 | 2 |
De SCL pin van de RTC module gaat dus naar de SCL (A5) pin van de Arduino. En de SDA pin van de module gaat vanzelfsprekend naar de SDA (A4) pin van de Arduino.
Onderstaande afbeelding geeft aan hoe de RTC module nu op de Arduino Uno is aangesloten.

Installeren van de RTC Library voor de DS3231 module
Om te communiceren met de DS3231 RTC zou je de juiste commando’s uit de datasheet kunnen halen, maar een makkelijkere manier is door gebruik te maken van een goede Library voor Arduino. In de library zijn de functionaliteiten van de RTC ondergebracht is functies die je kunt aanspreken.
De library kun je hieronder downloaden en dien je in Arduino te installeren. Weet je niet hoe dat gaat? Lees hier hoe een library in Arduino installeren werkt.
Download Arduino Library <RTClib>
Arduino code voor de DS3231 RTC module
Nadat je de RTClib (zie bovenstaand) hebt geïnstalleerd kun je de code hieronder gebruiken om een eerste start te maken met de RTC.
Dit stukje software voor de DS3231 kijkt allereerst of de RTC aanwezig is op de I2C lijn. Daarna wordt er gecontroleerd of de batterijspanning is weggevallen. Als dat het geval is wordt de tijd op de RTC gelijk gesteld aan het moment dat de Arduino sketch is gecompiled.
Nadat de setup() is afgerond zal het programma in de loop() elke seconde de huidige tijd van de RTC uitlezen en weergeven in de Serial Monitor (9600 baud).
#include <Wire.h>
#include "RTClib.h"
RTC_DS3231 rtc;
// Representation of the day of the week instead of a number
// The week starts on sunday
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
void setup ()
{
Serial.begin(9600);
// Stop the Arduino if no RTC is found
if (!rtc.begin()) {
Serial.println("Couldn't find RTC. Program stopped.");
while (1);
}
// Load the current time into the RTC after a powerloss
if (rtc.lostPower()) {
Serial.println("RTC lost power, lets set the time!");
// If the Arduino is NOT connected to a PC, then comment out the line below
// Set the Date & Time to the time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// Following line sets the RTC with an explicit date & time
// for example to set January 27 2017 at 12:56 you would call:
// rtc.adjust(DateTime(2017, 1, 27, 12, 56, 0));
}
}
void loop ()
{
// Fetch the current time from the RTC
DateTime now = rtc.now();
// Print readable time
Serial.print("Current Date & Time: ");
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(" (");
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
Serial.print(") ");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
// Print UNIX Time
Serial.print("Current Unix Time: ");
Serial.print(now.unixtime());
Serial.print(" seconds");
Serial.println(" since 01/01/1970");
Serial.println();
delay(1000);
}
In de Serial Monitor van Arduino krijg je dan de volgende output te zien:

Arduino code voor het 24C32 EEPROM geheugen
-
#include <Wire.h>
#define EEPROM_ADDRESS 0x50 // Set your EEPROM address here
void setup()
{
char data[] = "Hello VDR Electronics!";
Wire.begin(); // Initialize I2C bus
Serial.begin(9600); // Initialize Serial bus for Serial Monitor
// Write the data to the first byte (0) in the EEPROM.
i2c_eeprom_write_page(EEPROM_ADDRESS, 0, (byte *)data, sizeof(data));
}
void loop()
{
Serial.print("Reading memory: ");
int addressByte = 0; // which byte from the EEPROM to access
// Read the first byte in the EEPROM
byte readByte = i2c_eeprom_read_byte(EEPROM_ADDRESS, addressByte);
// Keep reading the EEPROM until an empty cell (value = 0) is detected
while (readByte !=0)
{
Serial.print((char)readByte ); // Print the content of this cell
addressByte++; // increase addressByte by 1
readByte = i2c_eeprom_read_byte(EEPROM_ADDRESS, addressByte); // Read 1 byte from the memory
}
Serial.println(" ");
delay(3000);
}
// Write a single byte to the EEPROM
void i2c_eeprom_write_byte( int deviceAddress, unsigned int eeAddress, byte data ) {
int writeData = data;
Wire.beginTransmission(deviceAddress);
Wire.write((int)(eeAddress >> 8)); // MSB
Wire.write((int)(eeAddress & 0xFF)); // LSB
Wire.write(writeData);
Wire.endTransmission();
}
// Write a string to the EEPROM
void i2c_eeprom_write_page( int deviceAddress, unsigned int eeAddressPage, byte* data, byte length ) {
Wire.beginTransmission(deviceAddress);
Wire.write((int)(eeAddressPage >> 8)); // MSB
Wire.write((int)(eeAddressPage & 0xFF)); // LSB
for ( byte i = 0; i < length; i++)
Wire.write(data[i]);
Wire.endTransmission();
}
// Read a single byte from the EEPROM
byte i2c_eeprom_read_byte( int deviceAddress, unsigned int eeAddress ) {
byte readData = 0x00;
Wire.beginTransmission(deviceAddress);
Wire.write((int)(eeAddress >> 8)); // MSB
Wire.write((int)(eeAddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(deviceAddress,1);
if (Wire.available()) readData = Wire.read();
return readData;
}
In de Serial Monitor kun je dan de volgende output verwachten:

Real Time Clock (RTC) Modules in ons assortiment

