Wake up from sleep using external interrupt

Hello,

I found this web page, Using the watchdog for both preventing failures and energy savings . I think this code should be useful for my application as I wanted a low power setup as well as some protection against code failures.

How can I add an external interrupt to wake the Arduino up from sleep? Below is the original code from the website as well as some of the external interrupt code (in bold).

#include <avr/wdt.h>            // library for default watchdog functions
#include <avr/interrupt.h>      // library for interrupts handling
#include <avr/sleep.h>          // library for sleep
#include <avr/power.h>          // library for power control

// how many times remain to sleep before wake up
// volatile to be modified in interrupt function
volatile int nbr_remaining; 

// pin on which a led is attached on the board
#define led 13
int pin2 = 2;


void pin2Interrupt(void)
{
  /* This will bring us back from sleep. */
  
  /* We detach the interrupt to stop it from 
   * continuously firing while the interrupt pin
   * is low.
   */
  detachInterrupt(0);
}


// interrupt raised by the watchdog firing
// when the watchdog fires, this function will be executed
// remember that interrupts are disabled in ISR functions
// now we must check if the board is sleeping or if this is a genuine
// interrupt (hanging)
ISR(WDT_vect)
{
    // Check if we are in sleep mode or it is a genuine WDR.
    if(nbr_remaining > 0)
    {
        // not hang out, just waiting
        // decrease the number of remaining avail loops
        nbr_remaining = nbr_remaining - 1;
        wdt_reset();
    }
    else
    {
        // must be rebooted
        // configure
        MCUSR = 0;                          // reset flags
       
                                            // Put timer in reset-only mode:
        WDTCSR |= 0b00011000;               // Enter config mode.
        WDTCSR =  0b00001000 | 0b000000;    // clr WDIE (interrupt enable...7th from left)
                                            // set WDE (reset enable...4th from left), and set delay interval
                                            // reset system in 16 ms...
                                            // unless wdt_disable() in loop() is reached first
                                       
        // reboot
        while(1);
    }
}

// function to configure the watchdog: let it sleep 8 seconds before firing
// when firing, configure it for resuming program execution by default
// hangs will correspond to watchdog fired when nbr_remaining <= 0 and will
// be determined in the ISR function
void configure_wdt(void)
{
 
  cli();                           // disable interrupts for changing the registers

  MCUSR = 0;                       // reset status register flags

                                   // Put timer in interrupt-only mode:                                       
  WDTCSR |= 0b00011000;            // Set WDCE (5th from left) and WDE (4th from left) to enter config mode,
                                   // using bitwise OR assignment (leaves other bits unchanged).
  WDTCSR =  0b01000000 | 0b100001; // set WDIE: interrupt enabled
                                   // clr WDE: reset disabled
                                   // and set delay interval (right side of bar) to 8 seconds

  sei();                           // re-enable interrupts 
}

// Put the Arduino to deep sleep. Only an interrupt can wake it up.
void sleep(int ncycles)
{  
  nbr_remaining = ncycles; // defines how many cycles should sleep

  // Set sleep to full power down.  Only external interrupts or
  // the watchdog timer can wake the CPU!
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 
  // Turn off the ADC while asleep.
  power_adc_disable();
 
  while (nbr_remaining > 0){ // while some cycles left, sleep!

  // Enable sleep and enter sleep mode.
  sleep_mode();

  // CPU is now asleep and program execution completely halts!
  // Once awake, execution will resume at this point if the
  // watchdog is configured for resume rather than restart
 
  // When awake, disable sleep mode
  sleep_disable();
  
  // we have slept one time more
  nbr_remaining = nbr_remaining - 1;
 
  }
 
  // put everything on again
  power_all_enable();
 
}

void setup(){

  /* Setup the pin direction. */
  pinMode(pin2, INPUT);
  
  // use led 13 and put it in low mode
  pinMode(led, OUTPUT);
  digitalWrite(led, LOW);
  
  delay(1000);
  
  // configure the watchdog
  configure_wdt();

  // blink twice
  digitalWrite(led, HIGH);   
  delay(500);               
  digitalWrite(led, LOW);   
  delay(500); 
  digitalWrite(led, HIGH);   
  delay(500);               
  digitalWrite(led, LOW);   
  delay(500); 

}

