I'll confess, Im only at the initial stages of head scratching....but Im struggling to see a way to combine both watchdog and external interrupt (via button) to wake the arduino up. Is it not possible, or (more likely) am I just missing the obvious?
Why combine? Won't either cause a wake from sleep independently?
See section 10.1 of the '328P datasheet to review all the wake interrupt sources.
http://www.atmel.com/Images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet.pdf (35 Mbytes)
My temperature sensor does exactly that:
excellent, thanks nick. looks essentially the same as what Im after.
sorry to revive this old topic, I do have a relevant question on this exact scenario though...
I also would like to combine an interrupt driven wakeup combined with a periodic one. In my scenario it's a PIR on a battery node (interrupt) which I'd like to send health stats every now and then. even with this example I can't seme to wrap my head around it...
- enable watchdog for say 2s
- after 2s check if something has happened
--> I have the following interrupt wakeup code inplace:
attachInterrupt(1, wakeUpFromSleepy, HIGH); //interrupt attached to PIN3 Allow wake up pin to trigger interrupt on high.
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); // Enter power down state with ADC and BOD module disabled. Wake up when wake up pin is high.
detachInterrupt(1); // Disable external pin interrupt on wake up pin PIN3 (interrupt 1).
so what should I put in the if (something happened) {???}
3) execute sending the event over RFM
4) after xx iterations send health stats.
thanks for your inputs
attachInterrupt(1, wakeUpFromSleepy, HIGH); //interrupt attached to PIN3 Allow wake up pin to trigger interrupt on high.
There is no HIGH interrupt. See the page about attachInterrupt. You can have LOW, CHANGE, RISING, FALLING.
ah, that's quite interesting, even more so because I have the sketch working (on a pro mini) as an interrupt trigger... I'll look at it tonight to see if changing it to RISING makes a difference.
My original question remains however; how would I know the PIN from the PIR has triggered so that I can execute some code based on that after the watchdog timer expires?
As I understand it now, the first line of code (attachInterrupt(1, wakeUpFromSleepy, HIGH); ) makes sure the signal gets picked up by the arduino, the second sleeps the device, the third detaches the interrupt 'cause the device is awake. I am puzzled how to integrate this into the exaple you referred to:
void loop ()
{
// sleep for 8 seconds
myWatchdogEnable (WDT_8_SEC);
// did the PIR trigger??
if (buttonPressed) // <--------------- what do I put here??
showStuff ();
// count number of times we slept
counter++;
// every 48 seconds check the time (6 lots of 8 seconds asleep)
if (counter >= 6)
{
// send health status
counter = 0;
} // end of sleeping for 6 times
} // end of loop
thanks
let me answer my own question; while I was looking for a way to trigger the interrupt within the wait time of the watchdog timer it made much more sense to wake earlier and check more often if my PIR pin was high, which leads to the following code:
for (byte i = 0; i < 300; ++i) { // sleep 10 mins 300*2
if (digitalRead(PirInput)==HIGH) { // apparently the PIR pin is triggered
i = 0; // reset the timer
break; // and break out of the loop
}
LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF); // otherwise go back to sleep for 2 sec
}
if PIN is high send alert RFM msg
otherwise just send health stats, assuming no PIR was triggered
cheers
Why shy away from using an interrupt to wake when PIR goes high?
I just went through this same exercise: watch dog timer plus an asynchronous interrupt source. Maybe it doesn't really matter that much for your application. But it's useful to know how to do it. It isn't that hard.
for (byte i = 0; i < 300; ++i) { // sleep 10 mins 300*2
if (digitalRead(PirInput)==HIGH) { // apparently the PIR pin is triggered
i = 0; // reset the timer
break; // and break out of the loop
}
What does setting i to zero do? It ceases to exist outside the loop, which you just broke out of.
@Nick so that once you get back in the counter starts anew, or so I thought, I actually don't know if the variable is persistent... I might remove it anyway since I'd like to keep the health check coming in periodically anyway, independent if a PIR is triggered... hmmm
@jboyton Could you share your combi code?
thanks!
for (byte i = 0; ...
The counter starts anew right there.
ehh, yes it does
Why shy away from using an interrupt to wake when PIR goes high?
'Cause I couldn't figure it out!, That's why I'd like to take a look at an example
Gandalph:
'Cause I couldn't figure it out!, That's why I'd like to take a look at an example
I understand. I also saved myself a lot of time by using examples: Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors.
I used a different Atmel processor. But other than a few minor details, the specific registers, it is the same. Here is a stripped down version:
// ATtiny841 -- Watchdog + pin change interrupt
// LED flashes briefly once per second via WDT
// LED flashes longer whenever the button is pressed via pin change interrupt
#include <avr/sleep.h>
#include <avr/wdt.h>
#define LED_PIN 0 // 841 pin 2
#define BUTTON_PIN 9 // 841 pin 12 (PCINT1) (PA1)
volatile bool buttonFlag;
// -------------------------------------------------------------------------------------------
// watchdog interrupt
ISR (WDT_vect) {
wdt_disable(); // disable watchdog
} // end of WDT_vect
// Pin change 0 interrupt
ISR (PCINT0_vect) {
buttonFlag = true; // set flag
GIMSK &= ~(1 << PCIE0); // disable interrupt
}
// -------------------------------------------------------------------------------------------
void setup()
{
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
pinMode(BUTTON_PIN, INPUT_PULLUP);
enableButtonInterrupt();
}
// -------------------------------------------------------------------------------------------
void loop()
{
digitalWrite(LED_PIN, HIGH);
if (buttonFlag) {
delay(250);
buttonFlag = false;
enableButtonInterrupt();
} else
delay(25);
digitalWrite(LED_PIN, LOW);
gotoSleep();
}
// -------------------------------------------------------------------------------------------
void gotoSleep()
{
// disable ADC
ADCSRA = 0;
MCUSR = 0;
WDTCSR = bit (WDE);
WDTCSR = bit (WDIE) | bit (WDP2) | bit (WDP1); // set WDIE, and 1 second delay
//WDTCSR = bit (WDIE) | bit (WDP3) | bit (WDP0); // set WDIE, and 8 second delay
wdt_reset();
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
noInterrupts ();
sleep_enable();
interrupts ();
sleep_cpu ();
sleep_disable();
}
// -------------------------------------------------------------------------------------------
void enableButtonInterrupt()
{
noInterrupts();
GIFR |= (1 << PCIF0); // clear pin change 0 interrupt flag
GIMSK |= (1 << PCIE0); // enable interrupt for button press
PCMSK0 |= (1 << PCINT1); // enable specific pin
buttonFlag = false;
interrupts();
}
thanks much, I'll keep on tinkering!