-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrtc.cpp
358 lines (302 loc) · 10.6 KB
/
rtc.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
#include "Wire.h" // Needed for I2C bus
#include "globals.h"
#include <Arduino.h>
#include <String.h>
extern byte iCount;
extern unsigned long timeStamp;
extern byte tempByte;
extern char inChar;
const String compTimeStr = __TIME__; // Compile timestamp string
const String compDateStr = __DATE__; // Compile datestamp string
// ------------------------------------------------------------------------------
//
// Hardware definitions for A040618 RTC Module Option (see DS3231 datasheet)
//
// ------------------------------------------------------------------------------
#define DS3231_RTC 0x68 // DS3231 I2C address
#define DS3231_SECRG 0x00 // DS3231 Seconds Register
#define DS3231_STATRG 0x0F // DS3231 Status Register
// DS3231 RTC variables
byte foundRTC; // Set to 1 if RTC is found, 0 otherwise
byte seconds, minutes, hours, day, month, year;
byte tempC; // Temperature (Celsius) encoded in two’s complement integer format
const byte daysOfMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// ------------------------------------------------------------------------------
// RTC Module routines
// ------------------------------------------------------------------------------
byte decToBcd(byte val)
// Convert a binary byte to a two digits BCD byte
{
return( (val/10*16) + (val%10) );
}
// ------------------------------------------------------------------------------
byte bcdToDec(byte val)
// Convert binary coded decimal to normal decimal numbers
{
return( (val/16*10) + (val%16) );
}
// ------------------------------------------------------------------------------
void readRTC(byte *second, byte *minute, byte *hour, byte *day, byte *month, byte *year, byte *tempC)
// Read current date/time binary values and the temprerature (2 complement) from the DS3231 RTC
{
Wire.beginTransmission(DS3231_RTC);
Wire.write(DS3231_SECRG); // Set the DS3231 Seconds Register
Wire.endTransmission();
// Read from RTC and convert to binary
Wire.requestFrom(DS3231_RTC, 18);
*second = bcdToDec(Wire.read() & 0x7f);
*minute = bcdToDec(Wire.read());
*hour = bcdToDec(Wire.read() & 0x3f);
Wire.read(); // Jump over the DoW
*day = bcdToDec(Wire.read());
*month = bcdToDec(Wire.read());
*year = bcdToDec(Wire.read());
for (iCount = 0; iCount < 10; iCount++) Wire.read(); // Jump over 10 registers
*tempC = Wire.read();
}
// ------------------------------------------------------------------------------
void writeRTC(byte second, byte minute, byte hour, byte day, byte month, byte year)
// Write given date/time binary values to the DS3231 RTC
{
Wire.beginTransmission(DS3231_RTC);
Wire.write(DS3231_SECRG); // Set the DS3231 Seconds Register
Wire.write(decToBcd(seconds));
Wire.write(decToBcd(minutes));
Wire.write(decToBcd(hours));
Wire.write(1); // Day of week not used (always set to 1 = Sunday)
Wire.write(decToBcd(day));
Wire.write(decToBcd(month));
Wire.write(decToBcd(year));
Wire.endTransmission();
}
// ------------------------------------------------------------------------------
void print2digit(byte data)
// Print a byte [0..99] using 2 digit with leading zeros if needed
{
if (data < 10) Serial.print("0");
Serial.print(data);
}
void printDateTime(byte readSourceFlag)
// Print to serial the current date/time from the global variables.
//
// Flag readSourceFlag [0..1] usage:
// If readSourceFlag = 0 the RTC read is not done
// If readSourceFlag = 1 the RTC read is done (global variables are updated)
{
if (readSourceFlag) readRTC(&seconds, &minutes, &hours, &day, &month, &year, &tempC);
print2digit(day);
Serial.print("/");
print2digit(month);
Serial.print("/");
print2digit(year);
Serial.print(" ");
print2digit(hours);
Serial.print(":");
print2digit(minutes);
Serial.print(":");
print2digit(seconds);
}
byte autoSetRTC()
// Check if the DS3231 RTC is present and set the date/time at compile date/time if
// the RTC "Oscillator Stop Flag" is set (= date/time failure).
// Return value: 0 if RTC not present, 1 if found.
{
byte OscStopFlag;
Wire.beginTransmission(DS3231_RTC);
if (Wire.endTransmission() != 0) return 0; // RTC not found
Serial.print("IOS: Found RTC DS3231 Module (");
printDateTime(1);
Serial.println(")");
// Print the temperaturefrom the RTC sensor
Serial.print("IOS: RTC DS3231 temperature sensor: ");
Serial.print((int8_t)tempC);
Serial.println("C");
// Read the "Oscillator Stop Flag"
Wire.beginTransmission(DS3231_RTC);
Wire.write(DS3231_STATRG); // Set the DS3231 Status Register
Wire.endTransmission();
Wire.requestFrom(DS3231_RTC, 1);
OscStopFlag = Wire.read() & 0x80; // Read the "Oscillator Stop Flag"
if (OscStopFlag)
// RTC oscillator stopped. RTC must be set at compile date/time
{
// Convert compile time strings to numeric values
seconds = compTimeStr.substring(6,8).toInt();
minutes = compTimeStr.substring(3,5).toInt();
hours = compTimeStr.substring(0,2).toInt();
day = compDateStr.substring(4,6).toInt();
switch (compDateStr[0])
{
case 'J': month = compDateStr[1] == 'a' ? 1 : month = compDateStr[2] == 'n' ? 6 : 7; break;
case 'F': month = 2; break;
case 'A': month = compDateStr[2] == 'r' ? 4 : 8; break;
case 'M': month = compDateStr[2] == 'r' ? 3 : 5; break;
case 'S': month = 9; break;
case 'O': month = 10; break;
case 'N': month = 11; break;
case 'D': month = 12; break;
};
year = compDateStr.substring(9,11).toInt();
// Ask for RTC setting al compile date/time
Serial.println("IOS: RTC clock failure!");
Serial.print("\nDo you want set RTC at IOS compile time (");
printDateTime(0);
Serial.print(")? [Y/N] >");
timeStamp = millis();
do
{
blinkIOSled(&timeStamp);
inChar = Serial.read();
}
while ((inChar != 'y') && (inChar != 'Y') && (inChar != 'n') &&(inChar != 'N'));
Serial.println(inChar);
// Set the RTC at the compile date/time and print a message
if ((inChar == 'y') || (inChar == 'Y'))
{
writeRTC(seconds, minutes, hours, day, month, year);
Serial.print("IOS: RTC set at compile time - Now: ");
printDateTime(1);
Serial.println();
}
// Reset the "Oscillator Stop Flag"
Wire.beginTransmission(DS3231_RTC);
Wire.write(DS3231_STATRG); // Set the DS3231 Status Register
Wire.write(0x08); // Reset the "Oscillator Stop Flag" (32KHz output left enabled)
Wire.endTransmission();
}
return 1;
}
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
byte isLeapYear(byte yearXX)
// Check if the year 2000+XX (where XX is the argument yearXX [00..99]) is a leap year.
// Returns 1 if it is leap, 0 otherwise.
// This function works in the [2000..2099] years range. It should be enough...
{
if (((2000 + yearXX) % 4) == 0) return 1;
else return 0;
}
// ------------------------------------------------------------------------------
void ChangeRTC()
// Change manually the RTC Date/Time from keyboard
{
byte leapYear; // Set to 1 if the selected year is bissextile, 0 otherwise [0..1]
// Read RTC
readRTC(&seconds, &minutes, &hours, &day, &month, &year, &tempC);
// Change RTC date/time from keyboard
tempByte = 0;
Serial.println("\nIOS: RTC manual setting:");
Serial.println("\nPress T/U to increment +10/+1 or CR to accept");
do
{
do
{
Serial.print(" ");
switch (tempByte)
{
case 0:
Serial.print("Year -> ");
print2digit(year);
break;
case 1:
Serial.print("Month -> ");
print2digit(month);
break;
case 2:
Serial.print(" ");
Serial.write(13);
Serial.print(" Day -> ");
print2digit(day);
break;
case 3:
Serial.print("Hours -> ");
print2digit(hours);
break;
case 4:
Serial.print("Minutes -> ");
print2digit(minutes);
break;
case 5:
Serial.print("Seconds -> ");
print2digit(seconds);
break;
}
timeStamp = millis();
do
{
blinkIOSled(&timeStamp);
inChar = Serial.read();
}
while ((inChar != 'u') && (inChar != 'U') && (inChar != 't') && (inChar != 'T') && (inChar != 13));
if ((inChar == 'u') || (inChar == 'U'))
// Change units
switch (tempByte)
{
case 0:
year++;
if (year > 99) year = 0;
break;
case 1:
month++;
if (month > 12) month = 1;
break;
case 2:
day++;
if (day > (daysOfMonth[month - 1] + isLeapYear(year))) day = 1;
break;
case 3:
hours++;
if (hours > 23) hours = 0;
break;
case 4:
minutes++;
if (minutes > 59) minutes = 0;
break;
case 5:
seconds++;
if (seconds > 59) seconds = 0;
break;
}
if ((inChar == 't') || (inChar == 'T'))
// Change tens
switch (tempByte)
{
case 0:
year = year + 10;
if (year > 99) year = year - (year / 10) * 10;
break;
case 1:
if (month > 10) month = month - 10;
else if (month < 3) month = month + 10;
break;
case 2:
day = day + 10;
if (day > (daysOfMonth[month - 1] + isLeapYear(year))) day = day - (day / 10) * 10;
if (day == 0) day = 1;
break;
case 3:
hours = hours + 10;
if (hours > 23) hours = hours - (hours / 10 ) * 10;
break;
case 4:
minutes = minutes + 10;
if (minutes > 59) minutes = minutes - (minutes / 10 ) * 10;
break;
case 5:
seconds = seconds + 10;
if (seconds > 59) seconds = seconds - (seconds / 10 ) * 10;
break;
}
Serial.write(13);
}
while (inChar != 13);
tempByte++;
}
while (tempByte < 6);
// Write new date/time into the RTC
writeRTC(seconds, minutes, hours, day, month, year);
Serial.println(" ...done ");
Serial.print("IOS: RTC date/time updated (");
printDateTime(1);
Serial.println(")");
}