"misbehaving" Watchdog

I’m starting to play with the Watchdog Timer (which is pretty awesome, BTW) using the LED with my ATtiny85 to learn more how to use it.

I’ve used some web resources to put together the following sketch, but it is not working exactly as I wanted to, and was wondering if anyone would have some advice to share. So, here’s what is happening:

What I want the ATtiny85 do is:
a. sleep for 8 seconds, and do this continuously for 8 cycles (~64 sec)
b. when it reaches ~64 sec, turn on the LED
c. after 220 seconds, turn LED off
d. go back to #a

But instead, what my sketch is doing now is:
a. sleep for 8 seconds, and do this continuously for 8 cycles (~64 sec)
b. when it reaches ~64 sec, turn on the LED
c. after 220 seconds, turn LED off
d. after~1 second, it goes back to #b, and repeats the cycle b through d

My guess is that the problem is in the loop section, since it seems that it is running the led commands infinitely without calling the sleep function at the end.

Therefore, how can I tell the ATtiny to do the entire process (a. through d.) over and over again?


#include <avr/sleep.h>
#include <avr/power.h>
int LED = 0;
volatile long watchdog_counter = 0;

void setup(void)
  ADCSRA &= ~(1<<ADEN); //Disable ADC
  ACSR = (1<<ACD); //Disable the analog comparator
  DIDR0 = 0x3F; //Disable digital input buffers on all ADC0-ADC5 pins to save power
  setup_watchdog(9);      // 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms
                          // 6=1 sec, 7=2 sec, 8=4 sec, 9= 8sec
   pinMode(LED, OUTPUT);

void loop()
  if (watchdog_counter >= 8) {  // # of watchdog cycles                                 
    watchdog_counter = 0;

void commands_to_carry_out() {
  digitalWrite(LED, HIGH);
  delay(220000);    // 220000 = ==> 220 sec (3.6 min)
  digitalWrite(LED, LOW);
  delay(1000);    // wait 1 second before going to sleep

void setup_watchdog(int ii) {
  byte bb;
  int ww;
  if (ii > 9 ) ii=9;
  bb=ii & 7;
  if (ii > 7) bb|= (1<<5);
  bb|= (1<<WDCE);
  MCUSR &= ~(1<<WDRF);
  // start timed sequence
  WDTCR_REG |= (1<<WDCE) | (1<<WDE);
  // set new watchdog timeout value
  WDTCR_REG = bb;

ISR(WDT_vect) {

haha never mind. I just realized that it was all due to the nested loop I had. Once that is removed, voila! :-p

Actually... I am still having the "infinite loop" problem! (I just realized that the "nested loop" has nothing to do) :frowning:

Any suggestions on what I can do to have it do the entire a. though d. process?

I think that what’s happening is the watchdog is still triggering and incrementing watchdog_counter while commands_to_carry_out() is executing. ThHis means that next time loop() executes watchdog_counter is already up to some high value, rather than zero as you might expect from the code.

A minimal change to address that would be to put the watchdog_counter = 0 assignment after the call to commands_to_carry_out().

An alternative way to structure this which would simplify the code would be to get rid of all the code to do with watchdog_counter and just use a for loop to call sleep_mode() eight times and then carry out the rest of your logic.

I modified the sketch I did in another thread to show the use of the watchdog, and the pin-change interrupt:

// ATtiny85 sleep mode, wake on pin change interrupt demo
// Author: Nick Gammon
// Date: 12 October 2013

//                  +-\/-+
// Ain0 (D 5) PB5  1|    |8  Vcc
// Ain3 (D 3) PB3  2|    |7  PB2 (D 2) Ain1
// Ain2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1
//            GND  4|    |5  PB0 (D 0) pwm0
//                  +----+

#include <avr/sleep.h>    // Sleep Modes
#include <avr/power.h>    // Power management
#include <avr/wdt.h>      // Watchdog timer

const byte LED = 3;  // pin 2
const byte SWITCH = 4; // pin 3 / PCINT4

ISR (PCINT0_vect) 
 // do something interesting here
 }  // end of PCINT0_vect
// watchdog interrupt
ISR (WDT_vect) 
   wdt_disable();  // disable watchdog
}  // end of WDT_vect

void resetWatchdog ()
  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset, clear existing interrupt
  WDTCR = bit (WDCE) | bit (WDE) | bit (WDIF);
  // set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
  WDTCR = bit (WDIE) | bit (WDP3) | bit (WDP0);    // set WDIE, and 8 seconds delay
  // pat the dog
  }  // end of resetWatchdog
void setup ()
  resetWatchdog ();  // do this first in case WDT fires
  pinMode (LED, OUTPUT);
  pinMode (SWITCH, INPUT);
  digitalWrite (SWITCH, HIGH);  // internal pull-up
  // pin change interrupt (example for D4)
  PCMSK  = bit (PCINT4);  // want pin D4 / pin 3
  GIFR  |= bit (PCIF);    // clear any outstanding interrupts
  GIMSK |= bit (PCIE);    // enable pin change interrupts 
  }  // end of setup

void loop ()
  digitalWrite (LED, HIGH);
  delay (500); 
  digitalWrite (LED, LOW);
  delay (500); 
  goToSleep ();
  }  // end of loop
void goToSleep ()
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  ADCSRA = 0;            // turn off ADC
  power_all_disable ();  // power off ADC, Timer 0 and 1, serial interface
  noInterrupts ();       // timed sequence coming up
  resetWatchdog ();      // get watchdog ready
  sleep_enable ();       // ready to sleep
  interrupts ();         // interrupts are required now
  sleep_cpu ();          // sleep                
  sleep_disable ();      // precaution
  power_all_enable ();   // power everything back on
  }  // end of goToSleep

Power consumption when asleep: 6.66 µA (LOL).

Again, this agrees with the datasheet, page 184:

Other thread: Problem coding tiny85, Sleep Mode, PinChangeInterrupt, 2 buttons interrupt - Programming Questions - Arduino Forum

Hi guys

this is actually really useful. Thank you so much! I am really really grateful for all the insights & knowledge you have for sharing. It really helps as you are trying to better understand what these amazing little Arduino guys can do :slight_smile: