Two Interrupts for two different tasks

Hi,

I have searched this forum for doing two different tasks independent to each other, using interrupts on Arduino Uno, but could not find any :o

One interrupt is through watchdog timer (wdt) and another is through PIN2 (connected to a push button).

I would like to use wdt for flashing an led connected to pin9 every 24 secs, and use PIN2 interrupt to flash an led connected to pin13.

After following Nick Gammons forum, I am able to flash the led connected to the wdt interrupt :slight_smile: , but not the PIN2 interrupt :frowning: . Could someone please help me. I want these interrupts to be independent to each other.

Attached is my code, also copy pasted below.

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

const byte LED = 9;

const byte LED2 = 13;

ISR (WDT_vect) 
{
   wdt_disable();  // disable watchdog
}  // 

void resetWatchdog ()
  {
  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset, clear existing interrupt
  WDTCSR = bit (WDCE) | bit (WDE);
  // set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
  WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0);    // set WDIE, and 8 seconds delay
  // pat the dog
  wdt_reset();  
  }  // end of resetWatchdog
  
  
void wake ()
{
  // cancel sleep as a precaution
  sleep_disable();
  interrupts ();  // one cycle
  // must do this as the pin will probably stay low for a while
  

  detachInterrupt (0);
}  // end of wake


void setup () 
  {
  resetWatchdog (); 
  pinMode (LED, OUTPUT);
  pinMode (LED2, OUTPUT);
  pinMode (2, INPUT);
  digitalWrite (2, HIGH);  // enable pull-up
  attachInterrupt (0, wake, LOW);

  }  // end of setup
  
  
  
  

void loop () 
{
if (digitalRead (2) == LOW)
   {
  digitalWrite (LED2, HIGH);
  delay (1000);
  digitalWrite (LED2, LOW);                                                         
  delay (1000);}
  
else
  
  {pinMode (LED, OUTPUT);
  digitalWrite (LED, HIGH);
  delay (1000);
  digitalWrite (LED, LOW);                                                         
  delay (50);
  }


  for (int thisPin = 1; thisPin < 4; thisPin++) { 
    goToSleep ();
  }
}
  
void goToSleep ()
{
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  ADCSRA = 0;  
  noInterrupts ();
  resetWatchdog (); 
  sleep_enable();

  // turn off brown-out enable in software
  // BODS must be set to one and BODSE must be set to zero within four clock cycles
    MCUCR = bit (BODS) | bit (BODSE);
    
     // The BODS bit is automatically cleared after three clock cycles
  MCUCR = bit (BODS);
  interrupts ();  // one cycle
  sleep_cpu ();   // one cycle
  sleep_disable (); 
  } // end of loop

Many thanks in advance for your help ! :slight_smile: :slight_smile:

IMP_INTERUPT_diff3.ino (1.93 KB)

  attachInterrupt (0, wake, LOW);

Don't use LOW use FALLING

void wake ()
{
  // cancel sleep as a precaution
  sleep_disable();
  interrupts ();  // one cycle
  // must do this as the pin will probably stay low for a while
  

  detachInterrupt (0);
}  // end of wake

Don't detach interrupts and then reattach use a flag. It's point less to dis able interrups in an ISR as they already are disabled!

I can't see how your sleep code allows the arduino to wake on the watch dog AND the ext interrupt

Mark

PS. NEVER USE interrupts() within an ISR as it turns interrupts back on an can/will create a real mess!.

M

Why would you think it desirable to use an interrupt to service a pushbutton?

It sounds like you are using the WDT just to create an interrupt and not because you want the Arduino to go to sleep or because you are afraid that your program might bet into an endless loop - which is what the dog is meant to be watching for.

Which leads me to wonder why you need any interrupts at all?

It is very easy to arrange for an Arduino to carry out two different tasks. Have you looked at the demo several things at a time?

...R

Thanks to everyone for your help :) . I was so afraid at first to post, as I thought it might be silly question and nobody would reply me. But thanks again for kind help!

First, I want to explain what I want to do.

I am trying to measure temperature, just once a day. So my Arduino should just wake up only once in a day (9AM), and should sleep all the time. So here, I would like to use wdt for this task.

Next, when I go with a bluetooth device, let's say once in a month, then I download the entire months data (30 values of temparature) into a Andriod device. Here I would like to use PIN2 as hardware interrupt. So as soon as Andriod connects to Arduino, the sensor should come out of sleep and it should just do one specific task of talking/sending to Andriod.

I hope, I clarified, what I want. In the sketch I posted here, I replaced sensing and sending data functions with blinking leds, and bluetooth interrupt with a pushbutton, so that I can see the effect easily and my question can be less clumsy.

Sorry for not articulating the question nicely, I find it is difficult to frame :disappointed_relieved: .

So

@Robin2

My task is not doing different things at the same time, instead, doing different tasks at different times, which are independent to each other. One is measuring (once in a day), another is communicating with andriod (once in a month) :cold_sweat:

@Paul__B As I explained above, I am just using push button instead of a bluetooth interrupt, to see the interrupt effect easily.

@holmes4

Thanks for your feedback on the code. I really confused in using both the hardware interrupt and wdt interrupt doing different things, so those are my mistakes.

Thanks everyone for your help :) I hope, I make my question more understandable :fearful: .

When you say "when I go with a bluetooth device" I presume you mean a phone or a PC that has bluetooth.

There will also need to be a bluetooth device attached to the Arduino. How will it know that the phone is trying to contact it if the Arduino is asleep? I presume the WDT wakes the Arduino every few seonds or minutes. You could program it to check for a bluetooth connection each time it wakes up. It would probably need to allow time for the devices to pair.

What bluetooth device are you planning to attach to the Arduino - can you post a link to its datasheet.

If you want something that is asleep and consuming very little power for 99% of the time you would be better with an Atmega 328 on a breadboard without all of the other Arduino hardware. A 328 using the internal 8MHz clock would be very simple to construct.

By the way, you will need a Real Time Clock (RTC) module if you want to do something at 9am every day. I think some of them come with alarms that can wake up an Arduino.

...R

Can you post the amended code, with the above suggestions incorporated, please?

Dear Nick Gammon and Holmes,

Below is my code after making the changes as you suggested. However, I could not change LOW to FALLING, if I do that LED is not changing its state with the push button.

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

const byte LED = 9;
const byte LED2 = 13;

ISR (WDT_vect) 
{
   wdt_disable();  // disable watchdog
}  // 

void resetWatchdog ()
  {
  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset, clear existing interrupt
  WDTCSR = bit (WDCE) | bit (WDE);
  // set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
  WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0);    // set WDIE, and 8 seconds delay
  // pat the dog
  wdt_reset();  
  }  // end of resetWatchdog
  
  
void wake ()
{
  // cancel sleep as a precaution
  sleep_disable();

}  // end of wake


void setup () 
  {
  resetWatchdog (); 
  pinMode (LED, OUTPUT);
  pinMode (2, INPUT);
  digitalWrite (2, HIGH);  // enable pull-up
  attachInterrupt (0, wake, LOW);

  }  // end of setup
  
  
  
  

void loop () 

{
   digitalWrite (LED2, LOW);
if (digitalRead (2) == LOW)
   {pinMode (LED2, OUTPUT);
  digitalWrite (LED2, HIGH);
  delay (100);
  digitalWrite (LED2, LOW);                                                         
  }
  
else
  
  {pinMode (LED, OUTPUT);
  digitalWrite (LED, HIGH);
  delay (1000);
  digitalWrite (LED, LOW);                                                         
  delay (50);}
  
 for (int thisPin = 1; thisPin < 4; thisPin++) { 
  goToSleep ();}
}
  
void goToSleep ()
{
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  ADCSRA = 0;  
  resetWatchdog (); 
  sleep_enable();
  // turn off brown-out enable in software
  // BODS must be set to one and BODSE must be set to zero within four clock cycles
    MCUCR = bit (BODS) | bit (BODSE);
    
     // The BODS bit is automatically cleared after three clock cycles
  MCUCR = bit (BODS);
  sleep_cpu ();   // one cycle
  sleep_disable (); 
  } // end of loop

Now at least both the interrupts seems to be independent, although delay in the if function is causing some timing issues and I don’t know if I am doing the things in the right order.

I would be grateful to you, if you can review my code.

@Robin2

