ds3231.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. #include "mbed.h"
  2. #include "main.h"
  3. #include "ds3231.h"
  4. InterruptIn IO_Rtc(PB_5);
  5. #define BCDToDecimal(x) (((x >> 4) * 10) + (x & 0xF))
  6. #define DecimalToBCD(x) (((x / 10) << 4) | (x % 10))
  7. void DS3231_Init(void (*Callback)()) {
  8. DS3231_REGS regs = {0};
  9. regs.Control_1.nEOSC = 0; // Enable internal oscillator on VBAT
  10. regs.Control_1.BBSQW = 0; // Disable outputs on VBAT
  11. regs.Control_1.RS1 = 0; // Set square wave output to 1Hz
  12. regs.Control_1.RS2 = 0; // Set square wave output tp 1Hz
  13. regs.Control_1.INTCN = 0; // Enable square wave output
  14. regs.Control_1.A1IE = 0; // Disable alarm 1
  15. regs.Control_1.A2IE = 0; // Disable alarm 2
  16. regs.Control_2.EN32KHZ = 0; // Disable 32kHz output
  17. I2C_Write(DS3231_ADDR, FIELD_OFFSET(DS3231_REGS, Control_1),
  18. regs.AS_BYTE + FIELD_OFFSET(DS3231_REGS, Control_1),
  19. FIELD_SIZE_THROUGH(DS3231_REGS, Control_1, Control_2));
  20. IO_Rtc.rise(Callback);
  21. }
  22. void DS3231_SetTime(int Second, int Minute, int Hour) {
  23. DS3231_REGS regs = {0};
  24. regs.Second.Value = DecimalToBCD(Second);
  25. regs.Minute.Value = DecimalToBCD(Minute);
  26. regs.Hour.Value = DecimalToBCD(Hour);
  27. regs.Hour.n24 = 0;
  28. I2C_Write(DS3231_ADDR, FIELD_OFFSET(DS3231_REGS, Second),
  29. regs.AS_BYTE + FIELD_OFFSET(DS3231_REGS, Second),
  30. FIELD_SIZE_THROUGH(DS3231_REGS, Second, Hour));
  31. }
  32. void DS3231_SetDate(int Day, int Date, int Month, int Year, int Century) {
  33. DS3231_REGS regs = {0};
  34. regs.DayOfWeek.Value = DecimalToBCD(Day);
  35. regs.Day.Value = DecimalToBCD(Date);
  36. regs.Month.Value = DecimalToBCD(Month);
  37. regs.Month.Century = DecimalToBCD(Century);
  38. regs.Year.Value = DecimalToBCD(Year);
  39. I2C_Write(DS3231_ADDR, FIELD_OFFSET(DS3231_REGS, Day),
  40. regs.AS_BYTE + FIELD_OFFSET(DS3231_REGS, Day),
  41. FIELD_SIZE_THROUGH(DS3231_REGS, Day, Year));
  42. }
  43. void DS3231_GetTime(int *Second, int *Minute, int *Hour) {
  44. DS3231_REGS regs = {0};
  45. I2C_Read(DS3231_ADDR, FIELD_OFFSET(DS3231_REGS, Second),
  46. regs.AS_BYTE + FIELD_OFFSET(DS3231_REGS, Second),
  47. FIELD_SIZE_THROUGH(DS3231_REGS, Second, Hour));
  48. *Second = BCDToDecimal(regs.Second.Value);
  49. *Minute = BCDToDecimal(regs.Minute.Value);
  50. *Hour = BCDToDecimal(regs.Hour.Value);
  51. }
  52. void DS3231_GetDate(int *Day, int *Date, int *Month, int *Year) {
  53. DS3231_REGS regs = {0};
  54. I2C_Read(DS3231_ADDR, FIELD_OFFSET(DS3231_REGS, Day),
  55. regs.AS_BYTE + FIELD_OFFSET(DS3231_REGS, Day),
  56. FIELD_SIZE_THROUGH(DS3231_REGS, Day, Year));
  57. *Day = BCDToDecimal(regs.DayOfWeek.Value);
  58. *Date = BCDToDecimal(regs.Day.Value);
  59. *Month = BCDToDecimal(regs.Month.Value);
  60. *Year = BCDToDecimal(regs.Year.Value);
  61. }
  62. bool IsDst(int DayOfWeek, int Day, int Month, int Hour_24) {
  63. // December through Feburary are always outside DST
  64. if (Month < 3 || Month > 11) return false;
  65. // April through October are always in DST
  66. if (Month > 3 && Month < 11) return true;
  67. // Compute the last sunday, given that DoW enum starts at 1
  68. int prevSunday = Day - DayOfWeek + 1;
  69. // In March, in DST if previous sunday is between 8th and 14th
  70. if (Month == 3) {
  71. if (prevSunday < 8) return false;
  72. if (prevSunday > 14) return true;
  73. return (Day == prevSunday) ? Hour_24 >= 2 : true;
  74. }
  75. // In November, in DST if before the first Sunday
  76. if (prevSunday <= 0) return true;
  77. return (prevSunday == Day && Day <= 7) ? (Hour_24 < 2) : false;
  78. }