#include "mbed.h" #include "main.h" #include "ds3231.h" InterruptIn IO_Rtc(PB_5); #define BCDToDecimal(x) (((x >> 4) * 10) + (x & 0xF)) #define DecimalToBCD(x) (((x / 10) << 4) | (x % 10)) void DS3231_Init(void (*Callback)()) { DS3231_REGS regs = {0}; regs.Control_1.nEOSC = 0; // Enable internal oscillator on VBAT regs.Control_1.BBSQW = 0; // Disable outputs on VBAT regs.Control_1.RS1 = 0; // Set square wave output to 1Hz regs.Control_1.RS2 = 0; // Set square wave output tp 1Hz regs.Control_1.INTCN = 0; // Enable square wave output regs.Control_1.A1IE = 0; // Disable alarm 1 regs.Control_1.A2IE = 0; // Disable alarm 2 regs.Control_2.EN32KHZ = 0; // Disable 32kHz output I2C_Write(DS3231_ADDR, FIELD_OFFSET(DS3231_REGS, Control_1), regs.AS_BYTE + FIELD_OFFSET(DS3231_REGS, Control_1), FIELD_SIZE_THROUGH(DS3231_REGS, Control_1, Control_2)); IO_Rtc.rise(Callback); } void DS3231_SetTime(int Second, int Minute, int Hour) { DS3231_REGS regs = {0}; regs.Second.Value = DecimalToBCD(Second); regs.Minute.Value = DecimalToBCD(Minute); regs.Hour.Value = DecimalToBCD(Hour); regs.Hour.n24 = 0; I2C_Write(DS3231_ADDR, FIELD_OFFSET(DS3231_REGS, Second), regs.AS_BYTE + FIELD_OFFSET(DS3231_REGS, Second), FIELD_SIZE_THROUGH(DS3231_REGS, Second, Hour)); } void DS3231_SetDate(int Day, int Date, int Month, int Year, int Century) { DS3231_REGS regs = {0}; regs.DayOfWeek.Value = DecimalToBCD(Day); regs.Day.Value = DecimalToBCD(Date); regs.Month.Value = DecimalToBCD(Month); regs.Month.Century = DecimalToBCD(Century); regs.Year.Value = DecimalToBCD(Year); I2C_Write(DS3231_ADDR, FIELD_OFFSET(DS3231_REGS, Day), regs.AS_BYTE + FIELD_OFFSET(DS3231_REGS, Day), FIELD_SIZE_THROUGH(DS3231_REGS, Day, Year)); } void DS3231_GetTime(int *Second, int *Minute, int *Hour) { DS3231_REGS regs = {0}; I2C_Read(DS3231_ADDR, FIELD_OFFSET(DS3231_REGS, Second), regs.AS_BYTE + FIELD_OFFSET(DS3231_REGS, Second), FIELD_SIZE_THROUGH(DS3231_REGS, Second, Hour)); *Second = BCDToDecimal(regs.Second.Value); *Minute = BCDToDecimal(regs.Minute.Value); *Hour = BCDToDecimal(regs.Hour.Value); } void DS3231_GetDate(int *Day, int *Date, int *Month, int *Year) { DS3231_REGS regs = {0}; I2C_Read(DS3231_ADDR, FIELD_OFFSET(DS3231_REGS, Day), regs.AS_BYTE + FIELD_OFFSET(DS3231_REGS, Day), FIELD_SIZE_THROUGH(DS3231_REGS, Day, Year)); *Day = BCDToDecimal(regs.DayOfWeek.Value); *Date = BCDToDecimal(regs.Day.Value); *Month = BCDToDecimal(regs.Month.Value); *Year = BCDToDecimal(regs.Year.Value); } bool IsDst(int DayOfWeek, int Day, int Month, int Hour_24) { // December through Feburary are always outside DST if (Month < 3 || Month > 11) return false; // April through October are always in DST if (Month > 3 && Month < 11) return true; // Compute the last sunday, given that DoW enum starts at 1 int prevSunday = Day - DayOfWeek + 1; // In March, in DST if previous sunday is between 8th and 14th if (Month == 3) { if (prevSunday < 8) return false; if (prevSunday > 14) return true; return (Day == prevSunday) ? Hour_24 >= 2 : true; } // In November, in DST if before the first Sunday if (prevSunday <= 0) return true; return (prevSunday == Day && Day <= 7) ? (Hour_24 < 2) : false; }