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.
RTclock.cpp@15:1645f55bd0ee, 2014-10-08 (annotated)
- 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?
User | Revision | Line number | New 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 | } |