Pages: 1 2 [3] 4   Go Down
Author Topic: Watchdog Timer Interrupt and External Interrupt  (Read 3847 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 0
Posts: 128
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Aah, that makes sense now!
Nick, just checked the Atmel datasheet (page 71), and it appears that INT0 & INT1 will trigger external interrupts.
Michael, INT0 & INT1 correspond to Digital pins 2 & 3, your memory serves you (us) well!

Paul
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 128
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Despite my previous message, I still can't get it to wake from D3.
I have added;

const int BTN_PIN = 2; //wire a button from pin 2 to ground
const int BTN_PIN3 = 3; //wire a button from pin 3 to ground


and

pinMode(BTN_PIN, INPUT_PULLUP);
pinMode(BTN_PIN3, INPUT_PULLUP);


but, grounding pin 3 does not trigger a extInterrupt.
Any thoughts?

Paul
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Post the complete code please, in code tags.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
const int BTN_PIN = 2; //wire a button from pin 2 to ground
...
pinMode(BTN_PIN, INPUT_PULLUP);

That's wrong, though. Pin 2 is interrupt 0.
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 128
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
const int BTN_PIN = 2; //wire a button from pin 2 to ground
...
pinMode(BTN_PIN, INPUT_PULLUP);

That's wrong, though. Pin 2 is interrupt 0.
Yes, and PIN2 (interrupt 0) does cause a wake up.
It's PIN3 (interrupt 1) that doesn't, and which is causing me difficulties.

The full code is on page 2 of this thread by Jack Christensen.

Paul
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

That code does not define an ISR for INT1_vect.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This also needs changing:

Code:
    EICRA = _BV(ISC01);            //configure INT0 to trigger on falling edge
    EIFR = _BV(INTF0);             //ensure interrupt flag cleared
    EIMSK = _BV(INT0);             //enable INT0

Why not use attachInterrupt? That's simpler.
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 128
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nick, I'm punching above my weight here!!
I've just had a look at attachInterrupt and that does not seem straightforward either...
From your tone, I suspect that this would not be easy to implement, so maybe I need to take a step back and try and find a solution using just one pin with interrupt.

Paul
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Not at all, it's simpler using that. Here:

Code:
//Using the watchdog timer, sleep for the given number of intervals,
//then print a message. Prints a dot at each WDT wakeup.
//A button is also connected to provide an external interrupt, print
//a message when the button is pressed.
//Finally, blink an LED after each wake-up regardless of source.
//Using an ATmega328P at 16MHz and 5V, draws ~6.3µA while sleeping, which
//is consistent with only the WDT running.
//
//Jack Christensen 19Nov2013
//CC BY-SA, see http://creativecommons.org/licenses/by-sa/3.0/

#include <avr/wdt.h>
#include <avr/sleep.h>
#include <util/atomic.h>
#include <Streaming.h>            //http://arduiniana.org/libraries/streaming/

const int BTN_PIN = 2;            //wire a button from pin 2 to ground
const int BTN_PIN2 = 3;            //wire a button from pin 3 to ground
const int LED_PIN = 13;           //wire an LED from pin 13 to ground through a proper current-limiting resistor
const int WDT_INTERVALS = 50;     //number of WDT timeouts before printing message
const unsigned long LED_ON_TIME = 200;  //turn on LED for this many ms after each wake-up
const long BAUD_RATE = 115200;

volatile boolean extInterrupt;    //external interrupt flag (button)
volatile boolean wdtInterrupt;    //watchdog timer interrupt flag

void wakeOnInterrupt ()
  {
  extInterrupt = true;
  // don't need the external interrupts any more
  detachInterrupt (0);  
  detachInterrupt (1);  
  }
  
void setup(void)
{
    pinMode(BTN_PIN, INPUT_PULLUP);
    pinMode(BTN_PIN2, INPUT_PULLUP);
    pinMode(LED_PIN, OUTPUT);
    Serial.begin(BAUD_RATE);

    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
        wdt_reset();
        MCUSR &= ~bit(WDRF);                            //clear WDRF
        WDTCSR |= bit(WDCE) | bit(WDE);                 //enable WDTCSR change
        WDTCSR =  bit(WDIE) | bit(WDP3) | bit(WDP0);    //~8 sec
    }
    Serial << endl << F("Setup complete");
}

