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@0:98b84d9c8c96, 2014-08-09 (annotated)
- Committer:
- vtraveller
- Date:
- Sat Aug 09 09:18:38 2014 +0000
- Revision:
- 0:98b84d9c8c96
- Child:
- 1:8952befe5d36
First version. Normalised version of DS1307 I2C control. Designed to map into the internal time.h functions using MapTime.
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 | 0:98b84d9c8c96 | 4 | const char * RTclock::m_aWeekDays[] = { "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" }; |
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 | 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 | 0:98b84d9c8c96 | 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 | 0:98b84d9c8c96 | 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 | 0:98b84d9c8c96 | 27 | bool RTclock::GetTime(tm & out_sTM) |
vtraveller | 0:98b84d9c8c96 | 28 | { |
vtraveller | 0:98b84d9c8c96 | 29 | char aBuffer[7]; |
vtraveller | 0:98b84d9c8c96 | 30 | bool b12hour = false; |
vtraveller | 0:98b84d9c8c96 | 31 | |
vtraveller | 0:98b84d9c8c96 | 32 | if (!read(0, aBuffer, 7)) return false; |
vtraveller | 0:98b84d9c8c96 | 33 | |
vtraveller | 0:98b84d9c8c96 | 34 | b12hour = ((aBuffer[2] & 64) == 64); |
vtraveller | 0:98b84d9c8c96 | 35 | out_sTM.tm_sec = BcdToDecimal(aBuffer[0] & 0x7F); |
vtraveller | 0:98b84d9c8c96 | 36 | out_sTM.tm_min = BcdToDecimal(aBuffer[1]); |
vtraveller | 0:98b84d9c8c96 | 37 | |
vtraveller | 0:98b84d9c8c96 | 38 | if (b12hour) |
vtraveller | 0:98b84d9c8c96 | 39 | { |
vtraveller | 0:98b84d9c8c96 | 40 | // add 12 hours if PM bit is set |
vtraveller | 0:98b84d9c8c96 | 41 | out_sTM.tm_hour = BcdToDecimal(aBuffer[2] & 31); |
vtraveller | 0:98b84d9c8c96 | 42 | if (aBuffer[2] & 32) out_sTM.tm_hour += 12; |
vtraveller | 0:98b84d9c8c96 | 43 | } |
vtraveller | 0:98b84d9c8c96 | 44 | else |
vtraveller | 0:98b84d9c8c96 | 45 | { |
vtraveller | 0:98b84d9c8c96 | 46 | out_sTM.tm_hour = BcdToDecimal(aBuffer[2] & 63); |
vtraveller | 0:98b84d9c8c96 | 47 | } |
vtraveller | 0:98b84d9c8c96 | 48 | |
vtraveller | 0:98b84d9c8c96 | 49 | out_sTM.tm_wday = aBuffer[3]; |
vtraveller | 0:98b84d9c8c96 | 50 | out_sTM.tm_mday = BcdToDecimal(aBuffer[4]); |
vtraveller | 0:98b84d9c8c96 | 51 | out_sTM.tm_mon = BcdToDecimal(aBuffer[5]); |
vtraveller | 0:98b84d9c8c96 | 52 | out_sTM.tm_year = BcdToDecimal(aBuffer[6]) + 2000; // plus hundred (RTC returns years since 2000) but std c is from 1900 |
vtraveller | 0:98b84d9c8c96 | 53 | |
vtraveller | 0:98b84d9c8c96 | 54 | return true; |
vtraveller | 0:98b84d9c8c96 | 55 | } |
vtraveller | 0:98b84d9c8c96 | 56 | |
vtraveller | 0:98b84d9c8c96 | 57 | const char * RTclock::GetWeekday(int in_nWeekDay) |
vtraveller | 0:98b84d9c8c96 | 58 | { |
vtraveller | 0:98b84d9c8c96 | 59 | return m_aWeekDays[in_nWeekDay]; |
vtraveller | 0:98b84d9c8c96 | 60 | } |
vtraveller | 0:98b84d9c8c96 | 61 | |
vtraveller | 0:98b84d9c8c96 | 62 | bool RTclock::read(int in_nAddress, char * out_pBuffer, int in_nLength) |
vtraveller | 0:98b84d9c8c96 | 63 | { |
vtraveller | 0:98b84d9c8c96 | 64 | char aBuffer[2] = { (char)in_nAddress, 0 }; |
vtraveller | 0:98b84d9c8c96 | 65 | |
vtraveller | 0:98b84d9c8c96 | 66 | if (0 != RTclock_parent::write(0xd0, aBuffer, 1)) return false; |
vtraveller | 0:98b84d9c8c96 | 67 | if (0 != RTclock_parent::read(0xd0, out_pBuffer, in_nLength)) return false; |
vtraveller | 0:98b84d9c8c96 | 68 | |
vtraveller | 0:98b84d9c8c96 | 69 | return true; |
vtraveller | 0:98b84d9c8c96 | 70 | } |
vtraveller | 0:98b84d9c8c96 | 71 | |
vtraveller | 0:98b84d9c8c96 | 72 | bool RTclock::MapTime() |
vtraveller | 0:98b84d9c8c96 | 73 | { |
vtraveller | 0:98b84d9c8c96 | 74 | tm sTM; |
vtraveller | 0:98b84d9c8c96 | 75 | if (!GetTime(sTM)) return false; |
vtraveller | 0:98b84d9c8c96 | 76 | |
vtraveller | 0:98b84d9c8c96 | 77 | // Convert and set internal time |
vtraveller | 0:98b84d9c8c96 | 78 | time_t nTime = ::mktime(&sTM); |
vtraveller | 0:98b84d9c8c96 | 79 | ::set_time(nTime); |
vtraveller | 0:98b84d9c8c96 | 80 | |
vtraveller | 0:98b84d9c8c96 | 81 | return true; |
vtraveller | 0:98b84d9c8c96 | 82 | } |
vtraveller | 0:98b84d9c8c96 | 83 | |
vtraveller | 0:98b84d9c8c96 | 84 | bool RTclock::SetTime(const tm & in_sTM) |
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 | 0:98b84d9c8c96 | 91 | aBuffer[0] &= 0x7F; |
vtraveller | 0:98b84d9c8c96 | 92 | aBuffer[0] = (aBuffer[0] & 0x80) | (DecimalToBcd(in_sTM.tm_sec)& 0x7f); |
vtraveller | 0:98b84d9c8c96 | 93 | aBuffer[1] = DecimalToBcd(in_sTM.tm_min); |
vtraveller | 0:98b84d9c8c96 | 94 | aBuffer[2] = (aBuffer[2] & 196) | (DecimalToBcd(in_sTM.tm_hour) & 0x3F); |
vtraveller | 0:98b84d9c8c96 | 95 | aBuffer[3] = in_sTM.tm_wday; |
vtraveller | 0:98b84d9c8c96 | 96 | aBuffer[4] = DecimalToBcd(in_sTM.tm_mday); |
vtraveller | 0:98b84d9c8c96 | 97 | aBuffer[5] = DecimalToBcd(in_sTM.tm_mon); |
vtraveller | 0:98b84d9c8c96 | 98 | aBuffer[6] = DecimalToBcd(in_sTM.tm_year-2000); |
vtraveller | 0:98b84d9c8c96 | 99 | |
vtraveller | 0:98b84d9c8c96 | 100 | // Write new date and time |
vtraveller | 0:98b84d9c8c96 | 101 | SetRunning(false); |
vtraveller | 0:98b84d9c8c96 | 102 | |
vtraveller | 0:98b84d9c8c96 | 103 | bool bSuccess = write(0, aBuffer, 7); |
vtraveller | 0:98b84d9c8c96 | 104 | |
vtraveller | 0:98b84d9c8c96 | 105 | if (bSuccess) SetRunning(true); |
vtraveller | 0:98b84d9c8c96 | 106 | |
vtraveller | 0:98b84d9c8c96 | 107 | return bSuccess; |
vtraveller | 0:98b84d9c8c96 | 108 | } |
vtraveller | 0:98b84d9c8c96 | 109 | |
vtraveller | 0:98b84d9c8c96 | 110 | bool RTclock::SetRunning(bool in_bEnable) |
vtraveller | 0:98b84d9c8c96 | 111 | { |
vtraveller | 0:98b84d9c8c96 | 112 | char nRunning; |
vtraveller | 0:98b84d9c8c96 | 113 | |
vtraveller | 0:98b84d9c8c96 | 114 | if (!read(0, &nRunning, 1)) return false; |
vtraveller | 0:98b84d9c8c96 | 115 | |
vtraveller | 0:98b84d9c8c96 | 116 | // Set running |
vtraveller | 0:98b84d9c8c96 | 117 | if (in_bEnable) |
vtraveller | 0:98b84d9c8c96 | 118 | { |
vtraveller | 0:98b84d9c8c96 | 119 | nRunning &= 0x7F; |
vtraveller | 0:98b84d9c8c96 | 120 | } |
vtraveller | 0:98b84d9c8c96 | 121 | else |
vtraveller | 0:98b84d9c8c96 | 122 | { |
vtraveller | 0:98b84d9c8c96 | 123 | nRunning |= 0x80; |
vtraveller | 0:98b84d9c8c96 | 124 | } |
vtraveller | 0:98b84d9c8c96 | 125 | |
vtraveller | 0:98b84d9c8c96 | 126 | return write(0, &nRunning, 1); |
vtraveller | 0:98b84d9c8c96 | 127 | } |
vtraveller | 0:98b84d9c8c96 | 128 | |
vtraveller | 0:98b84d9c8c96 | 129 | bool RTclock::SetSquareWaveOutput |
vtraveller | 0:98b84d9c8c96 | 130 | ( |
vtraveller | 0:98b84d9c8c96 | 131 | bool in_bEnable, |
vtraveller | 0:98b84d9c8c96 | 132 | ESquareWaveRates in_nRateSelect |
vtraveller | 0:98b84d9c8c96 | 133 | ) |
vtraveller | 0:98b84d9c8c96 | 134 | { |
vtraveller | 0:98b84d9c8c96 | 135 | char nValue; |
vtraveller | 0:98b84d9c8c96 | 136 | |
vtraveller | 0:98b84d9c8c96 | 137 | // Read register |
vtraveller | 0:98b84d9c8c96 | 138 | if (!read(7, &nValue, 1)) return false; |
vtraveller | 0:98b84d9c8c96 | 139 | |
vtraveller | 0:98b84d9c8c96 | 140 | // Protect control bits |
vtraveller | 0:98b84d9c8c96 | 141 | nValue = (nValue & 0x80) | (in_bEnable ? 0x10 : 0) | ((char)in_nRateSelect & 0x03); |
vtraveller | 0:98b84d9c8c96 | 142 | |
vtraveller | 0:98b84d9c8c96 | 143 | return write(7, &nValue, 1); |
vtraveller | 0:98b84d9c8c96 | 144 | } |
vtraveller | 0:98b84d9c8c96 | 145 | |
vtraveller | 0:98b84d9c8c96 | 146 | bool RTclock::write(int in_nAddress, const char * in_pBuffer, int in_nLength) |
vtraveller | 0:98b84d9c8c96 | 147 | { |
vtraveller | 0:98b84d9c8c96 | 148 | char aBuffer[10]; |
vtraveller | 0:98b84d9c8c96 | 149 | |
vtraveller | 0:98b84d9c8c96 | 150 | aBuffer[0] = in_nAddress & 0xff; |
vtraveller | 0:98b84d9c8c96 | 151 | |
vtraveller | 0:98b84d9c8c96 | 152 | for (size_t i = 0 ; i < in_nLength; i++) |
vtraveller | 0:98b84d9c8c96 | 153 | aBuffer[i + 1] = in_pBuffer[i]; |
vtraveller | 0:98b84d9c8c96 | 154 | |
vtraveller | 0:98b84d9c8c96 | 155 | return RTclock_parent::write(0xd0, aBuffer, in_nLength + 1); |
vtraveller | 0:98b84d9c8c96 | 156 | } |