Ian Bolfarini
/
APS_SO
APS_SO
Rtc_Ds1307.cpp@2:27a7a42b2bae, 2017-12-15 (annotated)
- Committer:
- ianwillianb
- Date:
- Fri Dec 15 20:07:49 2017 +0000
- Revision:
- 2:27a7a42b2bae
- Parent:
- 0:f603fa86c646
finalizado;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ianwillianb | 0:f603fa86c646 | 1 | #include "mbed.h" |
ianwillianb | 0:f603fa86c646 | 2 | #include "Rtc_Ds1307.h" |
ianwillianb | 0:f603fa86c646 | 3 | |
ianwillianb | 0:f603fa86c646 | 4 | #ifndef DEBUG |
ianwillianb | 0:f603fa86c646 | 5 | //#define DEBUG |
ianwillianb | 0:f603fa86c646 | 6 | #endif |
ianwillianb | 0:f603fa86c646 | 7 | |
ianwillianb | 0:f603fa86c646 | 8 | |
ianwillianb | 0:f603fa86c646 | 9 | const char *Rtc_Ds1307::m_weekDays[] = { "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" }; |
ianwillianb | 0:f603fa86c646 | 10 | |
ianwillianb | 0:f603fa86c646 | 11 | |
ianwillianb | 0:f603fa86c646 | 12 | Rtc_Ds1307::Rtc_Ds1307(PinName sda, PinName scl) |
ianwillianb | 0:f603fa86c646 | 13 | { |
ianwillianb | 0:f603fa86c646 | 14 | // Create a new I2C object |
ianwillianb | 0:f603fa86c646 | 15 | m_rtc = new I2C(sda, scl); |
ianwillianb | 0:f603fa86c646 | 16 | if (m_rtc == NULL) |
ianwillianb | 0:f603fa86c646 | 17 | error("Rtc_Ds1307"); |
ianwillianb | 0:f603fa86c646 | 18 | |
ianwillianb | 0:f603fa86c646 | 19 | // Set the frequency to standard 100kHz |
ianwillianb | 0:f603fa86c646 | 20 | m_rtc->frequency(100000); |
ianwillianb | 0:f603fa86c646 | 21 | } |
ianwillianb | 0:f603fa86c646 | 22 | |
ianwillianb | 0:f603fa86c646 | 23 | Rtc_Ds1307::~Rtc_Ds1307() |
ianwillianb | 0:f603fa86c646 | 24 | { |
ianwillianb | 0:f603fa86c646 | 25 | if (m_rtc != NULL) |
ianwillianb | 0:f603fa86c646 | 26 | delete m_rtc; |
ianwillianb | 0:f603fa86c646 | 27 | } |
ianwillianb | 0:f603fa86c646 | 28 | |
ianwillianb | 0:f603fa86c646 | 29 | bool Rtc_Ds1307::setTime(Time_rtc& time, bool start, bool thm) |
ianwillianb | 0:f603fa86c646 | 30 | { |
ianwillianb | 0:f603fa86c646 | 31 | char buffer[7]; |
ianwillianb | 0:f603fa86c646 | 32 | // INFO("reading clock registers to write the new time : %d:%d:%d\n", time.hour, time.min, time.sec); |
ianwillianb | 0:f603fa86c646 | 33 | if (!read(0,buffer,7)) { |
ianwillianb | 0:f603fa86c646 | 34 | // ERR("Failed to read from RTC\n"); |
ianwillianb | 0:f603fa86c646 | 35 | return false; |
ianwillianb | 0:f603fa86c646 | 36 | } |
ianwillianb | 0:f603fa86c646 | 37 | // Now update only the time part (saving the existing flags) |
ianwillianb | 0:f603fa86c646 | 38 | if (start) { buffer[0] &= 0x7F; } else { buffer[0] |= 0x80; } |
ianwillianb | 0:f603fa86c646 | 39 | buffer[0] = (buffer[0]&0x80) | (decimalToBcd(time.sec)& 0x7f); |
ianwillianb | 0:f603fa86c646 | 40 | buffer[1] = decimalToBcd(time.min); |
ianwillianb | 0:f603fa86c646 | 41 | if (thm) { |
ianwillianb | 0:f603fa86c646 | 42 | // AM PM format |
ianwillianb | 0:f603fa86c646 | 43 | buffer[2] = (buffer[2]& 192) | (time.hour>12 ? (0x20 | ((decimalToBcd(time.hour-12)))) : decimalToBcd(time.hour)); |
ianwillianb | 0:f603fa86c646 | 44 | } |
ianwillianb | 0:f603fa86c646 | 45 | else { |
ianwillianb | 0:f603fa86c646 | 46 | // 24 hours format |
ianwillianb | 0:f603fa86c646 | 47 | buffer[2] = (buffer[2]& 192) | (decimalToBcd(time.hour) & 0x3F); |
ianwillianb | 0:f603fa86c646 | 48 | } |
ianwillianb | 0:f603fa86c646 | 49 | buffer[3] = time.wday; |
ianwillianb | 0:f603fa86c646 | 50 | buffer[4] = decimalToBcd(time.date); |
ianwillianb | 0:f603fa86c646 | 51 | buffer[5] = decimalToBcd(time.mon); |
ianwillianb | 0:f603fa86c646 | 52 | buffer[6] = decimalToBcd(time.year-2000); |
ianwillianb | 0:f603fa86c646 | 53 | // INFO("Writing new time and date data to RTC\n"); |
ianwillianb | 0:f603fa86c646 | 54 | if (!write(0, buffer, 7) ) { |
ianwillianb | 0:f603fa86c646 | 55 | // ERR("Failed to write the data to RTC!\n"); |
ianwillianb | 0:f603fa86c646 | 56 | return false; |
ianwillianb | 0:f603fa86c646 | 57 | } |
ianwillianb | 0:f603fa86c646 | 58 | return true; |
ianwillianb | 0:f603fa86c646 | 59 | } |
ianwillianb | 0:f603fa86c646 | 60 | |
ianwillianb | 0:f603fa86c646 | 61 | bool Rtc_Ds1307::getTime(Time_rtc& time) |
ianwillianb | 0:f603fa86c646 | 62 | { |
ianwillianb | 0:f603fa86c646 | 63 | char buffer[7]; |
ianwillianb | 0:f603fa86c646 | 64 | bool thm = false; |
ianwillianb | 0:f603fa86c646 | 65 | |
ianwillianb | 0:f603fa86c646 | 66 | // INFO("Getting time from RTC\n"); |
ianwillianb | 0:f603fa86c646 | 67 | if (!read(0, buffer, 7) ) { |
ianwillianb | 0:f603fa86c646 | 68 | // Failed to read |
ianwillianb | 0:f603fa86c646 | 69 | // ERR("Failed to read from RTC\n"); |
ianwillianb | 0:f603fa86c646 | 70 | return false; |
ianwillianb | 0:f603fa86c646 | 71 | } |
ianwillianb | 0:f603fa86c646 | 72 | thm = ((buffer[2] & 64) == 64); |
ianwillianb | 0:f603fa86c646 | 73 | time.sec = bcdToDecimal(buffer[0]&0x7F); |
ianwillianb | 0:f603fa86c646 | 74 | time.min = bcdToDecimal(buffer[1]); |
ianwillianb | 0:f603fa86c646 | 75 | if (thm) { |
ianwillianb | 0:f603fa86c646 | 76 | // in 12-hour-mode, we need to add 12 hours if PM bit is set |
ianwillianb | 0:f603fa86c646 | 77 | time.hour = Rtc_Ds1307::bcdToDecimal( buffer[2] & 31 ); |
ianwillianb | 0:f603fa86c646 | 78 | if ((buffer[2] & 32) == 32) |
ianwillianb | 0:f603fa86c646 | 79 | time.hour += 12; |
ianwillianb | 0:f603fa86c646 | 80 | } |
ianwillianb | 0:f603fa86c646 | 81 | else { |
ianwillianb | 0:f603fa86c646 | 82 | time.hour = Rtc_Ds1307::bcdToDecimal( buffer[2] & 63 ); |
ianwillianb | 0:f603fa86c646 | 83 | } |
ianwillianb | 0:f603fa86c646 | 84 | time.wday = buffer[3]; |
ianwillianb | 0:f603fa86c646 | 85 | time.date = Rtc_Ds1307::bcdToDecimal( buffer[4]); |
ianwillianb | 0:f603fa86c646 | 86 | time.mon = Rtc_Ds1307::bcdToDecimal( buffer[5]); |
ianwillianb | 0:f603fa86c646 | 87 | time.year = Rtc_Ds1307::bcdToDecimal(buffer[6]) + 2000; // plus hundret is because RTC is giving the years since 2000, but std c struct tm needs years since 1900 |
ianwillianb | 0:f603fa86c646 | 88 | |
ianwillianb | 0:f603fa86c646 | 89 | return true; |
ianwillianb | 0:f603fa86c646 | 90 | } |
ianwillianb | 0:f603fa86c646 | 91 | |
ianwillianb | 0:f603fa86c646 | 92 | |
ianwillianb | 0:f603fa86c646 | 93 | bool Rtc_Ds1307::startClock() |
ianwillianb | 0:f603fa86c646 | 94 | { |
ianwillianb | 0:f603fa86c646 | 95 | char strtStop; |
ianwillianb | 0:f603fa86c646 | 96 | |
ianwillianb | 0:f603fa86c646 | 97 | // INFO ("Reading clock start/stop register value\n"); |
ianwillianb | 0:f603fa86c646 | 98 | if (!read(0, &strtStop, 1)) { |
ianwillianb | 0:f603fa86c646 | 99 | // ERR("Failed to read clock start stop register !\n"); |
ianwillianb | 0:f603fa86c646 | 100 | return false; |
ianwillianb | 0:f603fa86c646 | 101 | } |
ianwillianb | 0:f603fa86c646 | 102 | |
ianwillianb | 0:f603fa86c646 | 103 | strtStop &= 0x7F; |
ianwillianb | 0:f603fa86c646 | 104 | |
ianwillianb | 0:f603fa86c646 | 105 | //INFO("Writing back start/stop register value\n"); |
ianwillianb | 0:f603fa86c646 | 106 | if (!write(0, &strtStop, 1)) { |
ianwillianb | 0:f603fa86c646 | 107 | // ERR("Failed to write the start stop register !\n"); |
ianwillianb | 0:f603fa86c646 | 108 | return false; |
ianwillianb | 0:f603fa86c646 | 109 | } |
ianwillianb | 0:f603fa86c646 | 110 | |
ianwillianb | 0:f603fa86c646 | 111 | // INFO("Start/stop register value successfully written\n"); |
ianwillianb | 0:f603fa86c646 | 112 | return true; |
ianwillianb | 0:f603fa86c646 | 113 | } |
ianwillianb | 0:f603fa86c646 | 114 | |
ianwillianb | 0:f603fa86c646 | 115 | bool Rtc_Ds1307::stopClock() |
ianwillianb | 0:f603fa86c646 | 116 | { |
ianwillianb | 0:f603fa86c646 | 117 | char strtStop; |
ianwillianb | 0:f603fa86c646 | 118 | |
ianwillianb | 0:f603fa86c646 | 119 | // INFO ("Reading clock start/stop register value\n"); |
ianwillianb | 0:f603fa86c646 | 120 | if (!read(0, &strtStop, 1)) { |
ianwillianb | 0:f603fa86c646 | 121 | // ERR("Failed to read clock start stop register !\n"); |
ianwillianb | 0:f603fa86c646 | 122 | return false; |
ianwillianb | 0:f603fa86c646 | 123 | } |
ianwillianb | 0:f603fa86c646 | 124 | |
ianwillianb | 0:f603fa86c646 | 125 | strtStop |= 0x80; |
ianwillianb | 0:f603fa86c646 | 126 | |
ianwillianb | 0:f603fa86c646 | 127 | // INFO("Writing back start/stop register value\n"); |
ianwillianb | 0:f603fa86c646 | 128 | if (!write(0, &strtStop, 1)) { |
ianwillianb | 0:f603fa86c646 | 129 | // ERR("Failed to write the start stop register !\n"); |
ianwillianb | 0:f603fa86c646 | 130 | return false; |
ianwillianb | 0:f603fa86c646 | 131 | } |
ianwillianb | 0:f603fa86c646 | 132 | |
ianwillianb | 0:f603fa86c646 | 133 | //INFO("Start/stop register value successfully written\n"); |
ianwillianb | 0:f603fa86c646 | 134 | return true; |
ianwillianb | 0:f603fa86c646 | 135 | } |
ianwillianb | 0:f603fa86c646 | 136 | |
ianwillianb | 0:f603fa86c646 | 137 | bool Rtc_Ds1307::setSquareWaveOutput(bool ena, SqwRateSelect_t rs) |
ianwillianb | 0:f603fa86c646 | 138 | { |
ianwillianb | 0:f603fa86c646 | 139 | char reg; |
ianwillianb | 0:f603fa86c646 | 140 | // INFO("Reading register value first\n"); |
ianwillianb | 0:f603fa86c646 | 141 | |
ianwillianb | 0:f603fa86c646 | 142 | if (!read(7,®, 1)) { |
ianwillianb | 0:f603fa86c646 | 143 | // ERR("Failed to read register value !\n"); |
ianwillianb | 0:f603fa86c646 | 144 | return false; |
ianwillianb | 0:f603fa86c646 | 145 | } |
ianwillianb | 0:f603fa86c646 | 146 | //INFO("[Reg:0x07] = %02x\n", reg); |
ianwillianb | 0:f603fa86c646 | 147 | |
ianwillianb | 0:f603fa86c646 | 148 | // preserve the OUT control bit while writing the frequency and enable bits |
ianwillianb | 0:f603fa86c646 | 149 | reg = (reg & 0x80) | (ena ? 0x10 : 0) | ((char)rs & 0x03); |
ianwillianb | 0:f603fa86c646 | 150 | |
ianwillianb | 0:f603fa86c646 | 151 | //INFO("Writing back register value\n"); |
ianwillianb | 0:f603fa86c646 | 152 | //INFO("[Reg:0x07] = %02x\n", reg); |
ianwillianb | 0:f603fa86c646 | 153 | |
ianwillianb | 0:f603fa86c646 | 154 | if (!write(7, ®, 1)) { |
ianwillianb | 0:f603fa86c646 | 155 | // ERR("Failed to write register value !\n"); |
ianwillianb | 0:f603fa86c646 | 156 | return false; |
ianwillianb | 0:f603fa86c646 | 157 | } |
ianwillianb | 0:f603fa86c646 | 158 | |
ianwillianb | 0:f603fa86c646 | 159 | // INFO("Successfully changed the square wave output.\n"); |
ianwillianb | 0:f603fa86c646 | 160 | return true; |
ianwillianb | 0:f603fa86c646 | 161 | } |
ianwillianb | 0:f603fa86c646 | 162 | |
ianwillianb | 0:f603fa86c646 | 163 | |
ianwillianb | 0:f603fa86c646 | 164 | |
ianwillianb | 0:f603fa86c646 | 165 | bool Rtc_Ds1307::read(int address, char *buffer, int len) |
ianwillianb | 0:f603fa86c646 | 166 | { |
ianwillianb | 0:f603fa86c646 | 167 | char buffer2[2] = {(char)address, 0}; |
ianwillianb | 0:f603fa86c646 | 168 | |
ianwillianb | 0:f603fa86c646 | 169 | // m_rtc->start(); |
ianwillianb | 0:f603fa86c646 | 170 | if (m_rtc->write(0xd0, buffer2, 1) != 0) { |
ianwillianb | 0:f603fa86c646 | 171 | // ERR("Failed to write register address on rtv!\n"); |
ianwillianb | 0:f603fa86c646 | 172 | m_rtc->stop(); |
ianwillianb | 0:f603fa86c646 | 173 | return false; |
ianwillianb | 0:f603fa86c646 | 174 | } |
ianwillianb | 0:f603fa86c646 | 175 | if (m_rtc->read(0xd0, buffer, len) != 0) { |
ianwillianb | 0:f603fa86c646 | 176 | // ERR("Failed to read register !\n"); |
ianwillianb | 0:f603fa86c646 | 177 | return false; |
ianwillianb | 0:f603fa86c646 | 178 | } |
ianwillianb | 0:f603fa86c646 | 179 | m_rtc->stop(); |
ianwillianb | 0:f603fa86c646 | 180 | |
ianwillianb | 0:f603fa86c646 | 181 | // INFO("Successfully read %d registers from RTC\n", len); |
ianwillianb | 0:f603fa86c646 | 182 | return true; |
ianwillianb | 0:f603fa86c646 | 183 | } |
ianwillianb | 0:f603fa86c646 | 184 | |
ianwillianb | 0:f603fa86c646 | 185 | bool Rtc_Ds1307::write(int address, char *buffer, int len) |
ianwillianb | 0:f603fa86c646 | 186 | { |
ianwillianb | 0:f603fa86c646 | 187 | char buffer2[10]; |
ianwillianb | 0:f603fa86c646 | 188 | buffer2[0] = address&0xFF; |
ianwillianb | 0:f603fa86c646 | 189 | for (int i = 0 ; i < len ; i++) |
ianwillianb | 0:f603fa86c646 | 190 | buffer2[i+1] = buffer[i]; |
ianwillianb | 0:f603fa86c646 | 191 | |
ianwillianb | 0:f603fa86c646 | 192 | // m_rtc->start(); |
ianwillianb | 0:f603fa86c646 | 193 | if (m_rtc->write(0xd0, buffer2, len+1) != 0) { |
ianwillianb | 0:f603fa86c646 | 194 | // ERR("Failed to write data to rtc\n"); |
ianwillianb | 0:f603fa86c646 | 195 | m_rtc->stop(); |
ianwillianb | 0:f603fa86c646 | 196 | return false; |
ianwillianb | 0:f603fa86c646 | 197 | } |
ianwillianb | 0:f603fa86c646 | 198 | m_rtc->stop(); |
ianwillianb | 0:f603fa86c646 | 199 | return true; |
ianwillianb | 0:f603fa86c646 | 200 | } |
ianwillianb | 0:f603fa86c646 | 201 | |
ianwillianb | 0:f603fa86c646 | 202 | |
ianwillianb | 0:f603fa86c646 | 203 | |
ianwillianb | 0:f603fa86c646 | 204 | |
ianwillianb | 0:f603fa86c646 | 205 | RtcCls::RtcCls(PinName sda, PinName scl, PinName sqw, bool bUseSqw) |
ianwillianb | 0:f603fa86c646 | 206 | : Rtc_Ds1307(sda, scl), m_sqw(sqw), m_bUseSqw(bUseSqw), m_bAlarmEnabled(false), m_alarmfunc(NULL) |
ianwillianb | 0:f603fa86c646 | 207 | { |
ianwillianb | 0:f603fa86c646 | 208 | Time_rtc t; |
ianwillianb | 0:f603fa86c646 | 209 | // query time from device |
ianwillianb | 0:f603fa86c646 | 210 | getTime(t); |
ianwillianb | 0:f603fa86c646 | 211 | // sync the time with MBED RTC |
ianwillianb | 0:f603fa86c646 | 212 | struct tm now = {t.sec, t.min, t.hour, t.date, t.mon-1, t.year-1900}; |
ianwillianb | 0:f603fa86c646 | 213 | m_time = mktime(&now); |
ianwillianb | 0:f603fa86c646 | 214 | set_time(m_time); |
ianwillianb | 0:f603fa86c646 | 215 | |
ianwillianb | 0:f603fa86c646 | 216 | // Only register the callback and start the SQW if requested to do so. Otherwise the system |
ianwillianb | 0:f603fa86c646 | 217 | // will use the MBED built-in RTC. |
ianwillianb | 0:f603fa86c646 | 218 | if (m_bUseSqw) { |
ianwillianb | 0:f603fa86c646 | 219 | // start the wave |
ianwillianb | 0:f603fa86c646 | 220 | setSquareWaveOutput(true, RS1Hz); |
ianwillianb | 0:f603fa86c646 | 221 | // register callback from now on the time will be maintained by the square wave input |
ianwillianb | 0:f603fa86c646 | 222 | m_sqw.rise(this, &RtcCls::_callback); |
ianwillianb | 0:f603fa86c646 | 223 | } |
ianwillianb | 0:f603fa86c646 | 224 | } |
ianwillianb | 0:f603fa86c646 | 225 | |
ianwillianb | 0:f603fa86c646 | 226 | void RtcCls::_callback(void) |
ianwillianb | 0:f603fa86c646 | 227 | { |
ianwillianb | 0:f603fa86c646 | 228 | // INFO("Tick!"); |
ianwillianb | 0:f603fa86c646 | 229 | // Simply increase the number of seconds |
ianwillianb | 0:f603fa86c646 | 230 | m_time++; |
ianwillianb | 0:f603fa86c646 | 231 | // if (m_bAlarmEnabled && (m_time == m_alarmTime)) { |
ianwillianb | 0:f603fa86c646 | 232 | // if (m_alarmfunc != NULL) |
ianwillianb | 0:f603fa86c646 | 233 | // m_alarmfunc(); |
ianwillianb | 0:f603fa86c646 | 234 | // m_bAlarmEnabled = false; |
ianwillianb | 0:f603fa86c646 | 235 | // } |
ianwillianb | 0:f603fa86c646 | 236 | } |
ianwillianb | 0:f603fa86c646 | 237 | |
ianwillianb | 0:f603fa86c646 | 238 | time_t RtcCls::getTime() |
ianwillianb | 0:f603fa86c646 | 239 | { |
ianwillianb | 0:f603fa86c646 | 240 | // when not using the HW support, we have to query the RTC chip. Other wise we can just return out stored value |
ianwillianb | 0:f603fa86c646 | 241 | if (!m_bUseSqw) { |
ianwillianb | 0:f603fa86c646 | 242 | Time_rtc t; |
ianwillianb | 0:f603fa86c646 | 243 | getTime(t); |
ianwillianb | 0:f603fa86c646 | 244 | struct tm now = {t.sec, t.min, t.hour, t.date, t.mon-1, t.year-1900}; |
ianwillianb | 0:f603fa86c646 | 245 | m_time = mktime(&now); |
ianwillianb | 0:f603fa86c646 | 246 | //INFO("getting time %02d.%02d.%04d %02d:%02d:%02d Ticks=%08lx", t.date, t.mon, t.year, t.hour, t.min, t.sec, m_time); |
ianwillianb | 0:f603fa86c646 | 247 | } |
ianwillianb | 0:f603fa86c646 | 248 | else { |
ianwillianb | 0:f603fa86c646 | 249 | //INFO("getting time Ticks=%08lx", m_time); |
ianwillianb | 0:f603fa86c646 | 250 | } |
ianwillianb | 0:f603fa86c646 | 251 | return m_time; |
ianwillianb | 0:f603fa86c646 | 252 | } |
ianwillianb | 0:f603fa86c646 | 253 | |
ianwillianb | 0:f603fa86c646 | 254 | void RtcCls::setTime(time_t t) |
ianwillianb | 0:f603fa86c646 | 255 | { |
ianwillianb | 0:f603fa86c646 | 256 | Time_rtc tim; |
ianwillianb | 0:f603fa86c646 | 257 | struct tm *now; |
ianwillianb | 0:f603fa86c646 | 258 | now = localtime(&t); |
ianwillianb | 0:f603fa86c646 | 259 | |
ianwillianb | 0:f603fa86c646 | 260 | tim.sec = now->tm_sec; |
ianwillianb | 0:f603fa86c646 | 261 | tim.min = now->tm_min; |
ianwillianb | 0:f603fa86c646 | 262 | tim.hour = now->tm_hour; |
ianwillianb | 0:f603fa86c646 | 263 | tim.date = now->tm_mday; |
ianwillianb | 0:f603fa86c646 | 264 | tim.mon = now->tm_mon+1; |
ianwillianb | 0:f603fa86c646 | 265 | tim.year = now->tm_year + 1900; |
ianwillianb | 0:f603fa86c646 | 266 | tim.wday = now->tm_wday +1; |
ianwillianb | 0:f603fa86c646 | 267 | |
ianwillianb | 0:f603fa86c646 | 268 | setTime( tim, true, true); |
ianwillianb | 0:f603fa86c646 | 269 | set_time(t); |
ianwillianb | 0:f603fa86c646 | 270 | } |
ianwillianb | 0:f603fa86c646 | 271 |