Simple RTC class based on DS1307. Emphasis on simple. Allows you to run at 100k or 400k Hz (for newer DS1307 capable devices). MapTime() allows you to set the time() service to the same as the RTC. Uses struct tm throughout so you can use traditional time functions for manipulation.

Dependents:   AdaFruit_RGBLCD

Committer:
vtraveller
Date:
Thu Oct 09 14:04:25 2014 +0000
Revision:
16:f7e4b4cbfb9e
Parent:
15:1645f55bd0ee
Child:
17:bdc15c054ac1
Fixed midnight bug.; Fixed minutes going beyond 59.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
vtraveller 0:98b84d9c8c96 1 #include "mbed.h"
vtraveller 0:98b84d9c8c96 2 #include "RTclock.h"
vtraveller 0:98b84d9c8c96 3
vtraveller 13:1ccadbd4c1bd 4 RTclock::RTclock(I2C & in_cI2C, uint8_t in_nAddress, EClockType in_eClockType)
vtraveller 10:e5eabd3a1ca6 5 : m_bTwelveHour(false)
vtraveller 10:e5eabd3a1ca6 6 , m_cI2C(in_cI2C)
vtraveller 13:1ccadbd4c1bd 7 , m_nAddress(in_nAddress)
vtraveller 9:3a0ba8364ef2 8 , m_eClockType(in_eClockType)
vtraveller 0:98b84d9c8c96 9 {
vtraveller 0:98b84d9c8c96 10 }
vtraveller 0:98b84d9c8c96 11
vtraveller 0:98b84d9c8c96 12 RTclock::~RTclock()
vtraveller 0:98b84d9c8c96 13 {
vtraveller 0:98b84d9c8c96 14 }
vtraveller 0:98b84d9c8c96 15
vtraveller 7:3621025e7949 16 int RTclock::bcdToDecimal(int in_nBCD)
vtraveller 0:98b84d9c8c96 17 {
vtraveller 0:98b84d9c8c96 18 return ((in_nBCD & 0xF0) >> 4) * 10 + (in_nBCD & 0x0F);
vtraveller 0:98b84d9c8c96 19 }
vtraveller 0:98b84d9c8c96 20
vtraveller 7:3621025e7949 21 int RTclock::decimalToBcd(int in_nDecimal)
vtraveller 0:98b84d9c8c96 22 {
vtraveller 0:98b84d9c8c96 23 return (in_nDecimal % 10) + ((in_nDecimal / 10) << 4);
vtraveller 0:98b84d9c8c96 24 }
vtraveller 0:98b84d9c8c96 25
vtraveller 7:3621025e7949 26 bool RTclock::getTime(tm & out_sTM)
vtraveller 0:98b84d9c8c96 27 {
vtraveller 0:98b84d9c8c96 28 char aBuffer[7];
vtraveller 0:98b84d9c8c96 29
vtraveller 0:98b84d9c8c96 30 if (!read(0, aBuffer, 7)) return false;
vtraveller 0:98b84d9c8c96 31
vtraveller 5:d71d6e5a7eee 32 m_bTwelveHour = ((aBuffer[2] & 0x40) == 0x40);
vtraveller 4:04a51e4dbf4c 33
vtraveller 7:3621025e7949 34 out_sTM.tm_sec = bcdToDecimal(aBuffer[0] & 0x7f);
vtraveller 7:3621025e7949 35 out_sTM.tm_min = bcdToDecimal(aBuffer[1]);
vtraveller 0:98b84d9c8c96 36
vtraveller 5:d71d6e5a7eee 37 if (m_bTwelveHour)
vtraveller 0:98b84d9c8c96 38 {
vtraveller 5:d71d6e5a7eee 39 // add 12 hours if PM bit is set and past midday
vtraveller 15:1645f55bd0ee 40 out_sTM.tm_hour = bcdToDecimal(aBuffer[2] & 0x1f);
vtraveller 5:d71d6e5a7eee 41
vtraveller 5:d71d6e5a7eee 42 bool bPM = (0 != (aBuffer[2] & 0x20));
vtraveller 5:d71d6e5a7eee 43 if (bPM && 12 != out_sTM.tm_hour) out_sTM.tm_hour += 12;
vtraveller 16:f7e4b4cbfb9e 44 if (!bPM && 12 == out_sTM.tm_hour) out_sTM.tm_hour = 0;
vtraveller 0:98b84d9c8c96 45 }
vtraveller 0:98b84d9c8c96 46 else
vtraveller 0:98b84d9c8c96 47 {
vtraveller 7:3621025e7949 48 out_sTM.tm_hour = bcdToDecimal(aBuffer[2] & 0x3f);
vtraveller 0:98b84d9c8c96 49 }
vtraveller 0:98b84d9c8c96 50
vtraveller 7:3621025e7949 51 out_sTM.tm_wday = aBuffer[3] % 7;
vtraveller 7:3621025e7949 52 out_sTM.tm_mday = bcdToDecimal(aBuffer[4]);
vtraveller 7:3621025e7949 53 out_sTM.tm_mon = bcdToDecimal(aBuffer[5]);
vtraveller 7:3621025e7949 54 out_sTM.tm_year = (bcdToDecimal(aBuffer[6]) + 2000) - 1900; // Returns from 2000, need form 1900 for time function
vtraveller 1:8952befe5d36 55 out_sTM.tm_isdst = 0;
vtraveller 0:98b84d9c8c96 56
vtraveller 0:98b84d9c8c96 57 return true;
vtraveller 0:98b84d9c8c96 58 }
vtraveller 0:98b84d9c8c96 59
vtraveller 7:3621025e7949 60 bool RTclock::isTwelveHour()
vtraveller 5:d71d6e5a7eee 61 {
vtraveller 5:d71d6e5a7eee 62 return m_bTwelveHour;
vtraveller 5:d71d6e5a7eee 63 }
vtraveller 5:d71d6e5a7eee 64
vtraveller 7:3621025e7949 65 bool RTclock::mapTime()
vtraveller 0:98b84d9c8c96 66 {
vtraveller 0:98b84d9c8c96 67 tm sTM;
vtraveller 7:3621025e7949 68 if (!getTime(sTM)) return false;
vtraveller 0:98b84d9c8c96 69
vtraveller 0:98b84d9c8c96 70 // Convert and set internal time
vtraveller 0:98b84d9c8c96 71 time_t nTime = ::mktime(&sTM);
vtraveller 0:98b84d9c8c96 72 ::set_time(nTime);
vtraveller 0:98b84d9c8c96 73
vtraveller 0:98b84d9c8c96 74 return true;
vtraveller 0:98b84d9c8c96 75 }
vtraveller 0:98b84d9c8c96 76
vtraveller 11:49b987f6ae26 77 bool RTclock::read(uint8_t in_nAddress, char * out_pBuffer, int in_nLength)
vtraveller 1:8952befe5d36 78 {
vtraveller 13:1ccadbd4c1bd 79 if (0 != m_cI2C.write(m_nAddress, (char *)&in_nAddress, 1)) return false;
vtraveller 13:1ccadbd4c1bd 80 if (0 != m_cI2C.read(m_nAddress, out_pBuffer, in_nLength)) return false;
vtraveller 1:8952befe5d36 81
vtraveller 1:8952befe5d36 82 return true;
vtraveller 1:8952befe5d36 83 }
vtraveller 1:8952befe5d36 84
vtraveller 7:3621025e7949 85 bool RTclock::setTime(const tm & in_sTM, bool in_bTwelveHour)
vtraveller 0:98b84d9c8c96 86 {
vtraveller 0:98b84d9c8c96 87 char aBuffer[7];
vtraveller 0:98b84d9c8c96 88
vtraveller 0:98b84d9c8c96 89 // Preserve flags that were in register
vtraveller 0:98b84d9c8c96 90 if (!read(0,aBuffer,7)) return false;
vtraveller 0:98b84d9c8c96 91
vtraveller 5:d71d6e5a7eee 92 m_bTwelveHour = in_bTwelveHour;
vtraveller 5:d71d6e5a7eee 93
vtraveller 5:d71d6e5a7eee 94 // We always have tm in 24hr form - so adjut if 12hr clock
vtraveller 5:d71d6e5a7eee 95 int nHour = in_sTM.tm_hour;
vtraveller 5:d71d6e5a7eee 96 if (in_bTwelveHour) nHour %= 12;
vtraveller 5:d71d6e5a7eee 97
vtraveller 9:3a0ba8364ef2 98 switch (m_eClockType)
vtraveller 5:d71d6e5a7eee 99 {
vtraveller 9:3a0ba8364ef2 100 case eDS1311:
vtraveller 9:3a0ba8364ef2 101 aBuffer[0] &= 0x7f;
vtraveller 9:3a0ba8364ef2 102 aBuffer[0] = (aBuffer[0] & 0x80) | (decimalToBcd(in_sTM.tm_sec)& 0x7f);
vtraveller 9:3a0ba8364ef2 103 aBuffer[1] = decimalToBcd(in_sTM.tm_min);
vtraveller 9:3a0ba8364ef2 104 aBuffer[2] = (aBuffer[2] & 0xc4) | (decimalToBcd(nHour) & 0x3f);
vtraveller 9:3a0ba8364ef2 105 aBuffer[3] = in_sTM.tm_wday;
vtraveller 9:3a0ba8364ef2 106 aBuffer[4] = decimalToBcd(in_sTM.tm_mday);
vtraveller 9:3a0ba8364ef2 107 aBuffer[5] = decimalToBcd(in_sTM.tm_mon);
vtraveller 9:3a0ba8364ef2 108 aBuffer[6] = decimalToBcd(in_sTM.tm_year + 1900 - 2000);
vtraveller 5:d71d6e5a7eee 109
vtraveller 9:3a0ba8364ef2 110 // Handle the 12hr clock bits
vtraveller 9:3a0ba8364ef2 111 if (in_bTwelveHour)
vtraveller 9:3a0ba8364ef2 112 {
vtraveller 9:3a0ba8364ef2 113 // Turn on 12hr clock
vtraveller 9:3a0ba8364ef2 114 aBuffer[2] |= 0x40;
vtraveller 9:3a0ba8364ef2 115
vtraveller 9:3a0ba8364ef2 116 // Set am/pm bit based on hours
vtraveller 9:3a0ba8364ef2 117 if (in_sTM.tm_hour >= 12) aBuffer[2] |= 0x20; else aBuffer[2] &= ~0x20;
vtraveller 9:3a0ba8364ef2 118 }
vtraveller 9:3a0ba8364ef2 119 else
vtraveller 9:3a0ba8364ef2 120 {
vtraveller 9:3a0ba8364ef2 121 aBuffer[2] &= ~64;
vtraveller 9:3a0ba8364ef2 122 }
vtraveller 9:3a0ba8364ef2 123 break;
vtraveller 9:3a0ba8364ef2 124
vtraveller 9:3a0ba8364ef2 125 case eDS3231:
vtraveller 9:3a0ba8364ef2 126 aBuffer[0] = decimalToBcd(in_sTM.tm_sec) & 0x7f;
vtraveller 9:3a0ba8364ef2 127 aBuffer[1] = decimalToBcd(in_sTM.tm_min) & 0x7f;
vtraveller 9:3a0ba8364ef2 128 aBuffer[2] = decimalToBcd(nHour) & (m_bTwelveHour ? 0x1f : 0x3f);
vtraveller 9:3a0ba8364ef2 129 aBuffer[3] = in_sTM.tm_wday;
vtraveller 9:3a0ba8364ef2 130 aBuffer[4] = decimalToBcd(in_sTM.tm_mday);
vtraveller 14:d5b47ff12d17 131 aBuffer[5] = decimalToBcd(in_sTM.tm_mon) & ~0x80 /* 2000+ */;
vtraveller 9:3a0ba8364ef2 132 aBuffer[6] = decimalToBcd(in_sTM.tm_year + 1900 - 2000);
vtraveller 9:3a0ba8364ef2 133
vtraveller 9:3a0ba8364ef2 134 // Handle the 12hr clock bits
vtraveller 9:3a0ba8364ef2 135 if (in_bTwelveHour)
vtraveller 9:3a0ba8364ef2 136 {
vtraveller 9:3a0ba8364ef2 137 // Turn on 12hr clock
vtraveller 9:3a0ba8364ef2 138 aBuffer[2] |= 0x40;
vtraveller 9:3a0ba8364ef2 139
vtraveller 9:3a0ba8364ef2 140 // Set am/pm bit based on hours
vtraveller 9:3a0ba8364ef2 141 if (in_sTM.tm_hour >= 12) aBuffer[2] |= 0x20;
vtraveller 9:3a0ba8364ef2 142 }
vtraveller 9:3a0ba8364ef2 143 break;
vtraveller 9:3a0ba8364ef2 144 }
vtraveller 5:d71d6e5a7eee 145
vtraveller 0:98b84d9c8c96 146 // Write new date and time
vtraveller 7:3621025e7949 147 setRunning(false);
vtraveller 0:98b84d9c8c96 148
vtraveller 0:98b84d9c8c96 149 bool bSuccess = write(0, aBuffer, 7);
vtraveller 0:98b84d9c8c96 150
vtraveller 7:3621025e7949 151 if (bSuccess) setRunning(true);
vtraveller 0:98b84d9c8c96 152
vtraveller 0:98b84d9c8c96 153 return bSuccess;
vtraveller 0:98b84d9c8c96 154 }
vtraveller 0:98b84d9c8c96 155
vtraveller 7:3621025e7949 156 bool RTclock::setRunning(bool in_bEnable)
vtraveller 0:98b84d9c8c96 157 {
vtraveller 0:98b84d9c8c96 158 char nRunning;
vtraveller 0:98b84d9c8c96 159
vtraveller 0:98b84d9c8c96 160 if (!read(0, &nRunning, 1)) return false;
vtraveller 0:98b84d9c8c96 161
vtraveller 0:98b84d9c8c96 162 // Set running
vtraveller 0:98b84d9c8c96 163 if (in_bEnable)
vtraveller 0:98b84d9c8c96 164 {
vtraveller 0:98b84d9c8c96 165 nRunning &= 0x7F;
vtraveller 0:98b84d9c8c96 166 }
vtraveller 0:98b84d9c8c96 167 else
vtraveller 0:98b84d9c8c96 168 {
vtraveller 0:98b84d9c8c96 169 nRunning |= 0x80;
vtraveller 0:98b84d9c8c96 170 }
vtraveller 0:98b84d9c8c96 171
vtraveller 0:98b84d9c8c96 172 return write(0, &nRunning, 1);
vtraveller 0:98b84d9c8c96 173 }
vtraveller 0:98b84d9c8c96 174
vtraveller 7:3621025e7949 175 bool RTclock::setSquareWaveOutput
vtraveller 0:98b84d9c8c96 176 (
vtraveller 0:98b84d9c8c96 177 bool in_bEnable,
vtraveller 0:98b84d9c8c96 178 ESquareWaveRates in_nRateSelect
vtraveller 0:98b84d9c8c96 179 )
vtraveller 0:98b84d9c8c96 180 {
vtraveller 0:98b84d9c8c96 181 char nValue;
vtraveller 0:98b84d9c8c96 182
vtraveller 0:98b84d9c8c96 183 // Read register
vtraveller 0:98b84d9c8c96 184 if (!read(7, &nValue, 1)) return false;
vtraveller 0:98b84d9c8c96 185
vtraveller 0:98b84d9c8c96 186 // Protect control bits
vtraveller 0:98b84d9c8c96 187 nValue = (nValue & 0x80) | (in_bEnable ? 0x10 : 0) | ((char)in_nRateSelect & 0x03);
vtraveller 0:98b84d9c8c96 188
vtraveller 0:98b84d9c8c96 189 return write(7, &nValue, 1);
vtraveller 0:98b84d9c8c96 190 }
vtraveller 0:98b84d9c8c96 191
vtraveller 11:49b987f6ae26 192 bool RTclock::write(uint8_t in_nAddress, const char * in_pBuffer, int in_nLength)
vtraveller 0:98b84d9c8c96 193 {
vtraveller 0:98b84d9c8c96 194 char aBuffer[10];
vtraveller 0:98b84d9c8c96 195
vtraveller 0:98b84d9c8c96 196 aBuffer[0] = in_nAddress & 0xff;
vtraveller 0:98b84d9c8c96 197
vtraveller 0:98b84d9c8c96 198 for (size_t i = 0 ; i < in_nLength; i++)
vtraveller 0:98b84d9c8c96 199 aBuffer[i + 1] = in_pBuffer[i];
vtraveller 0:98b84d9c8c96 200
vtraveller 13:1ccadbd4c1bd 201 return m_cI2C.write(m_nAddress, aBuffer, in_nLength + 1);
vtraveller 0:98b84d9c8c96 202 }