1

I want to use to use an IR sensor as an interrupt to wake up my Arduino Uno R3 from the deep sleep power mode and then go back to sleep after changing the state of the relay.

Lets say if I press a button on the remote and the relay is on LOW mode, the relay is turned to HIGH mode and vice versa.

#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <IRremote.h>

/* Sleep Demo
------------

int relayPin = 8;            // LED connected to digital pin 13
int irPin = 2;            // active LOW, ground this pin momentary to wake up
int sleepStatus = 0;        // variable to store a request for sleep
volatile byte state = LOW;

IRrecv irrecv(irPin);
decode_results results;

void setup()
{
  pinMode(relayPin, OUTPUT);         // sets the digital pin as output
  pinMode(irPin, INPUT);
  irrecv.enableIRIn(); // Start the receiver

  /* Now is time to enable a interrupt. In the function call
     attachInterrupt(A, B, C)
     A   can be either 0 or 1 for interrupts on pin 2 or 3.

     B   Name of a function you want to execute while in interrupt A.

     C   Trigger mode of the interrupt pin. can be:
                 LOW        a low level trigger
                 CHANGE     a change in level trigger
                 RISING     a rising edge of a level trigger
                 FALLING    a falling edge of a level trigger

     In all but the IDLE sleep modes only LOW can be used.
  */

  attachInterrupt(0, wakeUpNow, CHANGE); // use interrupt 0 (pin 2) and run function
  // wakeUpNow when pin 2 gets LOW
}



void sleepNow()         // here we put the arduino to sleep
{
  /* Now is the time to set the sleep mode. In the Atmega8 datasheet
     http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf on page 35
     there is a list of sleep modes which explains which clocks and
     wake up sources are available in which sleep modus.

     In the avr/sleep.h file, the call names of these sleep modus are to be found:

     The 5 different modes are:
         SLEEP_MODE_IDLE         -the least power savings
         SLEEP_MODE_ADC
         SLEEP_MODE_PWR_SAVE
         SLEEP_MODE_STANDBY
         SLEEP_MODE_PWR_DOWN     -the most power savings

     For now, we want as much power savings as possible,
     so we choose the according sleep modus: SLEEP_MODE_PWR_DOWN

  */
  set_sleep_mode(SLEEP_MODE_IDLE);   // sleep mode is set here

  sleep_enable();              // enables the sleep bit in the mcucr register
  // so sleep is possible. just a safety pin

  /* Now is time to enable a interrupt. we do it here so an
     accidentally pushed interrupt button doesn't interrupt
     our running program. if you want to be able to run
     interrupt code besides the sleep function, place it in
     setup() for example.

     In the function call attachInterrupt(A, B, C)
     A   can be either 0 or 1 for interrupts on pin 2 or 3.

     B   Name of a function you want to execute at interrupt for A.

     C   Trigger mode of the interrupt pin. can be:
                 LOW        a low level triggers
                 CHANGE     a change in level triggers
                 RISING     a rising edge of a level triggers
                 FALLING    a falling edge of a level triggers

     In all but the IDLE sleep modes only LOW can be used.
  */

  attachInterrupt(0, wakeUpNow, CHANGE); // use interrupt 0 (pin 2) and run function
  // wakeUpNow when pin 2 gets LOW

  sleep_mode();                // here the device is actually put to sleep!!
  //

  sleep_disable();             // first thing after waking from sleep:
  // disable sleep...
  detachInterrupt(0);          // disables interrupt 0 on pin 2 so the
  // wakeUpNow code will not be executed
  // during normal running time.
  delay(1000);                 // wat 2 sec. so humans can notice the
  // interrupt.
  // LED to show the interrupt is handled
}



void wakeUpNow()        // here the interrupt is handled after wakeup
{
  //execute code here after wake-up before returning to the loop() function
  // timers and code using timers (serial.print and more...) will not work here.
  if (irrecv.decode(&results)) {
    if (results.value == 0xff629d) {
      state = !state;
      digitalWrite(relayPin, state);
    }
  }
}




void loop()
{

  sleepNow();                      // sleep function called here
}

The Arduino never seems to wake up from sleep when I use the CHANGE interrupt. But if I use with the IDLE sleep mode, it is working.

Can somebody please help me how to fix this ? Also will this code work with an Arduino Pro Mini or an ATTiny45?

2 Answers 2

3

You actually don't need to to worry about interrupts at all for this project. The IRremote library is itself based on a timer interrupt. As soon as you irrecv.enableIRIn(), you start receiving a continuous stream of interrupts... in addition to the timer interrupt initially set up by the Arduino core.

If you want to save some power, you can call sleep_mode() once in your loop. That's it. No need to sleep_enable() or sleep_disable(), as these are already taken care of by sleep_mode(). No need to set_sleep_mode() either, as the default sleep mode (IDLE) is the only one that is appropriate for you. No need to attachInterrupt(), as you will be waken up by these timer interrupts anyway.

Removing all the cruft, your posted code would become:

#include <avr/sleep.h>
#include <IRremote.h>

const int relayPin = 8;
const int irPin = 2;
IRrecv irrecv(irPin);

void setup()
{
    pinMode(relayPin, OUTPUT);
    pinMode(irPin, INPUT);
    irrecv.enableIRIn();
}

void loop()
{
    decode_results results;
    if (irrecv.decode(&results)) {
        if (results.value == 0xff629d) {
            static byte state = LOW;
            state = !state;
            digitalWrite(relayPin, state);
        }
        irrecv.resume();
    }

    // Sleep until next interrupt.
    sleep_mode();
}
0
0

The Arduino never seems to wake up from sleep when I use the CHANGE interrupt.

  attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function

That's not a CHANGE interrupt, it's a LOW interrupt. Please post code that supports what you say in the question.


void wakeUpNow()        // here the interrupt is handled after wakeup
{
  //execute code here after wake-up before returning to the loop() function
  // timers and code using timers (serial.print and more...) will not work here.
  if (irrecv.decode(&results)) {
    if (results.value == 0xff629d) {
      Serial.println("UP");
      state = !state;
      digitalWrite(relayPin, state);
    }
  }
}

Don't do serial prints inside an ISR. In particular, a LOW interrupt keeps being called continuously while the interrupt pin is low.

// timers and code using timers (serial.print and more...) will not work here

You even have a comment saying that the code won't work, yet you posted it in your question.

1
  • I changed the code accordingly
    – Shaam
    Mar 23, 2018 at 9:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.