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 Oct 08 16:57:04 2014 +0000
Revision:
15:1645f55bd0ee
Parent:
14:d5b47ff12d17
Child:
16:f7e4b4cbfb9e
Fix for month.

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