Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.
 Entire forum ➜ Electronics ➜ Microprocessors ➜ Saving power

Saving power

Postings by administrators only.

Refresh page


Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Mon 30 May 2011 06:18 AM (UTC)

Amended on Sat 14 Jan 2012 09:52 PM (UTC) by Nick Gammon

Message
I had a question on the Arduino forum about saving power for a battery-powered chip mounted in a hard-to-get-at place.

Apart from suggesting a larger battery, the code below shows how you can make the processor go into a "power down" sleep, and let the watchdog timer wake it up some seconds later.

This code also illustrates polling a DS1307 clock chip to find the time of day. The idea being (in this case) that you might only want to do something during business hours (or daytime, or nighttime or whatever). So by checking the time you work out whether we need to do whatever-it-is right now.

To save power the clock itself is powered from a digital pin (pin 5 in this case) so we turn the clock on by setting pin 5 high, read the time, and then power it down again. The clock board itself has a small battery on it which lets it remember the time over something like 10 years.

This is my example board, with the clock mounted:



That board is described here:

http://www.gammon.com.au/forum/?id=11109


This is the sketch:


// Example of sleeping and saving power, and reading a clock
// 
// Author: Nick Gammon
// Date:   25 May 2011

#include <Wire.h>
#include "RTClib.h"

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

RTC_DS1307 RTC;

#define CLOCK_POWER 5

#define LED 13

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

void myWatchdogEnable(const byte interval) {  // turn on watchdog timer; interrupt mode every 2.0s
  MCUSR = 0;                          // reset various flags
  WDTCSR |= 0b00011000;               // see docs, set WDCE, WDE
  WDTCSR =  0b01000000 | interval;    // set WDIE, and appropriate delay

  wdt_reset();
  
  byte adcsra_save = ADCSRA;
  byte prr_save = PRR;

  // disable ADC
  ADCSRA = 0;  
  
  // power reduction register
  // Bit 7 - PRTWI: Power Reduction TWI
  // Bit 6 - PRTIM2: Power Reduction Timer/Counter2
  // Bit 5 - PRTIM0: Power Reduction Timer/Counter0
  // Bit 4 - Res: Reserved bit
  // Bit 3 - PRTIM1: Power Reduction Timer/Counter1
  // Bit 2 - PRSPI: Power Reduction Serial Peripheral Interface
  // Bit 1 - PRUSART0: Power Reduction USART0
  // Bit 0 - PRADC: Power Reduction ADC
  
  // turn off various modules
  PRR = 0b11101111;
    
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
  sleep_mode();            // now goes to Sleep and waits for the interrupt
  
  // stop power reduction
  ADCSRA = adcsra_save;
  PRR = prr_save;
} 

void setup()
{
  pinMode (CLOCK_POWER, OUTPUT);
  digitalWrite (CLOCK_POWER, HIGH);  // power up clock
  delay (1);

  Wire.begin();
  RTC.begin();

  // set time in clock chip if not set before
  if (! RTC.isrunning()) {
    // following line sets the RTC to the date & time this sketch was compiled
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }

  digitalWrite (CLOCK_POWER, LOW);  // power down clock
  
}  // end of setup

void loop()
{

  // power up clock
  digitalWrite (CLOCK_POWER, HIGH);  // power up clock
  delay (1);  // give it time to stabilize

  // activate I2C and clock
  Wire.begin();
  RTC.begin();

  // find the time  
  DateTime now = RTC.now();

  // time now available in now.hour(), now.minute() etc.

  // finished with clock
  digitalWrite (CLOCK_POWER, LOW); 
  
  // turn off I2C pull-ups
  digitalWrite (A4, LOW);
  digitalWrite (A5, LOW);
  
  // turn off I2C
  TWCR &= ~(_BV(TWEN) | _BV(TWIE) | _BV(TWEA));

  // -------- do something here if required by the time of day

  // in my case flash an LED for 5 seconds
  pinMode (LED, OUTPUT);
  digitalWrite (LED, HIGH);
  delay (5000);
  digitalWrite (LED, LOW);
  
  // sleep bit patterns:
  //  1 second:  0b000110
  //  2 seconds: 0b000111
  //  4 seconds: 0b100000
  //  8 seconds: 0b100001

  // sleep for a total of 20 seconds
  myWatchdogEnable (0b100001);  // 8 seconds
  myWatchdogEnable (0b100001);  // 8 seconds
  myWatchdogEnable (0b100000);  // 4 seconds

}  // end of loop



It uses about 19 mA when awake (some of which would be the LED) but only 25 uA (0.025 mA) when asleep. 25 uA isn't much, and would not drain your battery very quickly.

Measurements indicate that the clock chip was powered up for 2 ms (1 one of which was the delay for it to get ready) so that means that (during the 8 second cycles) the higher power consumption only applied for 1/4000 of the duty cycle.

[EDIT] Further tests show that if you disable the brown-out detection (by changing a fuse byte) you can greatly save power, especially in sleep mode. With brown-out detection disabled power consumption goes down to around 6 uA. This is because the brown-out detection needs an internal voltage reference to be running.

For more information about power saving:

Template:post=11497 Please see the forum thread: http://gammon.com.au/forum/?id=11497.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by David DeFilippis   (4 posts)  Bio
Date Reply #1 on Fri 02 Dec 2011 07:59 PM (UTC)
Message
I cannot get this code to compile to an Arduino Mega 2560. The board runs on the Amtel ATmega2560. I do not have a lot of experience in computer sciences but I am assuming that the avr/wdt.h library doesn't cover this chip. If there is any advice or help that you could give me it would be greatly appreciated.

here is a link to the chip's datasheet http://www.atmel.com/dyn/resources/prod_documents/doc2549.PDF

here is the error that I get from the compiler
sketch_dec02a.cpp: In function 'void myWatchdogEnable(byte)':
sketch_dec02a:30: error: 'PRR' was not declared in this scope

Thank you for your time,

David DeFilippis
Top

Posted by Nick Gammon   Australia  (23,120 posts)  Bio   Forum Administrator
Date Reply #2 on Sat 03 Dec 2011 09:01 AM (UTC)
Message
Did you search the data sheet for PRR? It looks like the 2560 has PRR0 and PRR1 (because it has more things in it).

By the looks of it, PRR0 has the same functionality of PRR on the smaller chips.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


23,920 views.

Postings by administrators only.

Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.