void loop(){

  // sleep for a given number of cycles (here, 5 * 8 seconds) in lowest power mode
  sleep(5);

  // usefull stuff
  // blink three times
  digitalWrite(led, HIGH);   
  delay(500);               
  digitalWrite(led, LOW);   
  delay(500); 
  digitalWrite(led, HIGH);   
  delay(500);               
  digitalWrite(led, LOW);   
  delay(500);
  digitalWrite(led, HIGH);   
  delay(500);               
  digitalWrite(led, LOW);   
  delay(500); 

  // now a real hang is happening: this will rebood the board
  // after 8 seconds
  // (at the end of the sleep, nrb_remaining = 0)
  //while (1);

}

Where should I place attachInterrupt(0, pin2Interrupt, LOW); so the external interrupt works? I haven't been able to get this to work.

Thanks for any help

Have you read Mr. Gammon's interrupt discussion?

.

I had a look at Nick Gammon's interrupt discussion from here

I added 2 interrupts on digital pins D2 and D3 as shown below. Both of these pins wake the arduino from sleep.

Can anyone see absolutely any problems with the below code, with interrupts in the wrong position etc. that can cause problems?

#include <avr/wdt.h>            // library for default watchdog functions
#include <avr/interrupt.h>      // library for interrupts handling
#include <avr/sleep.h>          // library for sleep
#include <avr/power.h>          // library for power control

// how many times remain to sleep before wake up
// volatile to be modified in interrupt function
volatile int nbr_remaining; 

// pin on which a led is attached on the board
#define led 13
const int buttonPin2 = 2;      // input pin (for a pushbutton switch)
const int buttonPin3 = 3; 


// interrupt raised by the watchdog firing
// when the watchdog fires, this function will be executed
// remember that interrupts are disabled in ISR functions
// now we must check if the board is sleeping or if this is a genuine
// interrupt (hanging)
ISR(WDT_vect)
{
    // Check if we are in sleep mode or it is a genuine WDR.
    if(nbr_remaining > 0)
    {
        // not hang out, just waiting
        // decrease the number of remaining avail loops
        nbr_remaining = nbr_remaining - 1;
        wdt_reset();
    }
    else
    {
        // must be rebooted
        // configure
        MCUSR = 0;                          // reset flags
       
                                            // Put timer in reset-only mode:
        WDTCSR |= 0b00011000;               // Enter config mode.
        WDTCSR =  0b00001000 | 0b000000;    // clr WDIE (interrupt enable...7th from left)
                                            // set WDE (reset enable...4th from left), and set delay interval
                                            // reset system in 16 ms...
                                            // unless wdt_disable() in loop() is reached first
                                       
        // reboot
        while(1);
    }
}

// function to configure the watchdog: let it sleep 8 seconds before firing
// when firing, configure it for resuming program execution by default
// hangs will correspond to watchdog fired when nbr_remaining <= 0 and will
// be determined in the ISR function
void configure_wdt(void)
{
 
  cli();                           // disable interrupts for changing the registers

  MCUSR = 0;                       // reset status register flags

                                   // Put timer in interrupt-only mode:                                       
  WDTCSR |= 0b00011000;            // Set WDCE (5th from left) and WDE (4th from left) to enter config mode,
                                   // using bitwise OR assignment (leaves other bits unchanged).
  WDTCSR =  0b01000000 | 0b100001; // set WDIE: interrupt enabled
                                   // clr WDE: reset disabled
                                   // and set delay interval (right side of bar) to 8 seconds

  sei();                           // re-enable interrupts 
}

