Subversion Repositories idreammicro-arduino

Rev

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
////////////////////////////////////////////////////////////////////////////////