Problem with interrupts

Hi,
I have to realize aproject with Arduino Mini, powered by battery, that when the window is opened more then 10 minutes send a message with NRF24l01 to an Arduino Nano that switch off the boiler. When the window is closed, send another message and if all windows are closed switch on the boiler.

To save the battery, I think to sleep Arduino, when the switch connected to the window change (on to off or viceversa) by interrupt wake up Arduino Mini, send a message to the Arduino Nano connected to the boiler then go to sleep.

My first test is to sleep Arduino and when a button switch off the first time or switch on the second time, by interrupt wake up Arduino.
I try to use this example:

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

byte i, adcsra, mcucr1, mcucr2;
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup()
{
   Serial.begin(9600);
   pinMode(13, OUTPUT);
   digitalWrite(13, LOW);
   EICRA = 0x00;                 //pin2 richiesta interrupt a livello low
}

void loop()
{  
   sleep_enable();                           //abilita sleep
   set_sleep_mode(SLEEP_MODE_PWR_DOWN);      //modalità sleep massima
   adcsra = ADCSRA;                          //memorizza ADC e Stato Registro A
   ADCSRA = 0;                               //disabilita ADC
   cli();                                    //disabilita interrupts
   EIMSK |= _BV(INT0);                       //abilita INT0
   mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE);  //spegne il brown-out detector
   mcucr2 = mcucr1 & ~_BV(BODSE);
   MCUCR = mcucr1;
   MCUCR = mcucr2;
   sei();                         //abilita interrupts per potersi svegliare
   Serial.println("Goodnigth...");
   delay(500);
   sleep_cpu();                   //sleep qua
   Serial.println("Wake up");
   delay(500);
   
   sleep_disable();               //sveglia quì
   ADCSRA = adcsra;               //ripristina ADCSRA
                                  //inserire qui il codice          

   if (EICRA == 0x00) {
       digitalWrite(13, HIGH);      
       Serial.println("Pull down...");
   } else {
       digitalWrite(13, LOW);      
       Serial.println("Pull up...");
   }
   delay(500);
   delay(50);
   EICRA = ~EICRA;                 //pin2 richiesta interrupt a livello low/high
}
ISR(INT0_vect)
{
   EIMSK &= ~_BV(INT0);           //interrupt int0 per svegliarsi
}

I insert the delay(500) to be sure that the println appear.
Problem:

I see the led switch on when I push the button and switch off the I release the button but I see only the string “Goodnigth”.
My personal impression is that the led status change only for the mechanical action of the button and not for the interrupt

Please edit you post to have code tags. See How to use the forum.

And if you want to wait until serial transfer is out, there is a nice function you can use ;) it's flush() :)

septillion: Please edit you post to have code tags. See How to use the forum.

And if you want to wait until serial transfer is out, there is a nice function you can use ;) it's flush() :)

....but make sure that flush returns only when the USART Tx register is empty after the last character has been written to it.

Groove: ....but make sure that flush returns only when the USART Tx register is empty after the last character has been written to it.

I'm sorry, next time I will use the code tags. Now I try to modify it but I can't insert this tag.

Flush don't change the result: I see only a part of the output. I try many example for the interrupt but I'm not able to manage interrupt...

sc73: I'm sorry, next time I will use the code tags. Now I try to modify it but I can't insert this tag.

Then keep trying... It's not hard and not impossible at all, even when editing. It makes the code soooooo much easier to read.

Code tags added by Moderator.

CrossRoads: Code tags added by Moderator.

Thanks'

Hi,
no one has experience with interrupts?
I put the explanation of my complete design for clarity. I know how to make each part of the project except the management of interrupt and I’m trusting in the experience of someone more expert then me …
I hope I explained clearly enough: my English is so poor…

Most of us have experience with interrupts. It's only now I can kind of read the code. The indentation is mangled (press ctrl+t and have a look) and the comments are in a language I don't master.

But, couple of things. - What do you plan to do with WDT? - Why don't you just use the Arduino functions (HAL) \ - What's the messing with MCUCR suppose to do? - And you don't need to clear the interrupt flag yourself. - And did you had a look at the datasheet about what interrupt is able to wake what sleep mode?

And if English is to hard, maybe try the subboard in your language (Italian?).

septillion: Most of us have experience with interrupts. It's only now I can kind of read the code. The indentation is mangled (press ctrl+t and have a look) and the comments are in a language I don't master.

I see correctly the code. Ctrl+t open another window in thr browser! I do not understand what's going on. Yes, I copyed and modified an example from a tutorial written in Italian (for this reason some comments are in Italian. I'm sorry but I don't know some instruction and I'm not able to translate them)

