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:
Sat Jan 24 15:59:29 2015 +0000
Revision:
17:bdc15c054ac1
Parent:
16:f7e4b4cbfb9e
Fixed bug where tm struct used a month range of 0-11 and the DS3231 uses a range 1-12.

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