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:
Sat Aug 30 15:55:28 2014 +0000
Revision:
9:3a0ba8364ef2
Parent:
7:3621025e7949
Child:
10:e5eabd3a1ca6
Added support for DS3231

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