septillion: But, couple of things. - What do you plan to do with WDT? - Why don't you just use the Arduino functions (HAL) \ - What's the messing with MCUCR suppose to do? - And you don't need to clear the interrupt flag yourself. - And did you had a look at the datasheet about what interrupt is able to wake what sleep mode?

  • I'm not using WDT
  • I don't now the Arduino functions (HAL), I'm trying to generate a source code with basic instruction. I will read a tutorial for the HAL if you tell me is necessary
  • ok, if is not necessary to clear the interrupt I don't do it
  • I read the datasheet about interrupt. I understood there are some way to activate the interrupt. I think to attivate the interrupt when the switch change state (I see is possible to call a function when the pin 2 change state: attachInterrupt(0, interrupttrigger, CHANGE); )

septillion: And if English is to hard, maybe try the subboard in your language (Italian?).

I written here because in the English forum there are many people and is major the probability that someone already had my problem

I should have told you, but Ctrl+T in the Arduino IDE of course..

Copying and modifying an example is a terrible way to go. Way better to learn from it and write your own code. Two pro's to that, 1) You really know what it does, 2) it really does what you want ;)

Why do you include WDT then?

You do know Arduino functions. digitalWrite, Serial.print() etc are all Arduino functions that handle HAL (Hardware Abstraction Layer). Aka, functions that helps you so you don't have to mess with the hardware and registers behind it. For external interrupts there is attachInterrupt() and digitalPinToInterrupt() :)

In sleep mode Power-down you can only wake it with a level interrupt (see page 39 of the datasheet), aka HIGH or LOW, no CHANGE, FALLING or RISING.

septillion: I should have told you, but Ctrl+T in the Arduino IDE of course..

I'm sorry... now I understand :-(

septillion: Copying and modifying an example is a terrible way to go. Way better to learn from it and write your own code. Two pro's to that, 1) You really know what it does, 2) it really does what you want ;)

You have reason!

septillion: Why do you include WDT then?

Included for error...

septillion: You do know Arduino functions. digitalWrite, Serial.print() etc are all Arduino functions that handle HAL (Hardware Abstraction Layer). Aka, functions that helps you so you don't have to mess with the hardware and registers behind it. For external interrupts there is attachInterrupt() and digitalPinToInterrupt() :)

In sleep mode Power-down you can only wake it with a level interrupt (see page 39 of the datasheet), aka HIGH or LOW, no CHANGE, FALLING or RISING.

Now I tried with attachInterrupt, but when I push button or release, I don't see the debug string and I don't see the correct action on the led...

int pin = 6;
volatile int state = LOW;

void setup()
{
  Serial.begin(9600);
  pinMode(pin, OUTPUT);
  digitalWrite(pin, LOW);
  attachInterrupt(0, GestInt, state);
}

void loop()
{
  Serial.println("In loop...");
  delay(10);
}

void GestInt()
{
  if (state == LOW) {
    Serial.println("DOWN");
    attachInterrupt(0, GestInt, HIGH);
    digitalWrite(pin, HIGH);
  } else {
    Serial.println("Up");
    attachInterrupt(0, GestInt, LOW);
    digitalWrite(pin, LOW);
  }
  delay(50);
  state = !state;
}
    attachInterrupt(0, GestInt, HIGH);
    digitalWrite(pin, HIGH);
  } else {
    Serial.println("Up");
    attachInterrupt(0, GestInt, LOW);

You almost certainly do not want to be using HIGH or LOW as the type. RISING and FALLING, maybe.

You do not want to attach a new handler without detaching the previous one.

You probably should not be detaching and attaching the handler. Use CHANGE as the type, and in the handler determine what the state changed to.

Hi,

thanks to all for the tips.
Combining your suggestions to some news found thanks to St. Google, now I’m able to send Arduino to sleep and wake up it when I push or release a button.
Now I have to manage the debouncing because sometime the final state of the led is not the state aspected.

hoping not to abuse too much of the patience of the forum users, I wonder: it works, but is there a better way to implement this example?

#include <avr/sleep.h>

const byte ledPin = 6;
const byte interruptPin = 2;
volatile byte state = LOW;
byte i, adcsra, mcucr1, mcucr2;
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}

