Using sleep mode effectivelly

An old thread was not answered at the time and was in a funny place so I bring back here.

Is anyone able to bring chip out of sleep mode without external trigger.

Is chip able to count 30 minutes while in sleep mode then wake up . Any other way to count externally to 30 min then trigger wake up.

Any new thought here?

I see this comment at http://www.sensor-networks.org/index.php?page=0820520514 but do not understand?

In Arduino we are going to use power save mode to save power and as interrupt source we are going to use the overflow interrupt in timer 2.

Timer 2 is a 8 bit counter (counts until 255) and is able to trigger an overflow interrupt if we also use a 10 bits preescaler we divide the frecuency by 1024 and we get an interrupt source that is triggered 61 times per seconds (16000000 / 1024 / 255 = 61).

This is what I need .How can I program to do this and bring back after 30 minutes

From Data sheet ATMega328 9.5 Power-down Mode When the SM2..0 bits are written to 010, the SLEEP instruction makes the MCU enter Power- down mode. In this mode, the external Oscillator is stopped, while the external interrupts, the 2- wire Serial Interface address watch, and the Watchdog continue operating (if enabled). Only an External Reset, a Watchdog System Reset, a Watchdog Interrupt, a Brown-out Reset, a 2-wire Serial Interface address match, an external level interrupt on INT0 or INT1, or a pin change interrupt can wake up the MCU. This sleep mode basically halts all generated clocks, allowing operation of asynchronous modules only. Note that if a level triggered interrupt is used for wake-up from Power-down mode, the changed level must be held for some time to wake up the MCU. Refer to ”External Interrupts” on page 70 for details. When waking up from Power-down mode, there is a delay from the wake-up condition occurs until the wake-up becomes effective. This allows the clock to restart and become stable after having been stopped. The wake-up period is defined by the same CKSEL Fuses that define the Reset Time-out period, as described in ”Clock Sources” on page 27.

I can turn off Watchdog and ADC and others and bring back on when awake. I look for the code to turn everything off except one timer to count the 30 minutes then bring it back and turn them all on again. I have external occillator crystal operating on the arduino board anyway

There is no single "sleep mode".

In the first quote, they're using "power-save" mode, which leaves the timer oscillator enabled. In the second quote, they're talking about "power-down" mode, which allows only external stimulii (INT0, INT1, TWI address match, WDT and BDO).

See section "9.1 Sleep Mode[u]s[/u]" in the device datasheet for a better explanation of the various sleep mode[u]s[/u].

Is anyone able to bring chip out of sleep mode without external trigger. Is chip able to count 30 minutes while in sleep mode then wake up . Any other way to count externally to 30 min then trigger wake up. Any new thought here?

Hi! To answer your questions:

  1. Yes. Anyone who reads the mentioned article will have the knowledge to wake up the Arduino without external trigger. Here is another good article:
    http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/

  2. If you want to not have a timer wake up the chip multiple times, increase a counter and when the counter has counted to a specific value, i.e. the 30 min, but to count only once you have to run the chip very slow - in the KHz area. That means to attach a “slow” resonator to the atmega chip. You are asking about the chip, not the Arduino itself, which is “locked” to 16 MHz.
    And secondly - yes, you can build an external trigger circuit with an 555 timer in monostable mode, that you can generate a PCInt or an external interrupt. Here are some good descriptions of 555 circuits: 555 and 556 Timer Circuits

Is chip able to count 30 minutes while in sleep mode then wake up

Please note: there is no single "sleep mode" - there are several. It is pointless to keep referring to "sleep mode" unless you specify which one you mean.

However, you could wake up the processor from power-down mode in little bursts every time the watchdog times out. Count the watchdog timeouts until 30 minutes has elapsed. This is what the nightingale example does. To get a single 30 minute timeout in power-down mode, you'd probably have to supply a very slow external clock, which may well cost you more in micro-amps than you save. [edit]Scratch that: the watchdog has its own oscillator, duh. {smacks forehead}[/edit]

Thanks . The last two posts offer more potential. I will use any sleep mode that gets the job done and attaching an external timer seems will use more than chip in turned on mode.

Some important notes about the watchdog oscillator...

  • It is not accurate. Expect it to be wrong by as much as 10%.
  • It is dependant on temperature. Warm the processor and the oscillator runs at a different rate.
  • It is dependant on processor load. Turn a few digital outputs high and the oscillator runs at a different rate.
  • It "jitters". Even when everything is kept constant, the oscillator runs at slightly different rates.

Yes thank you . I do not care if it delays 30 minutes or 34 minutes as long as it turns off between these read times.

Trouble is it seems to interfere with Dallas temperature sensors atm and the chip will turn off for 30 mins but I cannot get a Dallas reading for some reason?

If you read that article, you probably see, that by default, you can set processor to sleep for max 8sec. My solution is to multiply this 8s to get the wanted down-time. See the code, this example will blink the led 10 times every 80 seconds (approx.):

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

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

int nint;
int pinLed=13;

volatile boolean f_wdt=1;

void setup(){

  Serial.begin(9600);
  pinMode(pinLed,OUTPUT);
  Serial.println("Setup watchdog");

  // CPU Sleep Modes
  // SM2 SM1 SM0 Sleep Mode
  // 0    0  0 Idle
  // 0    0  1 ADC Noise Reduction
  // 0    1  0 Power-down
  // 0    1  1 Power-save
  // 1    0  0 Reserved
  // 1    0  1 Reserved
  // 1    1  0 Standby(1)

  cbi( SMCR,SE );      // sleep enable, power down mode
  cbi( SMCR,SM0 );     // power down mode
  sbi( SMCR,SM1 );     // power down mode
  cbi( SMCR,SM2 );     // power down mode

  setup_watchdog(9);

}

byte del;
int cnt;
int counter = 10; // timer for counting watchdog cicles
long time = 0;

//****************************************************************
//****************************************************************
//****************************************************************
void loop(){

  if (f_wdt==1) {  // wait for timed out watchdog / flag is set when a watchdog timeout occurs
    f_wdt=0;       // reset flag

    ///// debuging purpose only /////
    time = millis();
    Serial.print(counter); 
    Serial.print(" "); 
    Serial.println(time);
    delay(2); //needed for serial.print operation to finish
    /////////////////////////////////////

    if(counter==10)  // if ==10 -> this will be true every 10x8 = 80seconds; set to 225 to get 225x8=1800s = 30min 
    {

      //////////////// put code inside this IF ////////
      
      pinMode(pinLed,INPUT); // set all used port to intput to save power

      for(int i=0; i<10; i++)
      {
        digitalWrite(pinLed, HIGH);
        delay(90);
        digitalWrite(pinLed, LOW);
        delay(90);  
      }

      pinMode(pinLed,OUTPUT); // set all ports into state before sleep
      
      ////////////////////////////////////////////////////
      
      counter = 0;
    }
    else counter++;

    system_sleep();

  }

}


//****************************************************************
// set system into the sleep state
// system wakes up when wtchdog is timed out
void system_sleep() {

  cbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter OFF

  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
  sleep_enable();

  sleep_mode();                        // System sleeps here

    sleep_disable();                     // System continues execution here when watchdog timed out
  sbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter ON

}

//****************************************************************
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
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);
  ww=bb;
  Serial.println(ww);


  MCUSR &= ~(1<<WDRF);
  // start timed sequence
  WDTCSR |= (1<<WDCE) | (1<<WDE);
  // set new watchdog timeout value
  WDTCSR = bb;
  WDTCSR |= _BV(WDIE);

}
//****************************************************************
// Watchdog Interrupt Service / is executed when  watchdog timed out
ISR(WDT_vect) {
  f_wdt=1;  // set global flag
}

What dallas sensor are you using? 1-Wire? If so, do you have a delay before Read command?

Regards,
Peter

Thank you Odisej

No I dont have delay before read ,I will try Thanks for above code I will work it some while and come back

Is so I do have a delay before the read. I saw this some time ago related to analog inputs only as they are multiplexed to the ADC.

I am using a digital pin 7 to read the 1 wire signal for the dallas device.
Watchdog example works fine The dallas example tester in the library works too if I just put that on arduino. Still working on your program to work

So both examples work apart on own. Problem comes when combining both into one program. Watchdog is interfering somehow.
On a tested and working sensor I get one reading only eg 28.50C and it stays the same reading even when I heat sensor.

I just would like to point out that the Arduino is NOT hardwired to 16 MHz. You can overwrite the prescaler with

#include <avr/power.h>

...

clock_prescale_set(value);

value = n → prescale by 2^n maximum value for n is found in the datasheet. I think 8 is the maximum → 16 MHz / 256 gives 62.6 kHz.

It is possible to combine this with sleep modes. I found in my project that if I put the processor to idle then it will consume less power if I prescale as well. In my project I could not use a deeper sleep mode, but idle plus prescaling gave significant power reduction as well.

Cheers, Udo

Ok, I don’t have a sensor with me, but try this code:

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

OneWire ds(7); 

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

int nint;
int pinLed=13;

volatile boolean f_wdt=1;

//////// 1- wire variables /////////
int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;

byte i;
byte present = 0;
byte data[12];
byte addr[8]; 
////////////////

void setup(){

  Serial.begin(9600);
  pinMode(pinLed,OUTPUT);
  Serial.println("Setup watchdog");

  // CPU Sleep Modes
  // SM2 SM1 SM0 Sleep Mode
  // 0    0  0 Idle
  // 0    0  1 ADC Noise Reduction
  // 0    1  0 Power-down
  // 0    1  1 Power-save
  // 1    0  0 Reserved
  // 1    0  1 Reserved
  // 1    1  0 Standby(1)

  cbi( SMCR,SE );      // sleep enable, power down mode
  cbi( SMCR,SM0 );     // power down mode
  sbi( SMCR,SM1 );     // power down mode
  cbi( SMCR,SM2 );     // power down mode

  setup_watchdog(9);

}

byte del;
int cnt;
int counter = 10; // timer for counting watchdog cicles
long time = 0;

//****************************************************************
//****************************************************************
//****************************************************************
void loop(){

  if (f_wdt==1) {  // wait for timed out watchdog / flag is set when a watchdog timeout occurs
    f_wdt=0;       // reset flag

    /* ///// debuging purpose only ///// 
     time = millis();
     Serial.print(counter);
     Serial.print(" ");
     Serial.println(time);
     delay(2); //needed for serial.print operation to finish
     */    ////////////////////////////////////

    if(counter==10)  // if ==10 -> this will be true every 10x8 = 80seconds; set to 225 to get 225x8=1800s = 30min
    {

      //////////////// put code inside this IF ////////

      pinMode(pinLed,INPUT); // set all used port to intput to save power

      for(int i=0; i<10; i++)
      {
        digitalWrite(pinLed, HIGH);
        delay(90);
        digitalWrite(pinLed, LOW);
        delay(90);  
      }

      ///////// 1-wire //////////
      ds.reset();
      ds.skip();
      ds.write(0x44,1);         // start conversion, with parasite power on at the end

      delay(1000);     // maybe 750ms is enough, maybe not
      // we might do a ds.depower() here, but the reset will take care of it.

      present = ds.reset();
      ds.skip();    
      ds.write(0xBE);         // Read Scratchpad


      for ( i = 0; i < 9; i++) {           // we need 9 bytes
        data[i] = ds.read();
      }


      LowByte = data[0];
      HighByte = data[1];
      TReading = (HighByte << 8) + LowByte;
      SignBit = TReading & 0x8000;  // test most sig bit
      if (SignBit) // negative
      {
        TReading = (TReading ^ 0xffff) + 1; // 2's comp
      }
      Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25


      Whole = Tc_100 / 100;  // separate off the whole and fractional portions
      Fract = Tc_100 % 100;


      if (SignBit) // If its negative
      {
        Serial.print("-");
      }
      Serial.print(Whole);
      Serial.print(".");
      if (Fract < 10)
      {
        Serial.print("0");
      }
      Serial.print(Fract);

      Serial.print("\n");
      ///////////////1-wire end///////////

      pinMode(pinLed,OUTPUT); // set all ports into state before sleep

      ////////////////////////////////////////////////////

      counter = 0;
    }
    else counter++;

    system_sleep();

  }

}


