user82213: How do I prevent an alarm, which checks if the current time matches an alarm time in hours and minutes, from going more than once within one minute?
I am using the DS3231 RTC module and RTClib from adafruit. I want to check if the current time equals to the alarm time, then set the alarmFlag variable. I want to clear alarmFlag when a button on pin D5 is pressed.
The code below works fine as long as I don't press the button within about a minute from the start of the alarm. If I press the button within about a minute from the start of the alarm, the alarmFlag will be 0 for one loop() cycle, but then (almost immediately, I don't have much in loop()) will be back to 1. I want for the button to stop the alarm completely, so it fires again only on the next day.
uint8_t alarm[2] = {19, 30}; // hour (24), minute

// other code ...

void loop() {

  currTime = rtc.now();

  // check if current time matches alarm time
  // if it matches, it matches for a whole minute, which is the problem here
  if (!alarmFlag && alarm[0] == currTime.hour() && alarm[1] == currTime.minute()) {
    alarmFlag = true;    
  }

  // clear alarmFlag on button press (this is a shortened version, excuse the lack of debouncing/other stuff)
  if (digitalRead(5) == HIGH) {
    alarmFlag = false;
  }

} 

Notes:

I can not use the RTC's built-in alarms because I need them elsewhere.
I don't want to just add currTime.seconds() == 0 to the first if statement, because that would skip the alarm if the loop() cycle takes more than a second.
I know that the way I detect a button press in the example code is suboptimal, I wrote a better way to deal with this in my main code, but I don't want to clutter up this question.


user7508: As suggested by the busybee, this is a textbook application of the
concept of finite state machine. Below is a state diagram that
hopefully captures the desired behavior. Its meaning is hopefully
obvious at first sight.

Here your alarmFlag is replaced by the TRIGGERED state. Please note
that, with this state machine, the only way to turn the alarm off is to
press the button. If nobody is there to press it, is goes on forever.
This kind of issue is quite obvious when looking at the state diagram,
less so when looking at the code. This is why it is advisable to draw a
state diagram before you start coding. If this behavior is a not
desirable, you may add an extra transition out of the TRIGGERED state,
which would happen on a timeout.
It is also worth noting that, with this state machine, pressing the
button multiple times in quick succession has the same effect as
pressing it once. In other words, there is no point in debouncing the
button.
For implementing this in C++, I suggest you follow the steps of this
tutorial on finite state machines.

82213: <h3>How do I prevent an alarm, which checks if the current time matches an alarm time in hours and minutes, from going more than once within one minute?</h3>
<p>I am using the DS3231 RTC module and RTClib from adafruit. I want to check if the current time equals to the alarm time, then set the <code>alarmFlag</code> variable. I want to clear <code>alarmFlag</code> when a button on pin D5 is pressed.</p>
<p>The code below works fine as long as I don't press the button within about a minute from the start of the alarm. If I press the button within about a minute from the start of the alarm, the alarmFlag will be 0 for one <code>loop()</code> cycle, but then (almost immediately, I don't have much in <code>loop()</code>) will be back to 1. I want for the button to stop the alarm completely, so it fires again only on the next day.</p>
<pre><code>uint8_t alarm[2] = {19, 30}; // hour (24), minute

// other code ...

void loop() {

  currTime = rtc.now();

  // check if current time matches alarm time
  // if it matches, it matches for a whole minute, which is the problem here
  if (!alarmFlag &amp;&amp; alarm[0] == currTime.hour() &amp;&amp; alarm[1] == currTime.minute()) {
    alarmFlag = true;    
  }

  // clear alarmFlag on button press (this is a shortened version, excuse the lack of debouncing/other stuff)
  if (digitalRead(5) == HIGH) {
    alarmFlag = false;
  }

} 
</code></pre>
<p>Notes:</p>
<ol>
<li>I can not use the RTC's built-in alarms because I need them elsewhere.</li>
<li>I don't want to just add <code>currTime.seconds() == 0</code> to the first <code>if</code> statement, because that would skip the alarm if the <code>loop()</code> cycle takes more than a second.</li>
<li>I know that the way I detect a button press in the example code is suboptimal, I wrote a better way to deal with this in my main code, but I don't want to clutter up this question.</li>
</ol>
 7508: <p>As suggested by the busybee, this is a textbook application of the
concept of <a href="https://en.wikipedia.org/wiki/Finite-state_machine" rel="nofollow noreferrer">finite state machine</a>. Below is a state diagram that
hopefully captures the desired behavior. Its meaning is hopefully
obvious at first sight.</p>
<p><a href="https://i.stack.imgur.com/AQu5b.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/AQu5b.png" alt="State diagram" /></a></p>
<p>Here your <code>alarmFlag</code> is replaced by the <code>TRIGGERED</code> state. Please note
that, with this state machine, the only way to turn the alarm off is to
press the button. If nobody is there to press it, is goes on forever.
This kind of issue is quite obvious when looking at the state diagram,
less so when looking at the code. This is why it is advisable to draw a
state diagram before you start coding. If this behavior is a not
desirable, you may add an extra transition out of the <code>TRIGGERED</code> state,
which would happen on a timeout.</p>
<p>It is also worth noting that, with this state machine, pressing the
button multiple times in quick succession has the same effect as
pressing it once. In other words, there is no point in debouncing the
button.</p>
<p>For implementing this in C++, I suggest you follow the steps of <a href="https://majenko.co.uk/blog/finite-state-machine" rel="nofollow noreferrer">this
tutorial on finite state machines</a>.</p>