Yes, I am using a phone which has a bluetooth and I am connecting the below bluetooth module to Arduino.
http://www.ebay.co.uk/itm/271062162602?_trksid=p2055119.m1438.l2649&ssPageName=STRK%3AMEBIDX%3AIT

I will also use only bread board version of the sensor, after doing my tests with the Arduino board.

Thank you for your feedback.

 for (int thisPin = 1; thisPin < 4; thisPin++) { 
  goToSleep ();}
}

What is this intended to do?

What have pins got to do with it?
Why is it necessary to do gotToSleep() 3 times?

…R

Dear Robin2,

Thanks for looking into my code and your kind reply.

I want for loop to go 3 times, because that would allow me to keep the Arduino into sleep mode for 24 seconds (3*8secs). My plan is to increase the for loop number, so that I can make it sleep as many seconds (or hours), as I want. Otherwise, I don't know how to make Arduino to sleep more than 8 seconds with wdt.

I was trying to follow the answer from the below forum link.

http://forum.arduino.cc/index.php?topic=173850.0

If you know any better way for this purpose, I am glad to know.

thispin is just a variable, which was given in the for loop example in the Arduino forum. That name can be any thing like i, j.

funny: because that would allow me to keep the Arduino into sleep mode for 24 seconds (3*8secs).

It had not occurred to me that it would work like that. I thought it would restart (rather than continue) when it wakes up.

Rather than put it to sleep for a certain length of time I would write my code so it would just go back to sleep every time unless there is something useful to do. In other words - wake-up; check things; do things if necessary; go to sleep.

...R

@Robin2,

I am not experienced in programming. So, I have just searched the forum and tried to adopt the parts of the codes that I have found. It has worked for me, I mean I have tested it to see that LED is blinking exactly every 24 seconds.

Rather than put it to sleep for a certain length of time I would write my code so it would just go back to sleep every time unless there is something useful to do. In other words - wake-up; check things; do things if necessary; go to sleep.

Honestly, I don't know how to do it. I can guess, I might need to put another if or while function and a counter. I will give it a try.

Thanks!

What sort of battery life can you expect with the bluetooth module waking up every so often?

Bianco:
What sort of battery life can you expect with the bluetooth module waking up every so often?

I doubt if you would need to start the bluetooth module every time the Arduino wakes up. Just often enough to be sure of detecting the PC when the guy comes to collect the data.

If the guy doing the data collection is required to wait (say) 5 minutes then the bluetooth device would only need to be started every (say) 3 minutes. And there might be times of the day (night time?) when the data guy would be certain not to call by.

…R

Robin2: I doubt if you would need to start the bluetooth module every time the Arduino wakes up. Just often enough to be sure of detecting the PC when the guy comes to collect the data.

My understanding of "every so often" might not be 100% then but that's what I meant.

Still, I'd be interested to have an idea of the battery life.

funny> To make your code more readable, you could hide the ugly sleeping stuff in other files (see exemple) while staying with the Arduino IDE and *.ino files.

