Posted by
| Nick Gammon
Australia (22,928 posts) bio
Forum Administrator |
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:
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | top |
|