void loop(void)
{
    static int wdtCount;
    static int btnCount;

    if (wdtCount == 0 || extInterrupt) Serial << endl << F("Sleep");
    Serial.flush();
    Serial.end();
    gotoSleep();

    digitalWrite(LED_PIN, HIGH);    //blink the LED on each wakeup
    delay(LED_ON_TIME);
    digitalWrite(LED_PIN, LOW);

    Serial.begin(BAUD_RATE);
    if (wdtInterrupt) {
        Serial << '.';
        if (++wdtCount >= WDT_INTERVALS) {
            Serial << endl << F("WDT: ") << wdtCount;
            wdtCount = 0;
        }
    }
    if (extInterrupt) {
        Serial << endl << F("Button: ") << ++btnCount;
    }
}

void gotoSleep(void)
{
    byte adcsra = ADCSRA;          //save the ADC Control and Status Register A
    ADCSRA = 0;                    //disable the ADC
    noInterrupts ();     // timed sequences follow
    EIFR = bit (INTF0);  // clear flag for interrupt 0
    EIFR = bit (INTF1);  // clear flag for interrupt 1
    attachInterrupt (0, wakeOnInterrupt, FALLING);
    attachInterrupt (1, wakeOnInterrupt, FALLING);
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    wdtInterrupt = false;
    extInterrupt = false;
    sleep_enable();
    byte mcucr1 = MCUCR | bit(BODS) | bit(BODSE); //turn off the brown-out detector while sleeping
    byte mcucr2 = mcucr1 & ~bit(BODSE);
    MCUCR = mcucr1; //timed sequence
    MCUCR = mcucr2; //BODS stays active for 3 cycles, sleep instruction must be executed while it's active
    interrupts ();      // need interrupts now
    sleep_cpu();                   //go to sleep
    sleep_disable();               //wake up here
    ADCSRA = adcsra;               //restore ADCSRA
}

//handles the Watchdog Time-out Interrupt
ISR(WDT_vect)
{
    wdtInterrupt = true;
}

The wakeOnInterrupt function handles waking on both interrupts.

Compiled and tested OK. Some style changes made (sorry, Jack!).
« Last Edit: December 13, 2013, 05:47:15 pm by Nick Gammon » Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 128
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Not at all, it's simpler using that. Here:

Code:
//Using the watchdog timer, sleep for the given number of intervals,
//then print a message. Prints a dot at each WDT wakeup.
//A button is also connected to provide an external interrupt, print
//a message when the button is pressed.
//Finally, blink an LED after each wake-up regardless of source.
//Using an ATmega328P at 16MHz and 5V, draws ~6.3µA while sleeping, which
//is consistent with only the WDT running.
//
//Jack Christensen 19Nov2013
//CC BY-SA, see http://creativecommons.org/licenses/by-sa/3.0/

#include <avr/wdt.h>
#include <avr/sleep.h>
#include <util/atomic.h>
#include <Streaming.h>            //http://arduiniana.org/libraries/streaming/

const int BTN_PIN = 2;            //wire a button from pin 2 to ground
const int BTN_PIN2 = 3;            //wire a button from pin 2 to ground
const int LED_PIN = 13;           //wire an LED from pin 13 to ground through a proper current-limiting resistor
const int WDT_INTERVALS = 50;     //number of WDT timeouts before printing message
const unsigned long LED_ON_TIME = 200;  //turn on LED for this many ms after each wake-up
const long BAUD_RATE = 115200;

volatile boolean extInterrupt;    //external interrupt flag (button)
volatile boolean wdtInterrupt;    //watchdog timer interrupt flag

void wakeOnInterrupt ()
  {
  extInterrupt = true;
  // don't need the external interrupts any more
  detachInterrupt (0); 
  detachInterrupt (1); 
  }
 
void setup(void)
{
    pinMode(BTN_PIN, INPUT_PULLUP);
    pinMode(BTN_PIN2, INPUT_PULLUP);
    pinMode(LED_PIN, OUTPUT);
    Serial.begin(BAUD_RATE);

    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
        wdt_reset();
        MCUSR &= ~bit(WDRF);                            //clear WDRF
        WDTCSR |= bit(WDCE) | bit(WDE);                 //enable WDTCSR change
        WDTCSR =  bit(WDIE) | bit(WDP3) | bit(WDP0);    //~8 sec
    }
    Serial << endl << F("Setup complete");
}