void loop() {
  delay(50);
  digitalWrite(ledPin, state);

  sleep_enable();                           //enable sleep
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);      //maximum sleep mode
  adcsra = ADCSRA;                          //store ADC e Status Register A
  ADCSRA = 0;                               //disable ADC
  cli();                                    //disable interrupts
  EIMSK |= _BV(INT0);                       //enable INT0
  mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE);  //switch off il brown-out detector
  mcucr2 = mcucr1 & ~_BV(BODSE);
  MCUCR = mcucr1;
  MCUCR = mcucr2;
  sei();                         //enable interrupts to wake up Arduino
  Serial.println("Goodnigth");
  delay(100);
  sleep_cpu();                   //sleep here
  Serial.println("wake up");
  delay(100);

  sleep_disable();               //Wake up
  ADCSRA = adcsra;               // ADCSRA
  // insert your code from here...

  EICRA = ~EICRA;                 //pin2 interrupt
}

void blink() {
  state = !state;
}

but is there a better way to implement this example?

Well, you could spell night correctly. 8)

#include <avr/sleep.h>

const byte LedPin = 13;
const byte InterruptPin = 2;

void setup() {
  Serial.begin(115200);
  
  // disable ADC
  ADCSRA = 0;
  
  pinMode(LedPin, OUTPUT);
  pinMode(InterruptPin, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(InterruptPin), wakeUp, FALLING);

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);      //maximum sleep mode
}

void loop() {
  Serial.println("Goodnight");
  Serial.flush();
  
  noInterrupts();
  sleep_enable();                           //enable sleep
  
  
  // turn off brown-out enable in software
  MCUCR = bit (BODS) | bit (BODSE);  // turn on brown-out enable select
  MCUCR = bit (BODS);        // this must be done within 4 clock cycles of above

  interrupts();
  sleep_mode();

  Serial.println("wake up");
  digitalToggle(LedPin);

  delay(100); //Let's stay away to debounce
}

void wakeUp() {
}

void digitalToggle(byte pin){
  digitalWrite(pin, !digitalRead(pin));
}

But having a LED turned on while in sleep is like isolating your house but put the heater outside… The led will take wayyyyyy more current then the micro, even with it running.

PaulS: Well, you could spell night correctly. 8)

Ok! :-) Other errors?

septillion:

#include <avr/sleep.h>

const byte LedPin = 13;
const byte InterruptPin = 2;

void setup() {
  Serial.begin(115200);
 
  // disable ADC
  ADCSRA = 0;
 
  pinMode(LedPin, OUTPUT);
  pinMode(InterruptPin, INPUT_PULLUP);

attachInterrupt(digitalPinToInterrupt(InterruptPin), wakeUp, FALLING);

set_sleep_mode(SLEEP_MODE_PWR_DOWN);      //maximum sleep mode
}

void loop() {
  Serial.println(“Goodnight”);
  Serial.flush();
 
  noInterrupts();
  sleep_enable();                          //enable sleep
 
 
  // turn off brown-out enable in software
  MCUCR = bit (BODS) | bit (BODSE);  // turn on brown-out enable select
  MCUCR = bit (BODS);        // this must be done within 4 clock cycles of above

interrupts();
  sleep_mode();

Serial.println(“wake up”);
  digitalToggle(LedPin);

delay(100); //Let’s stay away to debounce
}

void wakeUp() {
}

void digitalToggle(byte pin){
  digitalWrite(pin, !digitalRead(pin));
}




But having a LED turned on while in sleep is like isolating your house but put the heater outside... The led will take wayyyyyy more current then the micro, even with it running.

You are right, but this is only for the example.
In my project, I have to:

  1. opening the window (down button), wake up Arduino, send a string via rf to another Arduino (instead of switch on the led), then go back to sleep

  2. closing the window (up button), wake up Arduino, send a string via rf to another Arduino (instead of switch off the led), then go back to sleep

I have to manage debouncing (I don’t switch manually a button but I have the same problem because when I open or close the window I change the state of the switch)

In my project, I don’t use leds and all component are in power down mode (if I made it correctly). :frowning:

Makes sens. But then I think my code is a perfect starting place :) Don't forget to put the RF is a ultra-low power setting as well :)

And about debouncing, I think this is one of the cases a delay() aka a blocking function is appropriate. No matter how you turn it, you want to block the uC from going to sleep and do nothing. So yeah...

Hi,

I also thought that a delay() is enough to avoid the debouncing, but I'm not so expert and I wasn't sure this is a correct way to solve the problem. If you confirm me is correct, I avoid the debouncing with a delay()

Uhmmm... you have reason, to save battery I have to put the RF to a minimum power setting necessary. I don't know how to do. I Have to read the datasheet...

Now I'm also reading how to use timer interrupt to understand if is possible to check sometime the state of switch (in case of black-out, wen the power supply restart I don't know the state of the switch)