Many thanks Bianco, for giving link to sleepduino, which is very neat. This has also solved the problem of using counter, as suggested by Robin2. However, I have one small doubt here. If I am using another hardware interrupt (along with wdt) to wake up the Ardiuno, like pin2, then the counting of cycles will be missed, during this second interrupt time (in my case while connected to the bluetooth, cycles won't be counted correctly). Am I right?

So I am thinking that, it may be possible to set another counter, that measures, how many seconds (or cycles) Arduino is awake when interrupted by the pin2, and we delete that many seconds (or cycles) from the CYCLE. I am going to test this and post my modified code tonight.

Still, I'd be interested to have an idea of the battery life.

I think with 3.3 coin cell batteries, we expect at least 6 to 12 months, if I am collecting data only once or twice a month.

@Robin2

You have asked, how can I wake Arduino with bluetooth, sorry I forgot to answer that previously. I have connected the RX pin to the pin2, using 220 ohm resistor as suggested in the below link.

http://forum.arduino.cc/index.php?topic=107665.0

funny: So I am thinking that, it may be possible to set another counter, that measures, how many seconds (or cycles) Arduino is awake when interrupted by the pin2, and we delete that many seconds (or cycles) from the CYCLE. I am going to test this and post my modified code tonight.

If you want your MCU to wake-up at precise time, I'm wondering if you wouldn't be better off using an RTC module that wakes it up (with externel interrupt) at 9 o'clock every day. The precision of the watchdog timer isn't all that great.

Still, you might need the watchdog to turn your buetooth module on a few times a day.

6 to 12 months with a coin-cell, that's incredible! You might know it already but Atmel gives some nice advice to save power: http://www.atmel.com/technologies/lowpower/design_examples.aspx

Dear Biano,

I have changed my code as you suggested. There is one problem here. I am not able to read the values through the analogue input, when the arduino wakes up. Although, I am able to flash LEDS during thiswake up period. I am getting ‚Äė0‚Äô all the time. I must be doing some stupid mistake. Could you or anyone point out please.

Below is the main sensor code:

/* This software is released under the Do whatever you want
   with it licence. Sleep.ino has to be in the same folder. */
   
   
//#define debug //Uncomment to debug through serial

#define CYCLES 1 // Number of 8-second-cycles you wish to put it asleep for
#define LED 13
#define LED2 9
byte cycle = 0;
int sensorValue =0;

void sleep(); // sleep.ino
void wake();  // sleep.ino
void resetWatchdog (); // sleep.ino

ISR(WDT_vect);  // sleep.ino

void flash() { // <== Put the useful stuff there
  pinMode (LED, OUTPUT);
  digitalWrite (LED, HIGH);
  delay (1000);
  digitalWrite (LED, LOW);                                                         

}  // end of flash
 


  void flash2() { // <== Put the useful stuff there
  pinMode (LED2, OUTPUT);
  digitalWrite (LED2, HIGH);
  delay (1000);
  digitalWrite (LED2, LOW);                                                         

}  // end of flash
 

void communicate() { 
Serial.println("printing");
//Serial.println(sensorValue);
delay (100);
} 
 
void measure() { // <== Put the useful stuff there
Serial.println("measuring");
sensorValue = analogRead(0); 
Serial.println(analogRead(0));
delay (50);
}  

 
 
 
void setup () {

  Serial.begin(9600);
  pinMode (LED, OUTPUT);
  resetWatchdog (); 
  pinMode (2, INPUT);
  digitalWrite (2, LOW);  // enable pull-up
  attachInterrupt (0, wake, LOW);
  digitalWrite (LED, LOW);                                                         
}


void loop () {

  
  if (digitalRead (2) == LOW){
   flash2 ();  
communicate();
}  
else{
  if(cycle >= CYCLES) { // Check number of cycles since last action
    cycle = 0;
    flash ();  
    measure(); 
      
  }
  else {
  }
  }
  sleep();
/* -> When the watchdog timer will trigger the interrupt,
     execution will be resumed here. */
  wake();
} // end of loop

Below is the sleep.ino

/* You have to open sleepduino.ino in your Arduino IDE. */

// More about sleep: page 39 and following of the datasheet
// More about watchdog timer: page 50 and following

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

ISR(WDT_vect) 
{ // Watchdog Interrupt Service Routine
   wdt_disable();  // Disable watchdog then resume sketch
}



void resetWatchdog ()
  {
  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset, clear existing interrupt
  WDTCSR = bit (WDCE) | bit (WDE);
  // set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
  WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0);    // set WDIE, and 8 seconds delay
  // pat the dog
  wdt_reset();  
  }  // end of resetWatchdog
  

void sleep() 
{
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);  
  /ADCSRA = 0;  
  resetWatchdog (); 
  //power_all_disable ();  // power off ADC, Timer 0 and 1, serial interface
  sleep_enable();
  // turn off brown-out enable in software
  // BODS must be set to one and BODSE must be set to zero within four clock cycles
    MCUCR = bit (BODS) | bit (BODSE);
    
     // The BODS bit is automatically cleared after three clock cycles
  MCUCR = bit (BODS);
  sleep_cpu ();   // one cycle
  sleep_disable (); 
  } // end of loop




void wake() {
  sleep_disable();
 // power_all_enable(); // Not sure we need everything but it doesn't hurt.
  cycle++;
}

Maybe.

To save power, we deactivate the ADC (Analog to Digital Converter). Did you reactivate it? It's possible it needs a bit of time to settle, I'm no expert.