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:
Tue Sep 02 07:12:09 2014 +0000
Revision:
10:e5eabd3a1ca6
Parent:
9:3a0ba8364ef2
Child:
11:49b987f6ae26
Changed to use shared I2C object

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 10:e5eabd3a1ca6 4 RTclock::RTclock(I2C & in_cI2C, EClockType in_eClockType)
vtraveller 10:e5eabd3a1ca6 5 : m_bTwelveHour(false)
vtraveller 10:e5eabd3a1ca6 6 , m_cI2C(in_cI2C)
vtraveller 9:3a0ba8364ef2 7 , m_eClockType(in_eClockType)
vtraveller 0:98b84d9c8c96 8 {
vtraveller 0:98b84d9c8c96 9 }
vtraveller 0:98b84d9c8c96 10
vtraveller 0:98b84d9c8c96 11 RTclock::~RTclock()
vtraveller 0:98b84d9c8c96 12 {
vtraveller 0:98b84d9c8c96 13 }
vtraveller 0:98b84d9c8c96 14
vtraveller 7:3621025e7949 15 int RTclock::bcdToDecimal(int in_nBCD)
vtraveller 0:98b84d9c8c96 16 {
vtraveller 0:98b84d9c8c96 17 return ((in_nBCD & 0xF0) >> 4) * 10 + (in_nBCD & 0x0F);
vtraveller 0:98b84d9c8c96 18 }
vtraveller 0:98b84d9c8c96 19
vtraveller 7:3621025e7949 20 int RTclock::decimalToBcd(int in_nDecimal)
vtraveller 0:98b84d9c8c96 21 {
vtraveller 0:98b84d9c8c96 22 return (in_nDecimal % 10) + ((in_nDecimal / 10) << 4);
vtraveller 0:98b84d9c8c96 23 }
vtraveller 0:98b84d9c8c96 24
vtraveller 7:3621025e7949 25 bool RTclock::getTime(tm & out_sTM)
vtraveller 0:98b84d9c8c96 26 {
vtraveller 0:98b84d9c8c96 27 char aBuffer[7];
vtraveller 0:98b84d9c8c96 28
vtraveller 0:98b84d9c8c96 29 if (!read(0, aBuffer, 7)) return false;
vtraveller 0:98b84d9c8c96 30
vtraveller 5:d71d6e5a7eee 31 m_bTwelveHour = ((aBuffer[2] & 0x40) == 0x40);
vtraveller 4:04a51e4dbf4c 32
vtraveller 7:3621025e7949 33 out_sTM.tm_sec = bcdToDecimal(aBuffer[0] & 0x7f);
vtraveller 7:3621025e7949 34 out_sTM.tm_min = bcdToDecimal(aBuffer[1]);
vtraveller 0:98b84d9c8c96 35
vtraveller 5:d71d6e5a7eee 36 if (m_bTwelveHour)
vtraveller 0:98b84d9c8c96 37 {
vtraveller 5:d71d6e5a7eee 38 // add 12 hours if PM bit is set and past midday
vtraveller 7:3621025e7949 39 out_sTM.tm_hour = bcdToDecimal(aBuffer[2] & 31);
vtraveller 5:d71d6e5a7eee 40
vtraveller 5:d71d6e5a7eee 41 bool bPM = (0 != (aBuffer[2] & 0x20));
vtraveller 5:d71d6e5a7eee 42 if (bPM && 12 != out_sTM.tm_hour) out_sTM.tm_hour += 12;
vtraveller 0:98b84d9c8c96 43 }
vtraveller 0:98b84d9c8c96 44 else
vtraveller 0:98b84d9c8c96 45 {
vtraveller 7:3621025e7949 46 out_sTM.tm_hour = bcdToDecimal(aBuffer[2] & 0x3f);
vtraveller 0:98b84d9c8c96 47 }
vtraveller 0:98b84d9c8c96 48
vtraveller 7:3621025e7949 49 out_sTM.tm_wday = aBuffer[3] % 7;
vtraveller 7:3621025e7949 50 out_sTM.tm_mday = bcdToDecimal(aBuffer[4]);
vtraveller 7:3621025e7949 51 out_sTM.tm_mon = bcdToDecimal(aBuffer[5]);
vtraveller 7:3621025e7949 52 out_sTM.tm_year = (bcdToDecimal(aBuffer[6]) + 2000) - 1900; // Returns from 2000, need form 1900 for time function
vtraveller 1:8952befe5d36 53 out_sTM.tm_isdst = 0;
vtraveller 0:98b84d9c8c96 54
vtraveller 0:98b84d9c8c96 55 return true;
vtraveller 0:98b84d9c8c96 56 }
vtraveller 0:98b84d9c8c96 57
vtraveller 7:3621025e7949 58 bool RTclock::isTwelveHour()
vtraveller 5:d71d6e5a7eee 59 {
vtraveller 5:d71d6e5a7eee 60 return m_bTwelveHour;
vtraveller 5:d71d6e5a7eee 61 }
vtraveller 5:d71d6e5a7eee 62
vtraveller 7:3621025e7949 63 bool RTclock::mapTime()
vtraveller 0:98b84d9c8c96 64 {
vtraveller 0:98b84d9c8c96 65 tm sTM;
vtraveller 7:3621025e7949 66 if (!getTime(sTM)) return false;
vtraveller 0:98b84d9c8c96 67
vtraveller 0:98b84d9c8c96 68 // Convert and set internal time
vtraveller 0:98b84d9c8c96 69 time_t nTime = ::mktime(&sTM);
vtraveller 0:98b84d9c8c96 70 ::set_time(nTime);
vtraveller 0:98b84d9c8c96 71
vtraveller 0:98b84d9c8c96 72 return true;
vtraveller 0:98b84d9c8c96 73 }
vtraveller 0:98b84d9c8c96 74
vtraveller 1:8952befe5d36 75 bool RTclock::read(int in_nAddress, char * out_pBuffer, int in_nLength)
vtraveller 1:8952befe5d36 76 {
vtraveller 1:8952befe5d36 77 char aBuffer[2] = { (char)in_nAddress, 0 };
vtraveller 1:8952befe5d36 78
vtraveller 10:e5eabd3a1ca6 79 if (0 != m_cI2C.write(0xd0, aBuffer, 1)) return false;
vtraveller 10:e5eabd3a1ca6 80 if (0 != m_cI2C.read(0xd0, 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 9:3a0ba8364ef2 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 0:98b84d9c8c96 192 bool RTclock::write(int 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 10:e5eabd3a1ca6 201 return m_cI2C.write(0xd0, aBuffer, in_nLength + 1);
vtraveller 0:98b84d9c8c96 202 }