// Put the Arduino to deep sleep. Only an interrupt can wake it up.
void sleep(int ncycles)
{  
  nbr_remaining = ncycles; // defines how many cycles should sleep

  // Set sleep to full power down.  Only external interrupts or
  // the watchdog timer can wake the CPU!
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 
  // Turn off the ADC while asleep.
  power_adc_disable();
  
  attachInterrupt (0, wake, LOW); 
  attachInterrupt (1, wake, LOW); 
  
  while (nbr_remaining > 0){ // while some cycles left, sleep!

  // Enable sleep and enter sleep mode.
  sleep_mode();

  // CPU is now asleep and program execution completely halts!
  // Once awake, execution will resume at this point if the
  // watchdog is configured for resume rather than restart
 
  // When awake, disable sleep mode
  //sleep_disable();
  
  detachInterrupt(0);     // stop LOW interrupt
  detachInterrupt(1);     // stop LOW interrupt
  
  // we have slept one time more
  nbr_remaining = nbr_remaining - 1;
 
  }
 
  // put everything on again
  power_all_enable();
 
}

void setup(){
  Serial.begin(9600);
  
  pinMode(buttonPin2, OUTPUT);
  pinMode(buttonPin3, OUTPUT);
  digitalWrite (buttonPin2, HIGH);    // pull-up on button 
  digitalWrite (buttonPin3, HIGH);    // pull-up on button 
  
  Serial.println("Initialisation complete.");
  
  // use led 13 and put it in low mode
  pinMode(led, OUTPUT);
  digitalWrite(led, LOW);
  
  delay(1000);
  
  // configure the watchdog
  configure_wdt();

  // blink twice
//  digitalWrite(led, HIGH);   
//  delay(500);               
//  digitalWrite(led, LOW);   
//  delay(500); 
//  digitalWrite(led, HIGH);   
//  delay(500);               
//  digitalWrite(led, LOW);   
//  delay(500); 

}


// interrupt service routine in sleep mode
void wake ()
{
  sleep_disable ();         // first thing after waking from sleep:
}  //



void loop()
{

  // sleep for a given number of cycles (here, 5 * 8 seconds) in lowest power mode
  sleep(1);

  // usefull stuff
  // blink three times
  digitalWrite(led, HIGH);   
  delay(500);               
  digitalWrite(led, LOW);   
  delay(500); 
  digitalWrite(led, HIGH);   
  delay(500);               
  digitalWrite(led, LOW);   
  delay(500);
  digitalWrite(led, HIGH);   
  delay(500);               
  digitalWrite(led, LOW);   
  delay(500); 

  // now a real hang is happening: this will rebood the board
  // after 8 seconds
  // (at the end of the sleep, nrb_remaining = 0)
  //while (1);

}

Many thanks

#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#define PCINT_IN PORTB0 //14 PIN
#define LED_PORT PORTB1

void init_pcint()
{
  PCMSK0 = (1<<PCINT2); //pin(PB0)  registers that enable or disable pin-change interrupts on individual pins 16 PIN
  PCICR =(1<<PCIE2); //PORTB enables pci2 
  sei(); //start up global interrupt
}

int main()
{
  DDRB |= ((1 << DDB5)); //configured with internal pull-up resistor PCINT5 19pin
  PORTB = (1<<PCINT2); //0x005 16 PIN, set PCINT2 to trigger an interrupt on state change 
  init_pcint();
  while (1)
 {
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
        sleep_enable();
        
        sei();   // Must enable or can't wake!
        sleep_cpu();

        sleep_disable();

        
    }
}
 void SetupInterrupts(void)
{
 
  EIMSK   = (1<<PCIE1);    //Enable interrupt for flag PCIF1
}
int button = 2;
int LED = 13;
int buttonstate = 0;
void setup() 
{
  pinMode(LED, OUTPUT); 
  pinMode(2,INPUT);
  sleep_enable(); 
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); 
  }
 
void loop()
{
  attachInterrupt(2, interruptFunction, HIGH);
  digitalWrite(LED, HIGH);
  delay(5000);
  digitalWrite(LED, LOW);
 }
   
void interruptFunction()
{
  sleep_disable();
  LED=HIGH;
  digitalWrite(2, !digitalRead(2));
  delay(500);
  buttonstate= digitalRead(button);
  digitalWrite(LED,buttonstate);
}