DS3231_Driver.h

An example of a RTC driver based on the DS3231 RTC chip. The idea behind the driver is to replicate the chips register structure in part of the micro controller RAM memory in the form of a struct.

/*
Name		:	DS3231RTC_driver.ino
Created		:	14-Jan-19 20:46:08
Author		:	Oscar Goos
Code		:	C++, Flash: 3944B, RAM: 413B
Controller	:	ATmega328
Last tested	:	14-Jan-2019
Notes		:   Only Read Write Time and date registers implemented
.			:	Copy DS3231 to RTC and the other way around could be done with a memcopy
.			:	YinC must be uint16_t for both data sets
.			:	Temperature not implemented
*/
#include "ds3231_driver.h"
RTC_t*	RTC;
RTC_t	Timebuf={ 27, 20, 10, 6, 11, 12, 2019, 0 };
DS3231	clock;

void setup(void)
{
Serial.begin(115200);
Wire.begin();
//	RTC1.RTC = Timebuf;
//	RTC1.Driver(INIT);
delay(100);
clock.Driver(SYNC);
}

void loop(void)
{
RTC1.Driver(SYNC);
Serial.print(clock.RTC.sec); Serial.print("\t"), Serial.println(clock.RTC.SinD);
delay(1000);

}

Here the C++ code of the library to be included in the code. It is the smallest and the simplest I have seen so far. The functions are called based on one class member with the name “Driver” and a command parameters tells the driver what to do. Three commands are implemented

Sync: Copy time and date DS3231 registers to controller ram.
INIT: Copy the RAM image to the DS3231 registers.
TMDT2STR: Convert the RAM time and date registers to a time and date c-string.

#ifndef		DS3231_H
#define		DS3231_H

#include	"wire.h"

#define		INIT					0
#define		SYNC					1
#define		TMDT2STR				2

#define		I2C_DS3231_ADR 			0x68
#define		STOP					true

#define		BCD2DEC(bcdval)			(((bcd_val>>4)*10) + (bcd_val & 0x0F))
#define		DEC2BCD(decval)			(((dec_val/10)<<4) + (dec_val%10))

typedef struct RTC_t {
uint8_t						id;		// Struct identifier for future use
uint8_t						sec;	// seconds,			00..59
uint8_t						min;	// minuts,			00..59
uint8_t						hr;		// hours,			00..23
uint8_t						DinW;	// Day in week,		01..07
uint8_t						DinM;	// Day in month,	01..31
uint8_t						MinY;	// Month in year,	01..12
uint16_t					year;	// Year				2000..2100
uint32_t					SinD;	// seconds in day,	00..86399
uint32_t					epoch;	// epoch time in sec since 1/1/1970
int16_t						error;	// Time error in usec/sec
char						tmstr[9] ="00:00:00";	// buffer for time string
char						dtstr[11]="00/00/0000";	// buffer for date string
} RTC_t;

class DS3231 {

typedef struct reg {
uint8_t						sec;	// seconds,			00..59
uint8_t						min;	// minuts,			00..59
uint8_t						hr;		// hours,			00..23
uint8_t						DinW;	// Day in week,		01..07
uint8_t						DinM;	// Day in month,	01..31
uint8_t						MinY;	// Month in year,	01..12
uint8_t						YinC;	// Year in century,	00..99 respresenting 2000..2099)
}__attribute__((packed, aligned(1))) reg_t;

public:
DS3231();
RTC_t	RTC;
void	Driver (uint8_t);

private:
reg_t	DSreg;

protected:
};

DS3231::DS3231() {
}

void DS3231::Driver(uint8_t cmd) {

uint8_t		n, bcd_val, dec_val;
uint8_t*	DSptr = (uint8_t*)&DSreg;
String		TDstr;

switch (cmd) {
case INIT: {
DSreg.sec	= RTC.sec;
DSreg.min	= RTC.min;
DSreg.hr	= RTC.hr;
DSreg.DinM	= RTC.DinM;
DSreg.MinY	= RTC.MinY;
DSreg.YinC	= RTC.year - 2000;
DSreg.DinW	= RTC.DinW;
RTC.SinD	= (uint32_t)RTC.hr * 3600 + (uint32_t)RTC.min * 60 + (uint32_t)RTC.sec;
Wire.beginTransmission(I2C_DS3231_ADR);						// Start I2C and send Address
Wire.write(0);													// set DS3231 register pointer to 0
for (n = 0; n < sizeof(DSreg); n++) {
dec_val = *DSptr++;											// Read nth data element from DS3231
Wire.write(DEC2BCD(dec_val));								// Convert nth element dec2bcd and set all 7 RTC  Time date registers
}
Wire.endTransmission();											// Send I2C STOP and release the bus
} break;

case SYNC: {
Wire.beginTransmission(I2C_DS3231_ADR);							// Start I2C and send Address
Wire.write(0);													// set RTC  register address pointer to 0
Wire.endTransmission();
Wire.requestFrom((uint8_t)I2C_DS3231_ADR, (uint8_t)sizeof(DSreg),(uint8_t)STOP);
for (n = 0; n < sizeof(DSreg); n++) {
bcd_val = Wire.read();
*DSptr++ = BCD2DEC(bcd_val);									// Read all 7 RTC  registers, convert bcd2dec in
}
RTC.sec		= DSreg.sec;
RTC.min		= DSreg.min;
RTC.hr		= DSreg.hr;
RTC.DinM	= DSreg.DinM;
RTC.MinY	= DSreg.MinY;
RTC.year	= DSreg.YinC + 2000;
RTC.DinW	= DSreg.DinW;
RTC.SinD = (uint32_t)RTC.hr * 3600 + (uint32_t)RTC.min * 60 + (uint32_t)RTC.sec;
DS3231::Driver(TMDT2STR);
} break;

case TMDT2STR: {
TDstr = "";
if (RTC.hr <= 9) TDstr += F("0");
TDstr += String(RTC.hr);
TDstr += F(":");
if (RTC.min <= 9) TDstr += F("0");
TDstr += String(RTC.min);
TDstr += F(":");
if (RTC.sec <= 9) TDstr += F("0");
TDstr += String(RTC.sec);
//		tmstr=(char*)TDstr.c_str();
strcpy(RTC.tmstr, TDstr.c_str());

TDstr = "";
if (RTC.DinM <= 9) TDstr += F("0");
TDstr += String(RTC.DinM);
TDstr += F("/");
if (RTC.MinY <= 9) TDstr += F("0");
TDstr += String(RTC.MinY);
TDstr += F("/");
if (RTC.year <= 9) TDstr += F("0");
TDstr += String(RTC.year-2000);
//		dTDstr= (char*)TDstr.c_str();
strcpy(RTC.dtstr, TDstr.c_str());
} break;

}

}
#endif // !DS3231_H

Code is free for use.