Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
21 | jlesech | 1 | // Code by JeeLabs http://news.jeelabs.org/code/ |
2 | // Released to the public domain! Enjoy! |
||
3 | |||
4 | #include <Wire.h> |
||
5 | #include <avr/pgmspace.h> |
||
6 | #include "RTClib.h" |
||
7 | |||
8 | #define DS1307_ADDRESS 0x68 |
||
9 | #define SECONDS_PER_DAY 86400L |
||
10 | |||
11 | #define SECONDS_FROM_1970_TO_2000 946684800 |
||
12 | |||
13 | #if (ARDUINO >= 100) |
||
14 | #include <Arduino.h> // capital A so it is error prone on case-sensitive filesystems |
||
15 | #else |
||
16 | #include <WProgram.h> |
||
17 | #endif |
||
18 | |||
19 | int i = 0; //The new wire library needs to take an int when you are sending for the zero register |
||
20 | //////////////////////////////////////////////////////////////////////////////// |
||
21 | // utility code, some of this could be exposed in the DateTime API if needed |
||
22 | |||
23 | const uint8_t daysInMonth [] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 }; //has to be const or compiler compaints |
||
24 | |||
25 | // number of days since 2000/01/01, valid for 2001..2099 |
||
26 | static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) { |
||
27 | if (y >= 2000) |
||
28 | y -= 2000; |
||
29 | uint16_t days = d; |
||
30 | for (uint8_t i = 1; i < m; ++i) |
||
31 | days += pgm_read_byte(daysInMonth + i - 1); |
||
32 | if (m > 2 && y % 4 == 0) |
||
33 | ++days; |
||
34 | return days + 365 * y + (y + 3) / 4 - 1; |
||
35 | } |
||
36 | |||
37 | static long time2long(uint16_t days, uint8_t h, uint8_t m, uint8_t s) { |
||
38 | return ((days * 24L + h) * 60 + m) * 60 + s; |
||
39 | } |
||
40 | |||
41 | //////////////////////////////////////////////////////////////////////////////// |
||
42 | // DateTime implementation - ignores time zones and DST changes |
||
43 | // NOTE: also ignores leap seconds, see http://en.wikipedia.org/wiki/Leap_second |
||
44 | |||
45 | DateTime::DateTime (uint32_t t) { |
||
46 | t -= SECONDS_FROM_1970_TO_2000; // bring to 2000 timestamp from 1970 |
||
47 | |||
48 | ss = t % 60; |
||
49 | t /= 60; |
||
50 | mm = t % 60; |
||
51 | t /= 60; |
||
52 | hh = t % 24; |
||
53 | uint16_t days = t / 24; |
||
54 | uint8_t leap; |
||
55 | for (yOff = 0; ; ++yOff) { |
||
56 | leap = yOff % 4 == 0; |
||
57 | if (days < 365 + leap) |
||
58 | break; |
||
59 | days -= 365 + leap; |
||
60 | } |
||
61 | for (m = 1; ; ++m) { |
||
62 | uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1); |
||
63 | if (leap && m == 2) |
||
64 | ++daysPerMonth; |
||
65 | if (days < daysPerMonth) |
||
66 | break; |
||
67 | days -= daysPerMonth; |
||
68 | } |
||
69 | d = days + 1; |
||
70 | } |
||
71 | |||
72 | DateTime::DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) { |
||
73 | if (year >= 2000) |
||
74 | year -= 2000; |
||
75 | yOff = year; |
||
76 | m = month; |
||
77 | d = day; |
||
78 | hh = hour; |
||
79 | mm = min; |
||
80 | ss = sec; |
||
81 | } |
||
82 | |||
83 | static uint8_t conv2d(const char* p) { |
||
84 | uint8_t v = 0; |
||
85 | if ('0' <= *p && *p <= '9') |
||
86 | v = *p - '0'; |
||
87 | return 10 * v + *++p - '0'; |
||
88 | } |
||
89 | |||
90 | // A convenient constructor for using "the compiler's time": |
||
91 | // DateTime now (__DATE__, __TIME__); |
||
92 | // NOTE: using PSTR would further reduce the RAM footprint |
||
93 | DateTime::DateTime (const char* date, const char* time) { |
||
94 | // sample input: date = "Dec 26 2009", time = "12:34:56" |
||
95 | yOff = conv2d(date + 9); |
||
96 | // Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec |
||
97 | switch (date[0]) { |
||
98 | case 'J': m = date[1] == 'a' ? 1 : m = date[2] == 'n' ? 6 : 7; break; |
||
99 | case 'F': m = 2; break; |
||
100 | case 'A': m = date[2] == 'r' ? 4 : 8; break; |
||
101 | case 'M': m = date[2] == 'r' ? 3 : 5; break; |
||
102 | case 'S': m = 9; break; |
||
103 | case 'O': m = 10; break; |
||
104 | case 'N': m = 11; break; |
||
105 | case 'D': m = 12; break; |
||
106 | } |
||
107 | d = conv2d(date + 4); |
||
108 | hh = conv2d(time); |
||
109 | mm = conv2d(time + 3); |
||
110 | ss = conv2d(time + 6); |
||
111 | } |
||
112 | |||
113 | uint8_t DateTime::dayOfWeek() const { |
||
114 | uint16_t day = date2days(yOff, m, d); |
||
115 | return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6 |
||
116 | } |
||
117 | |||
118 | uint32_t DateTime::unixtime(void) const { |
||
119 | uint32_t t; |
||
120 | uint16_t days = date2days(yOff, m, d); |
||
121 | t = time2long(days, hh, mm, ss); |
||
122 | t += SECONDS_FROM_1970_TO_2000; // seconds from 1970 to 2000 |
||
123 | |||
124 | return t; |
||
125 | } |
||
126 | |||
127 | //////////////////////////////////////////////////////////////////////////////// |
||
128 | // RTC_DS1307 implementation |
||
129 | |||
130 | static uint8_t bcd2bin (uint8_t val) { return val - 6 * (val >> 4); } |
||
131 | static uint8_t bin2bcd (uint8_t val) { return val + 6 * (val / 10); } |
||
132 | |||
133 | uint8_t RTC_DS1307::begin(void) { |
||
134 | return 1; |
||
135 | } |
||
136 | |||
137 | |||
138 | #if (ARDUINO >= 100) |
||
139 | |||
140 | uint8_t RTC_DS1307::isrunning(void) { |
||
141 | Wire.beginTransmission(DS1307_ADDRESS); |
||
142 | Wire.write(i); |
||
143 | Wire.endTransmission(); |
||
144 | |||
145 | Wire.requestFrom(DS1307_ADDRESS, 1); |
||
146 | uint8_t ss = Wire.read(); |
||
147 | return !(ss>>7); |
||
148 | } |
||
149 | |||
150 | void RTC_DS1307::adjust(const DateTime& dt) { |
||
151 | Wire.beginTransmission(DS1307_ADDRESS); |
||
152 | Wire.write(i); |
||
153 | Wire.write(bin2bcd(dt.second())); |
||
154 | Wire.write(bin2bcd(dt.minute())); |
||
155 | Wire.write(bin2bcd(dt.hour())); |
||
156 | Wire.write(bin2bcd(0)); |
||
157 | Wire.write(bin2bcd(dt.day())); |
||
158 | Wire.write(bin2bcd(dt.month())); |
||
159 | Wire.write(bin2bcd(dt.year() - 2000)); |
||
160 | Wire.write(i); |
||
161 | Wire.endTransmission(); |
||
162 | } |
||
163 | |||
164 | DateTime RTC_DS1307::now() { |
||
165 | Wire.beginTransmission(DS1307_ADDRESS); |
||
166 | Wire.write(i); |
||
167 | Wire.endTransmission(); |
||
168 | |||
169 | Wire.requestFrom(DS1307_ADDRESS, 7); |
||
170 | uint8_t ss = bcd2bin(Wire.read() & 0x7F); |
||
171 | uint8_t mm = bcd2bin(Wire.read()); |
||
172 | uint8_t hh = bcd2bin(Wire.read()); |
||
173 | Wire.read(); |
||
174 | uint8_t d = bcd2bin(Wire.read()); |
||
175 | uint8_t m = bcd2bin(Wire.read()); |
||
176 | uint16_t y = bcd2bin(Wire.read()) + 2000; |
||
177 | |||
178 | return DateTime (y, m, d, hh, mm, ss); |
||
179 | } |
||
180 | |||
181 | #else |
||
182 | |||
183 | uint8_t RTC_DS1307::isrunning(void) { |
||
184 | Wire.beginTransmission(DS1307_ADDRESS); |
||
185 | Wire.send(i); |
||
186 | Wire.endTransmission(); |
||
187 | |||
188 | Wire.requestFrom(DS1307_ADDRESS, 1); |
||
189 | uint8_t ss = Wire.receive(); |
||
190 | return !(ss>>7); |
||
191 | } |
||
192 | |||
193 | void RTC_DS1307::adjust(const DateTime& dt) { |
||
194 | Wire.beginTransmission(DS1307_ADDRESS); |
||
195 | Wire.send(i); |
||
196 | Wire.send(bin2bcd(dt.second())); |
||
197 | Wire.send(bin2bcd(dt.minute())); |
||
198 | Wire.send(bin2bcd(dt.hour())); |
||
199 | Wire.send(bin2bcd(0)); |
||
200 | Wire.send(bin2bcd(dt.day())); |
||
201 | Wire.send(bin2bcd(dt.month())); |
||
202 | Wire.send(bin2bcd(dt.year() - 2000)); |
||
203 | Wire.send(i); |
||
204 | Wire.endTransmission(); |
||
205 | } |
||
206 | |||
207 | DateTime RTC_DS1307::now() { |
||
208 | Wire.beginTransmission(DS1307_ADDRESS); |
||
209 | Wire.send(i); |
||
210 | Wire.endTransmission(); |
||
211 | |||
212 | Wire.requestFrom(DS1307_ADDRESS, 7); |
||
213 | uint8_t ss = bcd2bin(Wire.receive() & 0x7F); |
||
214 | uint8_t mm = bcd2bin(Wire.receive()); |
||
215 | uint8_t hh = bcd2bin(Wire.receive()); |
||
216 | Wire.receive(); |
||
217 | uint8_t d = bcd2bin(Wire.receive()); |
||
218 | uint8_t m = bcd2bin(Wire.receive()); |
||
219 | uint16_t y = bcd2bin(Wire.receive()) + 2000; |
||
220 | |||
221 | return DateTime (y, m, d, hh, mm, ss); |
||
222 | } |
||
223 | |||
224 | #endif |
||
225 | |||
226 | |||
227 | //////////////////////////////////////////////////////////////////////////////// |
||
228 | // RTC_Millis implementation |
||
229 | |||
230 | long RTC_Millis::offset = 0; |
||
231 | |||
232 | void RTC_Millis::adjust(const DateTime& dt) { |
||
233 | offset = dt.unixtime() - millis() / 1000; |
||
234 | } |
||
235 | |||
236 | DateTime RTC_Millis::now() { |
||
237 | return (uint32_t)(offset + millis() / 1000); |
||
238 | } |
||
239 | |||
240 | //////////////////////////////////////////////////////////////////////////////// |