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 09 17:02:40 2014 +0000
Revision:
5:d71d6e5a7eee
Parent:
4:04a51e4dbf4c
Child:
7:3621025e7949
Added 12/24 hour am/pm support.

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