-
Notifications
You must be signed in to change notification settings - Fork 83
Expand file tree
/
Copy pathAdvanceAlarm.ino
More file actions
167 lines (131 loc) · 4.74 KB
/
AdvanceAlarm.ino
File metadata and controls
167 lines (131 loc) · 4.74 KB
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
/*
AdvanceAlarm.ino
David Sparks Sept 2022
Example of advancing an alarm by an arbitrary interval of time.
Hardware setup:
Connect DS3231 SQW pin to Arduino interrupt pin 2
Builds upon ArduinoInterrupt.ino example by
Jacob Nuernberg August 2022
Example on using recurring interrupts
of arbitrary frequency with DS3231 alarms.
Hardware setup:
Connect DS3231 SQW pin to Arduino interrupt pin 2
Tested on:
- Arduino Nano (ATmega328P)
*/
#include <DS3231.h>
#include <Wire.h>
// Interrupt frequency, in seconds
#define INT_FREQ 3UL // 3 seconds, characterized as unsigned long
// myRTC interrupt pin
#define CLINT 2
// Setup clock
DS3231 myRTC;
// Variables for use in method parameter lists
byte alarmDay;
byte alarmHour;
byte alarmMinute;
byte alarmSecond;
byte alarmBits;
bool alarmDayIsDay;
bool alarmH12;
bool alarmPM;
// Interrupt signaling byte
volatile byte tick = 1;
void setup() {
// Begin I2C communication
Wire.begin();
// Begin Serial communication
Serial.begin(9600);
while (!Serial);
// Set the DS3231 clock mode to 24-hour
myRTC.setClockMode(false); // false = not using the alternate, 12-hour mode
// Set the clock to an arbitrarily chosen time of
// 00:00:00 midnight the morning of January 1, 2020
// using a suitable Unix-style timestamp
myRTC.setEpoch(1640995200);
// Assign parameter values for Alarm 1
alarmDay = myRTC.getDate();
alarmHour = myRTC.getHour(alarmH12, alarmPM);
alarmMinute = myRTC.getMinute();
alarmSecond = INT_FREQ; // initialize to the interval length
alarmBits = 0b00001110; // Alarm 1 when seconds match
alarmDayIsDay = false; // using date of month
// Upload initial parameters of Alarm 1
myRTC.turnOffAlarm(1);
myRTC.setA1Time(
alarmDay, alarmHour, alarmMinute, alarmSecond,
alarmBits, alarmDayIsDay, alarmH12, alarmPM);
// clear Alarm 1 flag after setting the alarm time
myRTC.checkIfAlarm(1);
// now it is safe to enable interrupt output
myRTC.turnOnAlarm(1);
// When using interrupt with only one of the DS3231 alarms, as in this example,
// it may be possible to prevent the other alarm entirely,
// so it will not covertly block the outgoing interrupt signal.
// Try to prevent Alarm 2 altogether by assigning a
// nonsensical alarm minute value that cannot match the clock time,
// and an alarmBits value to activate "when minutes match".
alarmMinute = 0xFF; // a value that will never match the time
alarmBits = 0b01100000; // Alarm 2 when minutes match, i.e., never
// Upload the parameters to prevent Alarm 2 entirely
myRTC.setA2Time(
alarmDay, alarmHour, alarmMinute,
alarmBits, alarmDayIsDay, alarmH12, alarmPM);
// disable Alarm 2 interrupt
myRTC.turnOffAlarm(2);
// clear Alarm 2 flag
myRTC.checkIfAlarm(2);
// NOTE: both of the alarm flags must be clear
// to enable output of a FALLING interrupt
// attach clock interrupt
pinMode(CLINT, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(CLINT), isr_TickTock, FALLING);
// Configure the LED for blinking
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
// static variable to keep track of LED on/off state
static byte state = false;
// Do when alarm interrupt received:
if (tick) {
// right away, capture the current time in a DateTime variable
// for later processing
DateTime alarmDT = RTClib::now();
// disable Alarm 1 interrupt
myRTC.turnOffAlarm(1);
// Clear Alarm 1 flag
myRTC.checkIfAlarm(1);
tick = 0; // reset the local interrupt-received flag
state = ~state; // reverse the state of the LED
digitalWrite(LED_BUILTIN, state);
// optional serial output
Serial.print("Turning LED ");
Serial.print((state ? "ON" : "OFF"));
Serial.print(" at ");
Serial.print(alarmDT.hour());
Serial.print(":");
Serial.print(alarmDT.minute());
Serial.print(":");
Serial.println(alarmDT.second());
// extract the DateTime values as a timestamp
uint32_t nextAlarm = alarmDT.unixtime();
// add the INT_FREQ number of seconds
nextAlarm += INT_FREQ;
// update the DateTime with the new timestamp
alarmDT = DateTime(nextAlarm);
// upload the new time to Alarm 1
myRTC.setA1Time(
alarmDT.day(), alarmDT.hour(), alarmDT.minute(), alarmDT.second(),
alarmBits, alarmDayIsDay, alarmH12, alarmPM);
// enable Alarm 1 interrupts
myRTC.turnOnAlarm(1);
// clear Alarm 1 flag again after enabling interrupts
myRTC.checkIfAlarm(1);
}
}
void isr_TickTock() {
// interrupt signals to loop
tick = 1;
return;
}