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.