void loop(void)
{
    static int wdtCount;
    static int btnCount;

    if (wdtCount == 0 || extInterrupt) Serial << endl << F("Sleep");
    Serial.flush();
    Serial.end();
    gotoSleep();

    digitalWrite(LED_PIN, HIGH);    //blink the LED on each wakeup
    delay(LED_ON_TIME);
    digitalWrite(LED_PIN, LOW);

    Serial.begin(BAUD_RATE);
    if (wdtInterrupt) {
        Serial << '.';
        if (++wdtCount >= WDT_INTERVALS) {
            Serial << endl << F("WDT: ") << wdtCount;
            wdtCount = 0;
        }
    }
    if (extInterrupt) {
        Serial << endl << F("Button: ") << ++btnCount;
    }
}

void gotoSleep(void)
{
    byte adcsra = ADCSRA;          //save the ADC Control and Status Register A
    ADCSRA = 0;                    //disable the ADC
    noInterrupts ();     // timed sequences follow
    EIFR = bit (INTF0);  // clear flag for interrupt 0
    EIFR = bit (INTF1);  // clear flag for interrupt 1
    attachInterrupt (0, wakeOnInterrupt, FALLING);
    attachInterrupt (1, wakeOnInterrupt, FALLING);
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    wdtInterrupt = false;
    extInterrupt = false;
    sleep_enable();
    byte mcucr1 = MCUCR | bit(BODS) | bit(BODSE); //turn off the brown-out detector while sleeping
    byte mcucr2 = mcucr1 & ~bit(BODSE);
    MCUCR = mcucr1; //timed sequence
    MCUCR = mcucr2; //BODS stays active for 3 cycles, sleep instruction must be executed while it's active
    interrupts ();      // need interrupts now
    sleep_cpu();                   //go to sleep
    sleep_disable();               //wake up here
    ADCSRA = adcsra;               //restore ADCSRA
}

//handles the Watchdog Time-out Interrupt
ISR(WDT_vect)
{
    wdtInterrupt = true;
}

The wakeOnInterrupt function handles waking on both interrupts.

Compiled and tested OK. Some style changes made (sorry, Jack!).

That's great Nick, thank you very much!
This project has proved a steep learning curve, so I do appreciate your support.

Paul
Logged

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 93
Posts: 3981
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Compiled and tested OK. Some style changes made (sorry, Jack!).

No worries, to each his own! Thanks for getting my back there.

I suppose attachInterrupt() is simpler, but not much. Guess I just like diddling with the registers -- that way if anything goes South, I only have myself to blame. smiley-grin
« Last Edit: December 13, 2013, 07:57:59 pm by Jack Christensen » Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Offline Offline
Full Member
***
Karma: 0
Posts: 128
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

How long, precisely, is each sleep cycle?
My best guess is about 8.7 seconds, but is there a precise figure which could be used to determine reasonably accurate,  longer time periods by repeating the cycle, such as a re-occurring task exactly every 8hrs.
  
« Last Edit: December 18, 2013, 05:36:04 pm by pauldreed » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I suggest you add a real-time clock chip (for around $1) if you want more accurate time-keeping.
Logged

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 93
Posts: 3981
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

How long, precisely, is each sleep cycle?
My best guess is about 8.7 seconds, but is there a precise figure which could be used to determine reasonably accurate,  longer time periods by repeating the cycle, such as a re-occurring task exactly every 8hrs.

Some comments about the accuracy of the WDT:
http://forum.arduino.cc/index.php?topic=201460.msg1484665#msg1484665
http://forum.arduino.cc/index.php?topic=201460.msg1484794#msg1484794
Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Offline Offline
Newbie
*
Karma: 0
Posts: 29
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nick & Jack -

NG reply #38 & JC reply #24

I read this thread with great interest because i have been trying to figure out how to do exactly this for weeks. I have posted threads (questions) on this subject in this forum, and gotten no responses.

And in looking at your codes, I would not have figured it out in this lifetime.  But when i run either code, I get the same error message "in function 'void setup()'  end1 was not declared in this scope".

I am using UNO 1.0.1  I have all of the includes.h

Would either of you take a minute and help me to get your code running . it runs for you, but not for me.

thanks
pat

 

I
Logged

Pages: 1 2 [3] 4   Go Up
Jump to: