A standard Arduino Uno running at full speed draws roughly 40–50 mA from 5V — that’s about 200–250 mW of continuous power. A typical 9V alkaline battery holds around 500 mAh, giving you barely 10 hours of runtime. For most IoT sensors, weather stations, or remote monitoring devices that need to run for weeks or months on a battery, that equation simply does not work. This arduino low power sleep mode guide covers every technique available — from the built-in sleep modes to peripheral shutdown and optimized hardware selection — to turn your Arduino into an ultra-low-power device that can run for years on two AA batteries.
Table of Contents
- What Draws Power on an Arduino?
- AVR Sleep Modes Explained
- Using the LowPower Library
- Watchdog Timer for Timed Wake-up
- Disabling Unused Peripherals
- Hardware-level Power Reduction
- Real-world Current Measurements
- FAQ
What Draws Power on an Arduino?
Before optimizing, understand where the current goes on a standard Arduino Uno:
- ATmega328P MCU at 16 MHz, 5V: ~12–15 mA (clock-dependent)
- USB-to-serial chip (ATmega16U2 or CH340): ~7–15 mA (continuously active even without USB)
- Power LED (red LED via voltage regulator): ~5 mA (pure waste in battery designs)
- Onboard 5V linear regulator: conversion losses (especially high when input voltage is much higher than 5V)
- Peripherals: SPI, I2C, ADC, UART — each adds milliamps when active
For serious battery projects, the standard Arduino Uno form factor is the wrong choice. A bare ATmega328P on a custom PCB or an Arduino Pro Mini with the power LED and regulator removed can reach as low as 0.1–4 µA in deep sleep — a 10,000× improvement over a stock Uno.
AVR Sleep Modes Explained
The ATmega328P has six sleep modes, each trading off functionality for power savings. They are listed from lightest to deepest sleep:
1. Idle Mode (~6 mA saved)
CPU clock is halted but all peripherals continue running: timers, SPI, UART, ADC, I2C, TWI. Wake-up is fast (6 clock cycles). Used for: waiting for a hardware interrupt while keeping timers running.
2. ADC Noise Reduction Mode
CPU and most clocks halted, ADC continues. Specifically designed to reduce digital switching noise during ADC conversions. Wake-up sources: ADC conversion complete, external interrupt, TWI address match, Timer 2 interrupt, watchdog.
3. Power-save Mode
Same as power-down but Timer 2 can remain active (using the external 32.768 kHz crystal if installed). Useful for maintaining a real-time clock while the rest of the MCU sleeps.
4. Standby Mode
Like power-down but with the oscillator kept running, allowing faster wake-up (6 clock cycles vs. 6 ms in power-down). Only available when an external crystal is used.
5. Extended Standby Mode
Like power-save mode but with the oscillator also kept running.
6. Power-down Mode (~0.1–4 µA) — The Most Useful
All clocks stopped. Only wake-up sources: external level interrupt on INT0/INT1, pin change interrupt, TWI address match, watchdog timer (if configured). This is the mode to use for battery applications where the device wakes up periodically to take a reading and then goes back to sleep.
Using the LowPower Library
The LowPower library by Rocket Scream Electronics is the most convenient way to use AVR sleep modes in Arduino. Install it via Sketch → Include Library → Manage Libraries, search for “Low-Power” by Rocket Scream.
Basic Power-down with Watchdog Wake-up
#include <LowPower.h>
void setup() {
Serial.begin(9600);
}
void loop() {
// Do work here (take sensor reading, transmit, etc.)
Serial.println("Taking reading...");
Serial.flush(); // Wait for transmission before sleeping
// Sleep for 8 seconds (max watchdog period)
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
// Execution resumes here after wake-up
}
The BOD_OFF parameter disables the Brown-Out Detector during sleep, saving an additional ~25 µA. The ADC_OFF parameter shuts down the ADC before sleep (saves ~0.3 mA). Always call Serial.flush() before sleeping to ensure the UART transmit buffer is empty — the UART transmitter stops during power-down and any unsent bytes will be lost.
Sleeping for Longer Periods
The watchdog timer’s maximum single sleep period is 8 seconds. For longer periods (e.g., 5 minutes), loop the sleep:
// Sleep for approximately 5 minutes (37 × 8s = 296s ≈ 5 min)
for (int i = 0; i < 37; i++) {
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
Each 8-second sleep draws ~0.4 µA with a bare ATmega328P (Pro Mini with power LED removed). At 0.4 µA for 296 seconds, the MCU consumes just 0.118 µAs per 5-minute cycle — essentially negligible compared to the active burst for the sensor reading.
Watchdog Timer for Timed Wake-up
The Watchdog Timer (WDT) is a separate oscillator that continues running during power-down sleep. When the WDT expires, it generates an interrupt that wakes the MCU. Available periods (via wdt.h directly):
- WDTO_15MS, WDTO_30MS, WDTO_60MS, WDTO_120MS
- WDTO_250MS, WDTO_500MS, WDTO_1S, WDTO_2S, WDTO_4S, WDTO_8S
When using the watchdog as a wake-up source only (not as a reset watchdog), configure it in interrupt mode, not reset mode. The LowPower library handles this correctly — if you implement the WDT manually, ensure you disable the WDT reset mode and enable only the interrupt mode via the WDCE/WDE/WDIE bit sequence.
External Interrupt Wake-up
For event-driven wake-up (e.g., a door sensor, PIR motion detector, or button press), use external interrupts instead of the watchdog:
#include <LowPower.h>
void wakeISR() {} // Empty ISR — just wakes the CPU
void setup() {
attachInterrupt(digitalPinToInterrupt(2), wakeISR, LOW);
}
void loop() {
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
// Wakes only when pin 2 goes LOW
// Do work...
}
SLEEP_FOREVER means the MCU sleeps until an external interrupt wakes it, with no watchdog timeout. This achieves the absolute minimum power draw.
Disabling Unused Peripherals
Even in power-down mode, some peripherals can consume current if not explicitly disabled. The ATmega328P’s Power Reduction Register (PRR) allows individual peripheral clocks to be shut off:
// Disable all unused peripherals before sleep
power_adc_disable(); // ADC — saves ~0.3 mA
power_spi_disable(); // SPI
power_timer0_disable(); // Timer 0 (disables millis/micros — call before sleep only!)
power_timer1_disable(); // Timer 1
power_timer2_disable(); // Timer 2
power_twi_disable(); // I2C/TWI
power_usart0_disable(); // UART
// After waking up, re-enable what you need:
power_adc_enable();
power_usart0_enable();
// etc.
The power_* functions come from avr/power.h, which the LowPower library includes automatically. Note that disabling Timer 0 disables millis() and micros() — only do this immediately before sleeping and re-enable before any code that uses timing functions.
Hardware-level Power Reduction
Choose 3.3V Operation
Power consumption scales with the square of voltage for switching (dynamic power) and linearly for leakage. An ATmega328P at 3.3V/8 MHz consumes about 3 mA active vs. 9 mA at 5V/16 MHz — a 3× reduction. The Pro Mini 3.3V/8 MHz is purpose-built for this.
Remove or Bypass the Linear Regulator
If powering from a LiPo battery (3.7V nominal), bypass the onboard linear regulator entirely and connect battery directly to the MCU’s VCC pin through a 100 µF decoupling capacitor. Linear regulators waste input-output voltage difference as heat.
Use a Switching Regulator (Buck or Buck-boost)
For higher-voltage batteries (4× AA = 6V, 2× 18650 = 7.4V), use a switching regulator (e.g., MCP1640, TPS61222) instead of the linear regulator. Switching regulators achieve 85–95% efficiency vs. ~50% for linear regulators at typical input/output differentials.
Power Sensors from a GPIO Pin
Instead of wiring sensors directly to VCC, power them from a digital output pin. Pull the pin HIGH to power the sensor, take the reading, then pull it LOW to cut power during sleep. Each GPIO pin can source/sink up to 40 mA on AVR boards — enough for most low-power sensors.
Real-world Current Measurements
Here are measured current figures for a typical weather station sketch: wake up every 5 minutes, read a DHT20 sensor, transmit via SoftwareSerial to an NRF24L01 module, sleep again.
| Phase | Current | Duration | Charge Used |
|---|---|---|---|
| Wake, read sensor | 4.5 mA | 500 ms | 0.625 µAh |
| NRF24 transmit | 12 mA | 50 ms | 0.167 µAh |
| Power-down sleep | 0.4 µA | 299.45 s | 0.033 µAh |
| Total per cycle | — | 300 s | ~0.83 µAh |
At 0.83 µAh per 5-minute cycle = 9.96 µAh per hour. With 2× AA batteries (NiMH, 2000 mAh): over 20 years theoretical runtime — far exceeding battery shelf life. In practice, accounting for battery self-discharge (~3% per month for NiMH), you get a realistic 3–5 years. This is the power of sleep modes done right.
Frequently Asked Questions
Does sleep mode work on Arduino Mega and Nano 33 IoT too?
Yes, but the details differ. The Mega uses ATmega2560 which has the same 6 sleep modes as ATmega328P. The Nano 33 IoT uses a SAMD21 (ARM Cortex-M0+) with different sleep modes managed via the ArduinoLowPower library (from Arduino). The Nano RP2040 Connect supports dormant mode via the RP2040’s built-in sleep hardware. Each platform has its own library — the concepts are identical, the API differs.
Can I use millis() timing after waking from sleep?
Timer 0 (which drives millis()) is frozen during power-down sleep. When the MCU wakes, millis() resumes from where it left off but does not account for the sleep duration. For accurate elapsed time tracking across sleep periods, use the watchdog timer’s wake count as a clock, or add an external RTC module (DS3231) that keeps running during sleep.
My sensor wakes up but reads garbage after sleep — why?
Most sensors need a warm-up or stabilization period after power is restored. If you cut sensor power via a GPIO pin during sleep, allow 100–500 ms after re-powering before taking a reading. Also check that I2C (Wire) or SPI peripherals are properly re-initialized after waking — some require calling begin() again if their clocks were disabled during sleep.
Is it safe to disable the Brown-Out Detector?
BOD protects the MCU from writing corrupted data to flash or EEPROM when the supply voltage drops too low. During sleep (no flash writes happening), disabling BOD is safe and saves 25 µA. Re-enable it before any EEPROM write operations. The LowPower library’s BOD_OFF parameter only disables BOD during the sleep period, not permanently.
How do I debug a sleeping Arduino without disturbing the sleep cycle?
Use a current-measuring multimeter or a Nordic PPK2 power profiler to observe current waveforms. Avoid inserting Serial debug prints in the sleep-critical path (UART transmission forces the MCU to stay awake). Instead, blink an LED briefly at wake-up as a heartbeat indicator, or log data to EEPROM for retrieval later.
Battery-powered Arduino projects open up an entire world of wireless sensors, remote monitoring, and always-on IoT devices. Find the right board for your low-power build at zbotic.in Arduino & Microcontrollers — from the ultra-lean Pro Mini to the Wi-Fi-capable Nano 33 IoT.
Add comment