Nachdem ich den Minimal-Arduino auf dem Breadboard aufgebaut hatte, wollte ich diesen gerne über eine CR2032-Batterie mit Strom versorgen, und das möglichst lange.
Zum Glück gibt es schon einige Artikel im Internet, die sich mit dem Stromverbrauch des ATMEGA328P auseinandergesetzt haben. Allerdings erwarten hier viele einen Interrupt von Extern, was in meinem Anwendungsfall (halbwegs regelmässig einen Sensor auslesen und die Information abspeichern oder verschicken) nicht ganz praktisch war. Vor allem, weil ich den passenden Uhrenquarz nicht verfügbar habe…
Hier also (nachvollziehbar) die einzelnen Schritte, die ich bei meinem ATMEGA328P unternommen habe, um ihn den hohen Stromverbrauch streitig zu machen.
Step 1: Default blink program with 5s delay, 16 MHz ext. Osz., 3V CR2032-battery
void setup() { // initialize digital pin 13 as an output. pinMode(13, OUTPUT); } void loop() { digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level) delay(5000); // wait for a second digitalWrite(13, LOW); // turn the LED off by making the voltage LOW delay(5000); // wait for a second }
Result:
- LED On: 6.8mA
- LED Off: 5.8mA
Step 2: All other pins as input
void setup() { //To reduce power, setup all pins as inputs with no pullups for(int x = 1 ; x < 18 ; x++){ pinMode(x, INPUT); digitalWrite(x, LOW); } // initialize digital pin 13 as an output. pinMode(13, OUTPUT); } void loop() { digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level) delay(5000); // wait for a second digitalWrite(13, LOW); // turn the LED off by making the voltage LOW delay(5000); // wait for a second }
Result:
- LED On: 6.45mA
- LED Off: 5.65mA
Step 3: Power Down during sleep
I’ll admit that this next step is a bit confusing, as a lot of things are introduced.
#include <avr/sleep.h> //Needed for sleep_mode #include <avr/wdt.h> volatile boolean f_wdt=1; void setup() { //To reduce power, setup all pins as inputs with no pullups for(int x = 1 ; x < 18 ; x++){ pinMode(x, INPUT); digitalWrite(x, LOW); } // initialize digital pin 13 as an output. pinMode(13, OUTPUT); setup_watchdog(8); } byte state=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 switch (state){ case 0: digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level) state = 1; setup_watchdog(0); break; case 1: digitalWrite(13, LOW); // turn the LED off by making the voltage LOW state = 0; setup_watchdog(8); break; } system_sleep(); } } //**************************************************************** // set system into the sleep state // system wakes up when watchdog is timed out void system_sleep() { // power_adc_disable() 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 // power_adc_enable() } //**************************************************************** // 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; if (ii > 9 ) ii=9; bb=ii & 7; if (ii > 7) bb|= (1<<5); bb|= (1<<WDCE); 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 }
Result:
- LED On: 1.07mA
- LED Off: 0.02mA (206uA)
As long as we depend on the internal oscillator, we won’t get any further then 206uA, as the watchdog is still enabled and drawing current. Time to get one of those nice 32kHz-oscillators.
Here are some more links related to this topic, some of those helped me in my process (some in german):
- http://www.mikrocontroller.net/articles/Sleep_Mode
- http://interface.khm.de/index.php/lab/interfaces-advanced/sleep_watchdog_battery/