using sleep mode and IRremote

I am using a Promini 16MHz clone with IRremote library and sleep mode.

I had some problems, which I posted herehttps://forum.arduino.cc/index.php?topic=620127.new#new

There were no replies from the forum, but I found a workaround and posted that code as also included below.

Sometimes, the Promini does not wake from sleep. About 10% of the time. It will stay in sleep overnight and wake, but then at other odd intervals it will fail to wake up. The signal from the PIR is always working fine to generate the necessary LOW on the wake from sleep pin.

I am using a battery pack with AA cells and wonder if the electrical contacts lose connection at the low current consumed in sleep mode. Less than 1mA, mainly for the IR sensor.
I have cleaned them all up and hardwired the pack to the Promini, no change in the reliability to wake from sleep.

Or is it possible that the issue is the IRremote library is a bit touchy about being used with sleep mode?
Is there a way to turn off the IRremote Timer-driven interrupt polling part of the library code, within the sketch itself, before sleep is enabled? Then turn it back on?

Many thanks if any suggestions or thoughts on this.

[code]
#include <avr/interrupt.h>
#include <avr/power.h>
#include <avr/sleep.h>
#include <IRremote.h>

const int RECV_PIN = 7;
IRrecv irrecv(RECV_PIN);
decode_results results;
unsigned long previousMillis = 0;
unsigned long interval = 10000;

void motorcw(void) {
  digitalWrite(6, LOW); //activate motor
  for (int x = 1; x <= 2; x++) //slow flash diagnostic indicator
  { //digitalWrite(13,HIGH);
    delay(250);
    //digitalWrite(13,LOW);
    delay(250);
  }
  digitalWrite(6, HIGH);
} //de-activate motor

void motorccw(void) {
  digitalWrite(8, LOW); //activate motor
  for (int x = 1; x <= 4; x++) //fast flash diagnostic indicator
  { digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13, LOW);
    delay(100);
  }
  digitalWrite(8, HIGH);
} //de-activate motor

void motorstop(void) {
}//no code here yet!

void sleepNow(void) {
  digitalWrite(13, LOW);
  // Set pin 2 as interrupt and attach handler:
  attachInterrupt(0, pinInterrupt, LOW);
  delay(100);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  // Set sleep enable (SE) bit:
  sleep_enable();
  sleep_mode();
  // Upon waking up, sketch continues from this point.
  sleep_disable();
}

void pinInterrupt(void) {
  detachInterrupt(0);
}

void setup()
{
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
  irrecv.enableIRIn();
  //    irrecv.blink13(true);
  //    Serial.begin(9600);
}

void loop()
{
  digitalWrite(13, HIGH);//to indicate awake from sleep
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;
    sleepNow();
  }
  checkirforkey();
}

void checkirforkey (void)
{
  if (irrecv.decode(&results)) {
    if (results.value == 0x52A3D41F) {
      //Keypad button "4"
      //    Serial.print(" decode: ");
      //    Serial.println(results.value, HEX);
      motorcw();
    }

    if (results.value == 0x20FE4DBB) {
      //Keypad button "6"
      //      Serial.print(" decode: ");
      //      Serial.println(results.value, HEX);
      motorccw();
    }
    if (results.value == 0xD7E84B1B) {
      motorstop();
    }
    if (results.value == 0x00) {
      return;
    }
    irrecv.resume();
  }
}

[/code]

So what happens your PIR is active (LOW) when you try to go to sleep?

You will call call sleepNow() and attach the interrupt. It will immediately get called (since PIR is LOW) which will detach the interrupt and then you go to sleep, never to wake again...

I think you might want the interrupt do trigger on a falling edge, rather than a low state.

If you have the IR sensor connected as implied here:

const int RECV_PIN = 7;
IRrecv irrecv(RECV_PIN);

and you are expecting the device to wake up on an external interrupt:

 // Set pin 2 as interrupt and attach handler:
  attachInterrupt(0, pinInterrupt, LOW);

What have you got connected to pin 2 ?

I can see your point - many thanks blh64 - yes indeed what if PIR on Pin 2 interrupt is already LOW!
The same thing could happen with a simple button.

Which it will be if someone is moving around, with or without a remote.
Result of an experiment = If I remain perfectly still, sleep mode can be recovered from 100%.
The IRremote library being used in conjunction is not responsible.

'In all but the IDLE sleep modes only LOW can be used.' -from answers on this forum and SE.
But I have seen some tutorials which show using falling/rising/change with sleep mode.

I have turned logic output switch states with cmos into transient triggers using a capacitor+diode+resistor coupling. However that doesn't solve the problem that the PIR will retrigger on detecting any movement.

Use a capacitor/resistors and diode, or capacitor/resistors, to get a (much) shorter LOW pulse.

'The external interrupt signal must be long enough to be detected by the sleeping controller and shorter than the time duration of the Interrupt Service Routine. When the signal is too short no interrupt is detected. When too long more than one interrupt is created by one single pulse on the interrupt line.'

Many thanks, Nick Gammon,blh64 and all the other contributors I looked at.
I must have been just lucky when using PIR to wake from sleep in previous projects. Very narrow angle detection, people leaving area before arduino entered sleep mode etc.

If of any use to anyone, I used the circuit in the url link. 2k2 for R1, 2M2 for R2 and 2n2 uF for C1.
(After a bc109 as open collector signal inverter.)

Here is the attached final reliable working code.

turretremote10.ino (2.32 KB)