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:
Wed Sep 03 06:01:13 2014 +0000
Revision:
12:9e7a91c34083
Parent:
11:49b987f6ae26
Child:
13:1ccadbd4c1bd
Fixed bug in buffer caused by sizeof()

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 11:49b987f6ae26 75 bool RTclock::read(uint8_t in_nAddress, char * out_pBuffer, int in_nLength)
vtraveller 1:8952befe5d36 76 {
vtraveller 12:9e7a91c34083 77 if (0 != m_cI2C.write(0xd0, (char *)&in_nAddress, 1)) return false;
vtraveller 10:e5eabd3a1ca6 78 if (0 != m_cI2C.read(0xd0, out_pBuffer, in_nLength)) return false;
vtraveller 1:8952befe5d36 79
vtraveller 1:8952befe5d36 80 return true;
vtraveller 1:8952befe5d36 81 }
vtraveller 1:8952befe5d36 82
vtraveller 7:3621025e7949 83 bool RTclock::setTime(const tm & in_sTM, bool in_bTwelveHour)
vtraveller 0:98b84d9c8c96 84 {
vtraveller 0:98b84d9c8c96 85 char aBuffer[7];
vtraveller 0:98b84d9c8c96 86
vtraveller 0:98b84d9c8c96 87 // Preserve flags that were in register
vtraveller 0:98b84d9c8c96 88 if (!read(0,aBuffer,7)) return false;
vtraveller 0:98b84d9c8c96 89
vtraveller 5:d71d6e5a7eee 90 m_bTwelveHour = in_bTwelveHour;
vtraveller 5:d71d6e5a7eee 91
vtraveller 5:d71d6e5a7eee 92 // We always have tm in 24hr form - so adjut if 12hr clock
vtraveller 5:d71d6e5a7eee 93 int nHour = in_sTM.tm_hour;
vtraveller 5:d71d6e5a7eee 94 if (in_bTwelveHour) nHour %= 12;
vtraveller 5:d71d6e5a7eee 95
vtraveller 9:3a0ba8364ef2 96 switch (m_eClockType)
vtraveller 5:d71d6e5a7eee 97 {
vtraveller 9:3a0ba8364ef2 98 case eDS1311:
vtraveller 9:3a0ba8364ef2 99 aBuffer[0] &= 0x7f;
vtraveller 9:3a0ba8364ef2 100 aBuffer[0] = (aBuffer[0] & 0x80) | (decimalToBcd(in_sTM.tm_sec)& 0x7f);
vtraveller 9:3a0ba8364ef2 101 aBuffer[1] = decimalToBcd(in_sTM.tm_min);
vtraveller 9:3a0ba8364ef2 102 aBuffer[2] = (aBuffer[2] & 0xc4) | (decimalToBcd(nHour) & 0x3f);
vtraveller 9:3a0ba8364ef2 103 aBuffer[3] = in_sTM.tm_wday;
vtraveller 9:3a0ba8364ef2 104 aBuffer[4] = decimalToBcd(in_sTM.tm_mday);
vtraveller 9:3a0ba8364ef2 105 aBuffer[5] = decimalToBcd(in_sTM.tm_mon);
vtraveller 9:3a0ba8364ef2 106 aBuffer[6] = decimalToBcd(in_sTM.tm_year + 1900 - 2000);
vtraveller 5:d71d6e5a7eee 107
vtraveller 9:3a0ba8364ef2 108 // Handle the 12hr clock bits
vtraveller 9:3a0ba8364ef2 109 if (in_bTwelveHour)
vtraveller 9:3a0ba8364ef2 110 {
vtraveller 9:3a0ba8364ef2 111 // Turn on 12hr clock
vtraveller 9:3a0ba8364ef2 112 aBuffer[2] |= 0x40;
vtraveller 9:3a0ba8364ef2 113
vtraveller 9:3a0ba8364ef2 114 // Set am/pm bit based on hours
vtraveller 9:3a0ba8364ef2 115 if (in_sTM.tm_hour >= 12) aBuffer[2] |= 0x20; else aBuffer[2] &= ~0x20;
vtraveller 9:3a0ba8364ef2 116 }
vtraveller 9:3a0ba8364ef2 117 else
vtraveller 9:3a0ba8364ef2 118 {
vtraveller 9:3a0ba8364ef2 119 aBuffer[2] &= ~64;
vtraveller 9:3a0ba8364ef2 120 }
vtraveller 9:3a0ba8364ef2 121 break;
vtraveller 9:3a0ba8364ef2 122
vtraveller 9:3a0ba8364ef2 123 case eDS3231:
vtraveller 9:3a0ba8364ef2 124 aBuffer[0] = decimalToBcd(in_sTM.tm_sec) & 0x7f;
vtraveller 9:3a0ba8364ef2 125 aBuffer[1] = decimalToBcd(in_sTM.tm_min) & 0x7f;
vtraveller 9:3a0ba8364ef2 126 aBuffer[2] = decimalToBcd(nHour) & (m_bTwelveHour ? 0x1f : 0x3f);
vtraveller 9:3a0ba8364ef2 127 aBuffer[3] = in_sTM.tm_wday;
vtraveller 9:3a0ba8364ef2 128 aBuffer[4] = decimalToBcd(in_sTM.tm_mday);
vtraveller 9:3a0ba8364ef2 129 aBuffer[5] = decimalToBcd(in_sTM.tm_mon) & 0x80 /* 2000+ */;
vtraveller 9:3a0ba8364ef2 130 aBuffer[6] = decimalToBcd(in_sTM.tm_year + 1900 - 2000);
vtraveller 9:3a0ba8364ef2 131
vtraveller 9:3a0ba8364ef2 132 // Handle the 12hr clock bits
vtraveller 9:3a0ba8364ef2 133 if (in_bTwelveHour)
vtraveller 9:3a0ba8364ef2 134 {
vtraveller 9:3a0ba8364ef2 135 // Turn on 12hr clock
vtraveller 9:3a0ba8364ef2 136 aBuffer[2] |= 0x40;
vtraveller 9:3a0ba8364ef2 137
vtraveller 9:3a0ba8364ef2 138 // Set am/pm bit based on hours
vtraveller 9:3a0ba8364ef2 139 if (in_sTM.tm_hour >= 12) aBuffer[2] |= 0x20;
vtraveller 9:3a0ba8364ef2 140 }
vtraveller 9:3a0ba8364ef2 141 break;
vtraveller 9:3a0ba8364ef2 142 }
vtraveller 5:d71d6e5a7eee 143
vtraveller 0:98b84d9c8c96 144 // Write new date and time
vtraveller 7:3621025e7949 145 setRunning(false);
vtraveller 0:98b84d9c8c96 146
vtraveller 0:98b84d9c8c96 147 bool bSuccess = write(0, aBuffer, 7);
vtraveller 0:98b84d9c8c96 148
vtraveller 7:3621025e7949 149 if (bSuccess) setRunning(true);
vtraveller 0:98b84d9c8c96 150
vtraveller 0:98b84d9c8c96 151 return bSuccess;
vtraveller 0:98b84d9c8c96 152 }
vtraveller 0:98b84d9c8c96 153
vtraveller 7:3621025e7949 154 bool RTclock::setRunning(bool in_bEnable)
vtraveller 0:98b84d9c8c96 155 {
vtraveller 0:98b84d9c8c96 156 char nRunning;
vtraveller 0:98b84d9c8c96 157
vtraveller 0:98b84d9c8c96 158 if (!read(0, &nRunning, 1)) return false;
vtraveller 0:98b84d9c8c96 159
vtraveller 0:98b84d9c8c96 160 // Set running
vtraveller 0:98b84d9c8c96 161 if (in_bEnable)
vtraveller 0:98b84d9c8c96 162 {
vtraveller 0:98b84d9c8c96 163 nRunning &= 0x7F;
vtraveller 0:98b84d9c8c96 164 }
vtraveller 0:98b84d9c8c96 165 else
vtraveller 0:98b84d9c8c96 166 {
vtraveller 0:98b84d9c8c96 167 nRunning |= 0x80;
vtraveller 0:98b84d9c8c96 168 }
vtraveller 0:98b84d9c8c96 169
vtraveller 0:98b84d9c8c96 170 return write(0, &nRunning, 1);
vtraveller 0:98b84d9c8c96 171 }
vtraveller 0:98b84d9c8c96 172
vtraveller 7:3621025e7949 173 bool RTclock::setSquareWaveOutput
vtraveller 0:98b84d9c8c96 174 (
vtraveller 0:98b84d9c8c96 175 bool in_bEnable,
vtraveller 0:98b84d9c8c96 176 ESquareWaveRates in_nRateSelect
vtraveller 0:98b84d9c8c96 177 )
vtraveller 0:98b84d9c8c96 178 {
vtraveller 0:98b84d9c8c96 179 char nValue;
vtraveller 0:98b84d9c8c96 180
vtraveller 0:98b84d9c8c96 181 // Read register
vtraveller 0:98b84d9c8c96 182 if (!read(7, &nValue, 1)) return false;
vtraveller 0:98b84d9c8c96 183
vtraveller 0:98b84d9c8c96 184 // Protect control bits
vtraveller 0:98b84d9c8c96 185 nValue = (nValue & 0x80) | (in_bEnable ? 0x10 : 0) | ((char)in_nRateSelect & 0x03);
vtraveller 0:98b84d9c8c96 186
vtraveller 0:98b84d9c8c96 187 return write(7, &nValue, 1);
vtraveller 0:98b84d9c8c96 188 }
vtraveller 0:98b84d9c8c96 189
vtraveller 11:49b987f6ae26 190 bool RTclock::write(uint8_t in_nAddress, const char * in_pBuffer, int in_nLength)
vtraveller 0:98b84d9c8c96 191 {
vtraveller 0:98b84d9c8c96 192 char aBuffer[10];
vtraveller 0:98b84d9c8c96 193
vtraveller 0:98b84d9c8c96 194 aBuffer[0] = in_nAddress & 0xff;
vtraveller 0:98b84d9c8c96 195
vtraveller 0:98b84d9c8c96 196 for (size_t i = 0 ; i < in_nLength; i++)
vtraveller 0:98b84d9c8c96 197 aBuffer[i + 1] = in_pBuffer[i];
vtraveller 0:98b84d9c8c96 198
vtraveller 10:e5eabd3a1ca6 199 return m_cI2C.write(0xd0, aBuffer, in_nLength + 1);
vtraveller 0:98b84d9c8c96 200 }