user88533: I've written code for an Arduino Nano that when a button is pressed, it sends an IR command. It is set so that if no button press has been received for a period of 10 seconds, it will enter sleep mode until a button press is received. The button to send the IR command is the same button being used to send the wake up interrupt (button connected to pin D2). When testing the code the Arduino is able to go to sleep and wake up from the interrupt 1-3 times before it will suddenly receive an interrupt signal just before entering sleep mode. When this happens it gets stuck in sleep mode and will no longer accept the wake up interrupt. I am currently using Serial Monitor outputs and the built-in LED to determine when the Arduino is in sleep mode or not.
#include <IRLib.h>
#include <avr/sleep.h>
#define interruptPin 2

IRsend My_Sender;

const int button = 2;
int buttonState = 0;
int timeSinceCommand = 0;
const unsigned long eventInterval = 1000;
unsigned long previousTime = 0;

void setup() {
  Serial.begin(9600);
  pinMode(button, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);         //delete once code finalized and working
  pinMode(interruptPin, INPUT_PULLUP);
  digitalWrite(LED_BUILTIN, HIGH);      //delete once code finalized and working
  Serial.println("---------------------------New Run---------------------------");
}

void loop() {
  while (timeSinceCommand < 10) {
    unsigned long currentTime = millis();
    buttonState = digitalRead(button);
    if (buttonState == HIGH) {
      My_Sender.send(SONY, 0xC90, 12);
      timeSinceCommand = 0;
      previousTime = currentTime;
    }
    if (currentTime - previousTime >= eventInterval) {
      timeSinceCommand++;
      previousTime = currentTime;
    }
  }
  if (timeSinceCommand >= 10) {
    Going_To_Sleep();
    timeSinceCommand = 0;
  }
}

void Going_To_Sleep() {
  sleep_enable();
  attachInterrupt(0, wakeUp, RISING);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  digitalWrite(LED_BUILTIN, LOW);             //delete once code finalized and working
  Serial.println("Arudino going to sleep!");  //delete once code finalized and working
  delay(1000);                                //delete once code finalized and working
  sleep_cpu();
  Serial.println("Arudino has waken up!");    //delete once code finalized and working
  digitalWrite(LED_BUILTIN, HIGH);            //delete once code finalized and working
}

void wakeUp() {
  Serial.println("Interrupt received!");      //delete once code finalized and working
  sleep_disable();
  detachInterrupt(0);
}

Here is the Serial Monitor output from a couple of tests:
---------------------------New Run---------------------------
Arudino going to sleep!
Interrupt received!
Arudino has waken up!
Arudino going to sleep!
Interrupt received!
Arudino has waken up!
Interrupt received!
Arudino going to sleep!
---------------------------New Run---------------------------
Arudino going to sleep!
Interrupt received!
Arudino has waken up!
Interrupt received!
Arudino going to sleep!


user31043: I'm taking this opportunity to include a simple basic sleep sketch which eliminates the possible race condition risk that Edgar Bonet identified in the standard approach to using the sleep mode for AVR class MCUs. See the reference in the sketch to further optimise, if required, to switch off the ADC, Brown out detection etc.
/*
   Sleep mode demonstration (Uno/Nano ATmega328P)
   based on https://www.gammon.com.au/power Sketch J 
   but stripped down for demonstration purposes to exclude some optimisation (BOD and ADC etc.)
   See also: https://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html

   Connect a button switch between pin 2 and ground
   Press the button. It wakes, blinks the led and then sleeps.

*/

#include <avr/sleep.h>

const byte LED = 13;  // built in led

void wake()
{
  // nothing here. All done in the loop
}

void setup()
{
  Serial.begin( 115200 ) ;
  pinMode( LED, OUTPUT );
  pinMode( 2, INPUT_PULLUP ) ; 
  attachInterrupt ( digitalPinToInterrupt(2), wake, FALLING);
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
}

void loop()
{
  Serial.println( "waking . . . ") ;

  // your own code could go here instead 

  for ( int i = 0; i < 4; i++ ) {
    digitalWrite (LED, HIGH);
    delay (50);
    digitalWrite (LED, LOW);
    delay (50);
  }
  delay(3000) ;
  

  Serial.println( "Sleeping. . . " ) ;
  Serial.flush() ;
  delay(20) ; // allow message to be written

  sleep_mode();
  // *** we wake here ***
}


user7508: There are a couple of tricky things going on here... First, you should
be aware of a few facts:

Buttons are prone to mechanical bounce. You press a button once, and
quite often the microcontroller senses multiple transitions on the
input pin.

When INT0 is configured to sense rising edges, any rising edge on the
pin will set the INTF0 interrupt flag, whether the interrupt is
enabled or not. Once the flag is set, it will fire an interrupt
request as soon as the interrupt is enabled.

When the CPU receives an interrupt request, it finishes executing the
current instruction before servicing the request.


With that in mind, here is an explanation of what goes on:
When you wake up the Arduino with the push button, it often triggers
multiple signal transitions. The first rising edge wakes up the Arduino
and triggers the interrupt. The second rising edge only sets the INTF0
interrupt flag: the interrupt is “on hold”, because interrupts are not
themselves interruptible. However, before exiting, wakeUp() disables
servicing that interrupt, which means the flags just stays set. It is a
pending interrupt of sorts.
Some time later, Going_To_Sleep() is called again. attachInterrupt()
enables the interrupt and, since the flag is still set, the (pending)
interrupt fires immediately. That's when you see the message “Interrupt
received!” printed right before the Arduino goes to sleep. The problem
is that the interrupt is disabled by wakeUp(). One second later,
sleep_cpu() puts the CPU to sleep, and now our wake-up source is
disabled, so the Arduino is just locked into its dreams.
There is still one issue with this scenario. The interrupt handler
supposedly disabled sleeping, so how come the Arduino went to sleep
anyway? The answer is that sleeping was accidentally re-enabled by
set_sleep_mode() because of a data-race. Here is a disassembly of
set_sleep_mode():
in   r24, 0x33 ; read SMCR (Sleep Mode Control Register) into r24
andi r24, 0xF1 ; clear the Sleep Mode Select bits
ori  r24, 0x04 ; select the Power Down mode
out  0x33, r24 ; write back SMCR

The first instruction in this sequence comes right after the instruction
in attachInterrupt() that enables the INT0 interrupt. When that
instruction generates an interrupt request (because the interrupt flag
was already set), the interrupt request reaches the CPU while it is
already executing the in instruction above, and this instruction is
completed before servicing the interrupt request. This means that we
have now in register r24 a copy of the Sleep Mode Control Register from
before the interrupt is serviced. In this copy, the SE bit (Sleep
Enable) is set. Even though wakeUp() clears that bit in the actual
SMCR register, it stays set in our copy in r24. Then, the out
instruction re-enables sleeping. I experimented putting a single nop
instruction right before set_sleep_mode() and that was enough to
prevent the data race.
So here you have an explanation of the observed behavior. I may come
up with some suggestions for fixing the problem, but it need
to take some sleep before that (do not worry, I will make double sure I
have one interrupt source enabled before executing sleep).

88533: <p>I've written code for an Arduino Nano that when a button is pressed, it sends an IR command. It is set so that if no button press has been received for a period of 10 seconds, it will enter sleep mode until a button press is received. The button to send the IR command is the same button being used to send the wake up interrupt (button connected to pin D2). When testing the code the Arduino is able to go to sleep and wake up from the interrupt 1-3 times before it will suddenly receive an interrupt signal just before entering sleep mode. When this happens it gets stuck in sleep mode and will no longer accept the wake up interrupt. I am currently using Serial Monitor outputs and the built-in LED to determine when the Arduino is in sleep mode or not.</p>
<pre><code>#include &lt;IRLib.h&gt;
#include &lt;avr/sleep.h&gt;
#define interruptPin 2

IRsend My_Sender;

const int button = 2;
int buttonState = 0;
int timeSinceCommand = 0;
const unsigned long eventInterval = 1000;
unsigned long previousTime = 0;

void setup() {
  Serial.begin(9600);
  pinMode(button, INPUT);
  pinMode(LED_BUILTIN, OUTPUT);         //delete once code finalized and working
  pinMode(interruptPin, INPUT_PULLUP);
  digitalWrite(LED_BUILTIN, HIGH);      //delete once code finalized and working
  Serial.println(&quot;---------------------------New Run---------------------------&quot;);
}

void loop() {
  while (timeSinceCommand &lt; 10) {
    unsigned long currentTime = millis();
    buttonState = digitalRead(button);
    if (buttonState == HIGH) {
      My_Sender.send(SONY, 0xC90, 12);
      timeSinceCommand = 0;
      previousTime = currentTime;
    }
    if (currentTime - previousTime &gt;= eventInterval) {
      timeSinceCommand++;
      previousTime = currentTime;
    }
  }
  if (timeSinceCommand &gt;= 10) {
    Going_To_Sleep();
    timeSinceCommand = 0;
  }
}

void Going_To_Sleep() {
  sleep_enable();
  attachInterrupt(0, wakeUp, RISING);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  digitalWrite(LED_BUILTIN, LOW);             //delete once code finalized and working
  Serial.println(&quot;Arudino going to sleep!&quot;);  //delete once code finalized and working
  delay(1000);                                //delete once code finalized and working
  sleep_cpu();
  Serial.println(&quot;Arudino has waken up!&quot;);    //delete once code finalized and working
  digitalWrite(LED_BUILTIN, HIGH);            //delete once code finalized and working
}

void wakeUp() {
  Serial.println(&quot;Interrupt received!&quot;);      //delete once code finalized and working
  sleep_disable();
  detachInterrupt(0);
}
</code></pre>
<p>Here is the Serial Monitor output from a couple of tests:</p>
<pre><code>---------------------------New Run---------------------------
Arudino going to sleep!
Interrupt received!
Arudino has waken up!
Arudino going to sleep!
Interrupt received!
Arudino has waken up!
Interrupt received!
Arudino going to sleep!
---------------------------New Run---------------------------
Arudino going to sleep!
Interrupt received!
Arudino has waken up!
Interrupt received!
Arudino going to sleep!
</code></pre>
 31043: <p>I'm taking this opportunity to include a simple basic sleep sketch which eliminates the possible race condition risk that Edgar Bonet identified in the standard approach to using the sleep mode for AVR class MCUs. See the reference in the sketch to further optimise, if required, to switch off the ADC, Brown out detection etc.</p>
<pre><code>/*
   Sleep mode demonstration (Uno/Nano ATmega328P)
   based on https://www.gammon.com.au/power Sketch J 
   but stripped down for demonstration purposes to exclude some optimisation (BOD and ADC etc.)
   See also: https://www.nongnu.org/avr-libc/user-manual/group__avr__sleep.html

   Connect a button switch between pin 2 and ground
   Press the button. It wakes, blinks the led and then sleeps.

*/

#include &lt;avr/sleep.h&gt;

const byte LED = 13;  // built in led

void wake()
{
  // nothing here. All done in the loop
}

void setup()
{
  Serial.begin( 115200 ) ;
  pinMode( LED, OUTPUT );
  pinMode( 2, INPUT_PULLUP ) ; 
  attachInterrupt ( digitalPinToInterrupt(2), wake, FALLING);
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
}

void loop()
{
  Serial.println( &quot;waking . . . &quot;) ;

  // your own code could go here instead 

  for ( int i = 0; i &lt; 4; i++ ) {
    digitalWrite (LED, HIGH);
    delay (50);
    digitalWrite (LED, LOW);
    delay (50);
  }
  delay(3000) ;
  

  Serial.println( &quot;Sleeping. . . &quot; ) ;
  Serial.flush() ;
  delay(20) ; // allow message to be written

  sleep_mode();
  // *** we wake here ***
}
</code></pre>
 7508: <p>There are a couple of tricky things going on here... First, you should
be aware of a few facts:</p>
<ol>
<li><p>Buttons are prone to mechanical bounce. You press a button once, and
quite often the microcontroller senses multiple transitions on the
input pin.</p>
</li>
<li><p>When INT0 is configured to sense rising edges, any rising edge on the
pin will set the INTF0 interrupt flag, <em>whether the interrupt is
enabled or not</em>. Once the flag is set, it will fire an interrupt
request as soon as the interrupt is enabled.</p>
</li>
<li><p>When the CPU receives an interrupt request, it finishes executing the
current instruction before servicing the request.</p>
</li>
</ol>
<p>With that in mind, here is an explanation of what goes on:</p>
<p>When you wake up the Arduino with the push button, it often triggers
multiple signal transitions. The first rising edge wakes up the Arduino
and triggers the interrupt. The second rising edge only sets the INTF0
interrupt flag: the interrupt is “on hold”, because interrupts are not
themselves interruptible. However, before exiting, <code>wakeUp()</code> disables
servicing that interrupt, which means the flags just stays set. It is a
pending interrupt of sorts.</p>
<p>Some time later, <code>Going_To_Sleep()</code> is called again. <code>attachInterrupt()</code>
enables the interrupt and, since the flag is still set, the (pending)
interrupt fires immediately. That's when you see the message “Interrupt
received!” printed right before the Arduino goes to sleep. The problem
is that the interrupt is disabled by <code>wakeUp()</code>. One second later,
<code>sleep_cpu()</code> puts the CPU to sleep, and now our wake-up source is
disabled, so the Arduino is just locked into its dreams.</p>
<p>There is still one issue with this scenario. The interrupt handler
supposedly disabled sleeping, so how come the Arduino went to sleep
anyway? The answer is that sleeping was accidentally re-enabled by
<code>set_sleep_mode()</code> because of a data-race. Here is a disassembly of
<code>set_sleep_mode()</code>:</p>
<pre class="lang-lisp prettyprint-override"><code>in   r24, 0x33 ; read SMCR (Sleep Mode Control Register) into r24
andi r24, 0xF1 ; clear the Sleep Mode Select bits
ori  r24, 0x04 ; select the Power Down mode
out  0x33, r24 ; write back SMCR
</code></pre>
<p>The first instruction in this sequence comes right after the instruction
in <code>attachInterrupt()</code> that enables the INT0 interrupt. When that
instruction generates an interrupt request (because the interrupt flag
was already set), the interrupt request reaches the CPU while it is
already executing the <code>in</code> instruction above, and this instruction is
completed before servicing the interrupt request. This means that we
have now in register r24 a copy of the Sleep Mode Control Register from
before the interrupt is serviced. In this copy, the SE bit (Sleep
Enable) is set. Even though <code>wakeUp()</code> clears that bit in the actual
SMCR register, it stays set in our copy in r24. Then, the <code>out</code>
instruction re-enables sleeping. I experimented putting a single <code>nop</code>
instruction right before <code>set_sleep_mode()</code> and that was enough to
prevent the data race.</p>
<p>So here you have an explanation of the observed behavior. I may come
up with some suggestions for fixing the problem, but it need
to take some sleep before that (do not worry, I will make double sure I
have one interrupt source enabled before executing <code>sleep</code>).</p>