//****************************************************************
// set system into the sleep state
// system wakes up when wtchdog is timed out
void system_sleep() {

  cbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter OFF

  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
  sleep_enable();

  sleep_mode();                        // System sleeps here

    sleep_disable();                     // System continues execution here when watchdog timed out
  sbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter ON

}

//****************************************************************
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
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);
  ww=bb;
  Serial.println(ww);


  MCUSR &= ~(1<<WDRF);
  // start timed sequence
  WDTCSR |= (1<<WDCE) | (1<<WDE);
  // set new watchdog timeout value
  WDTCSR = bb;
  WDTCSR |= _BV(WDIE);

}
//****************************************************************
// Watchdog Interrupt Service / is executed when  watchdog timed out
ISR(WDT_vect) {
  f_wdt=1;  // set global flag
}
      pinMode(pinLed,INPUT); // set all used port to intput to save power

      for(int i=0; i<10; i++)
      {
        digitalWrite(pinLed, HIGH);
        delay(90);
        digitalWrite(pinLed, LOW);
        delay(90);
      }

If you’ve just set the pin to INPUT, how does the LED light by simply enabling and disabling the internal pull-ups?

It will light very dim and consume very little power... I did this once by mistake :)

Whoooops, there’s a glitch, my mistake. I guess I copyed the wrong code, from one of my tests… you need to do “input” before going to sleep and put back to “output” when exiting sleep.

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

OneWire ds(7);

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

int nint;
int pinLed=13;

volatile boolean f_wdt=1;

//////// 1- wire variables /////////
int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;

byte i;
byte present = 0;
byte data[12];
byte addr[8];
////////////////

void setup(){

  Serial.begin(9600);
  pinMode(pinLed,OUTPUT);
  Serial.println("Setup watchdog");

  // CPU Sleep Modes
  // SM2 SM1 SM0 Sleep Mode
  // 0    0  0 Idle
  // 0    0  1 ADC Noise Reduction
  // 0    1  0 Power-down
  // 0    1  1 Power-save
  // 1    0  0 Reserved
  // 1    0  1 Reserved
  // 1    1  0 Standby(1)

  cbi( SMCR,SE );      // sleep enable, power down mode
  cbi( SMCR,SM0 );     // power down mode
  sbi( SMCR,SM1 );     // power down mode
  cbi( SMCR,SM2 );     // power down mode

  setup_watchdog(9);

}

byte del;
int cnt;
int counter = 10; // timer for counting watchdog cicles
long time = 0;

//****************************************************************
//****************************************************************
//****************************************************************
void loop(){

  if (f_wdt==1) {  // wait for timed out watchdog / flag is set when a watchdog timeout occurs
    f_wdt=0;       // reset flag

    /* ///// debuging purpose only /////
     time = millis();
     Serial.print(counter);
     Serial.print(" ");
     Serial.println(time);
     delay(2); //needed for serial.print operation to finish
     */    ////////////////////////////////////

    if(counter==10)  // if ==10 -> this will be true every 10x8 = 80seconds; set to 225 to get 225x8=1800s = 30min
    {

      //////////////// put code inside this IF ////////

      pinMode(pinLed,OUTPUT); // set all used port to intput to save power

      for(int i=0; i<10; i++)
      {
        digitalWrite(pinLed, HIGH);
        delay(90);
        digitalWrite(pinLed, LOW);
        delay(90);
      }

      ///////// 1-wire //////////
      ds.reset();
      ds.skip();
      ds.write(0x44,1);         // start conversion, with parasite power on at the end

      delay(1000);     // maybe 750ms is enough, maybe not
      // we might do a ds.depower() here, but the reset will take care of it.

      present = ds.reset();
      ds.skip();
      ds.write(0xBE);         // Read Scratchpad


      for ( i = 0; i < 9; i++) {           // we need 9 bytes
        data[i] = ds.read();
      }


      LowByte = data[0];
      HighByte = data[1];
      TReading = (HighByte << 8) + LowByte;
      SignBit = TReading & 0x8000;  // test most sig bit
      if (SignBit) // negative
      {
        TReading = (TReading ^ 0xffff) + 1; // 2's comp
      }
      Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25


      Whole = Tc_100 / 100;  // separate off the whole and fractional portions
      Fract = Tc_100 % 100;


      if (SignBit) // If its negative
      {
        Serial.print("-");
      }
      Serial.print(Whole);
      Serial.print(".");
      if (Fract < 10)
      {
        Serial.print("0");
      }
      Serial.print(Fract);

      Serial.print("\n");
      ///////////////1-wire end///////////

      pinMode(pinLed,INPUT); // set all ports into state before sleep

      ////////////////////////////////////////////////////

      counter = 0;
    }
    else counter++;

    system_sleep();

  }

}


//****************************************************************
// set system into the sleep state
// system wakes up when wtchdog is timed out
void system_sleep() {

  cbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter OFF

  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
  sleep_enable();

  sleep_mode();                        // System sleeps here

    sleep_disable();                     // System continues execution here when watchdog timed out
  sbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter ON

}

//****************************************************************
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
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);
  ww=bb;
  Serial.println(ww);


  MCUSR &= ~(1<<WDRF);
  // start timed sequence
  WDTCSR |= (1<<WDCE) | (1<<WDE);
  // set new watchdog timeout value
  WDTCSR = bb;
  WDTCSR |= _BV(WDIE);

}
//****************************************************************
// Watchdog Interrupt Service / is executed when  watchdog timed out
ISR(WDT_vect) {
  f_wdt=1;  // set global flag
}

Thanks again Odisej
I have tried your code above and with debugging on get the count OK but not the temperature . Code is reading the sensor but this bit below seems to give wrong type of write in terminal output
.

///////// 1-wire //////////
ds.reset();
ds.skip();
ds.write(0x44,1); // start conversion, with parasite power on at the end

delay(1000); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.

present = ds.reset();
ds.skip();
ds.write(0xBE); // Read Scratchpad

for ( i = 0; i < 9; i++) { // we need 9 bytes
data = ds.read();

  • }*
  • LowByte = data[0];*
  • HighByte = data[1];*
  • TReading = (HighByte << 8) + LowByte;*
  • SignBit = TReading & 0x8000; // test most sig bit*
  • if (SignBit) // negative*
  • {*
  • TReading = (TReading ^ 0xffff) + 1; // 2’s comp*
  • }*
    Tc_100 = (6 * TReading) + TReading / 4; // multiply by (100 * 0.0625) or 6.25
  • Whole = Tc_100 / 100; // separate off the whole and fractional portions*
  • Fract = Tc_100 % 100;*
  • if (SignBit) // If its negative*
  • {*
  • Serial.print("-");*
  • }*
  • Serial.print(Whole);*
  • Serial.print(".");*
  • if (Fract < 10)*
  • {*
  • Serial.print(“0”);*
  • }*
  • Serial.print(Fract);*
  • Serial.print("\n");*
  • ///////////////1-wire end///////////*
    [/quote]

this bit below seems to give wrong type of write

And the right type of write would be what, exactly?

OMG, I'm so sory. I forgot a small detail... put a small delay (let's say delay(2); ) after printing the last thing on serial. That is to finish the transmission before processor sleeps.

I'll test the code when I find one of my arduino's :)

OMG, I'm so sory. I forgot a small detail

Don't knock yourself out about it - the delay was there in your first post at reply #8! :)

Maybe worth commenting that the delay is baud-rate dependent, i.e a slower baud rate will need a longer delay, to allow the UART time to clock out the last character.