A standard Arduino Uno running at full speed draws roughly 45–50 mA from the USB or power jack. At that rate, a common 2,000 mAh lithium battery lasts only about 40 hours — less than two days of continuous operation. For most battery-powered projects — environmental sensors, wildlife trackers, remote data loggers, and IoT nodes — that simply is not acceptable. You need your device to run for weeks or months without a battery change.
The answer is Arduino sleep mode. By putting the microcontroller into one of its deep sleep states, you can cut current consumption to as low as 0.75 µA — a 60,000× reduction. Combined with smart wake-up strategies, a sensor node can take readings every 8 seconds, transmit data, and go back to sleep, extending battery life from days to months or even years.
This guide covers every sleep mode available on the ATmega328P (Arduino Uno, Nano, Pro Mini), the popular LowPower library, wake-up methods, and practical techniques that make the difference between a device that lasts a week and one that lasts a year.
Why Sleep Mode Is Essential for Battery Projects
Before looking at code, it is worth understanding where the power goes in a typical Arduino circuit. On an Arduino Uno powered at 5V:
- ATmega328P microcontroller: ~15 mA at 16 MHz
- USB-serial chip (CH340/ATmega16U2): ~5–20 mA (even when idle!)
- Power LED: ~3 mA
- Onboard 5V regulator (from 9V input): quiescent current ~5 mA, plus heat waste
The USB chip and power LED alone consume power that dwarfs what the ATmega328P needs when sleeping. For serious battery projects, the Arduino Pro Mini 3.3V/8MHz is the preferred platform. It has no USB chip and no power LED, and at 3.3V/8 MHz draws only about 4.5 mA active. In power-down sleep with a 3.3V supply, it drops to approximately 0.36 µA — almost nothing.
ATmega328P Sleep Modes Explained
The ATmega328P (the chip on Arduino Uno, Nano, Pro Mini) supports five sleep modes, each trading wake-up speed and wake-up source flexibility for progressively lower power consumption:
| Sleep Mode | Current (3.3V) | Wake Sources | Use Case |
|---|---|---|---|
| Idle | ~1 mA | Any interrupt | Short pauses, timers still running |
| ADC Noise Reduction | ~0.9 mA | ADC complete, most interrupts | Precision ADC readings |
| Power-save | ~1.6 µA | External INT, TWI address match, WDT, Timer2 | Timer2 RTC wake-up |
| Standby | ~1.6 µA | External INT, WDT, crystal oscillator | Fast wake from crystal |
| Power-down | ~0.36 µA | External INT, WDT, TWI address match | Maximum battery life |
Power-down mode is the one you want for maximum battery life. It stops all clocks except the watchdog timer oscillator, halts the CPU, and disables all peripherals. The chip is essentially hibernating. Only an external interrupt on INT0/INT1, a level change on a pin (with pin-change interrupts), or the watchdog timer can wake it up.
Using the LowPower Library
Rocketscreem’s LowPower library (available in the Arduino IDE library manager as “Low-Power”) is the simplest way to put an Arduino into sleep mode without dealing with AVR registers directly. Install it via Sketch → Include Library → Manage Libraries → search “Low-Power”.
#include "LowPower.h"
void setup() {
Serial.begin(9600);
}
void loop() {
// Do work here
Serial.println("Awake!");
Serial.flush(); // Important: wait for serial to finish
// Sleep for 8 seconds (watchdog timer period)
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
// Code resumes here after wake-up
}
The three parameters in powerDown():
- Sleep period: SLEEP_15MS, SLEEP_30MS, SLEEP_60MS, SLEEP_120MS, SLEEP_250MS, SLEEP_500MS, SLEEP_1S, SLEEP_2S, SLEEP_4S, SLEEP_8S, or SLEEP_FOREVER
- ADC: ADC_OFF (saves ~0.3 mA) or ADC_ON
- BOD: BOD_OFF (Brown-out Detection off, saves ~25 µA) or BOD_ON
Always call Serial.flush() before sleeping to ensure the Serial transmit buffer is empty. If you sleep while bytes are still being transmitted, the output will be garbled and the UART may lock up.
For longer sleep periods, chain multiple SLEEP_8S calls:
void sleepMinutes(int minutes) {
// Each call sleeps ~8 seconds
// minutes * 60 / 8 = number of 8s periods
int cycles = (minutes * 60) / 8;
for (int i = 0; i < cycles; i++) {
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
}
Watchdog Timer Wake-Up
The Watchdog Timer (WDT) is a separate oscillator that continues running even in Power-down sleep mode. It generates an interrupt at programmable intervals from 16 ms to 8 seconds. This is the most common wake-up mechanism for periodic-sampling sensor nodes.
For applications that need wake-up intervals longer than 8 seconds, you must use an external RTC (Real-Time Clock) module like the DS3231, which has an alarm output that can trigger an external interrupt on the Arduino.
Here is a raw register approach (without the LowPower library) that demonstrates exactly what happens at the hardware level:
#include <avr/sleep.h>
#include <avr/wdt.h>
volatile bool wdtFlag = false;
ISR(WDT_vect) {
wdtFlag = true; // set flag in ISR
}
void enableWDT(uint8_t period) {
// period: WDTO_15MS ... WDTO_8S
cli();
MCUSR &= ~(1 << WDRF); // clear WDT reset flag
WDTCSR |= (1 << WDCE) | (1 << WDE); // enable change
WDTCSR = (1 << WDIE) | period; // interrupt mode + period
sei();
}
void goToSleep() {
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_cpu();
sleep_disable();
}
void setup() {
Serial.begin(9600);
enableWDT(WDTO_8S);
}
void loop() {
if (wdtFlag) {
wdtFlag = false;
Serial.println("Woke from WDT");
Serial.flush();
// Take sensor reading here
}
goToSleep();
}
This approach gives you precise control over the sleep mechanism. Note that the WDT oscillator is not perfectly accurate — it drifts with temperature and voltage. For applications requiring precise timing (e.g., reading every exactly 5 minutes), use an external RTC with a 32.768 kHz crystal instead.
External Interrupt Wake-Up
For event-driven applications — a PIR motion sensor, a door reed switch, a button press — you want the Arduino to wake up on an external signal rather than on a timer. External interrupts on pins D2 (INT0) and D3 (INT1) can wake the Arduino from Power-down sleep.
#include "LowPower.h"
const int wakePin = 2; // INT0 on D2
volatile bool motionDetected = false;
void wakeISR() {
motionDetected = true;
}
void setup() {
Serial.begin(9600);
pinMode(wakePin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(wakePin), wakeISR, LOW);
}
void loop() {
Serial.println("Going to sleep...");
Serial.flush();
// Sleep until pin D2 goes LOW
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
// Wake-up happened
if (motionDetected) {
motionDetected = false;
Serial.println("Motion detected!");
Serial.flush();
// Process event, take photo, send alert, etc.
delay(5000); // Debounce / processing time
}
}
Use SLEEP_FOREVER when you want the Arduino to sleep indefinitely until an external event occurs. The ISR is minimal — just set a flag. Do all real work in loop() after the wake-up.
Pin-change interrupts (PCINT) can wake from Power-down sleep on any digital pin, not just D2/D3. This is useful when you need more than 2 external wake-up sources. The EnableInterrupt library abstracts PCINT setup for all Arduino boards.
Hardware Optimizations
Sleep mode reduces the microcontroller’s consumption to near zero, but other components on your circuit still draw power. Here are the hardware changes that make the biggest difference:
Remove or Bypass the Onboard Regulator
The Arduino Pro Mini’s onboard LDO regulator has a quiescent current of ~35 µA (Torex XC6206 or similar). For absolute minimum power consumption, bypass it and supply 3.3V directly to the VCC pin. A lithium coin cell (CR2032) with a low-dropout regulator like the MCP1700-3302E (1.6 µA quiescent) is the optimal combination.
Disable Peripheral ICs
Sensors connected to the Arduino’s power rails draw power even when the Arduino is sleeping. Add a MOSFET switch (P-channel for high-side switching) or use the Arduino’s digital pin to control a transistor that powers down sensors during sleep. Pull the sensor power LOW before sleeping and HIGH after waking.
Disable the Arduino’s Unused Peripherals
Before entering sleep, disable the ADC, SPI, I2C, USART, and Timer modules you are not using. The LowPower library does this automatically when you use ADC_OFF. For manual control:
// Disable ADC
ADCSRA &= ~(1 << ADEN);
// Disable internal analog comparator
ACSR |= (1 << ACD);
// Disable all peripherals via PRR
PRR = 0xFF;
Real-World Example: Low-Power Temperature Logger
Here is a complete, production-ready low-power sketch for a temperature logger using a DS18B20 sensor. It wakes every 8 seconds, reads temperature, and goes back to sleep:
#include "LowPower.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 4
#define SENSOR_POWER 5 // transistor base: controls sensor VCC
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup() {
Serial.begin(9600);
pinMode(SENSOR_POWER, OUTPUT);
digitalWrite(SENSOR_POWER, LOW); // sensors off initially
}
float readTemperature() {
digitalWrite(SENSOR_POWER, HIGH); // power on sensor
delay(50); // stabilisation time
sensors.begin();
sensors.requestTemperatures();
float temp = sensors.getTempCByIndex(0);
digitalWrite(SENSOR_POWER, LOW); // power off sensor
return temp;
}
void loop() {
float temp = readTemperature();
Serial.print("Temp: ");
Serial.print(temp);
Serial.println(" C");
Serial.flush();
// Store to EEPROM, SD card, or transmit here
// Sleep 8 seconds
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
With this setup on an Arduino Pro Mini 3.3V, average current consumption is approximately:
- Active (8 seconds loop includes ~200ms awake): 4.5 mA × 0.2s = 0.9 mAs
- Sleep (7.8 seconds): 0.5 µA × 7.8s = 0.0039 mAs
- Average: roughly 0.112 mA
- On a 1000 mAh LiPo: ~370 days continuous operation
Frequently Asked Questions
Does sleep mode work on all Arduino boards?
Sleep modes are microcontroller-specific. The ATmega328P (Uno, Nano, Pro Mini) supports the five modes covered in this guide. The ATmega2560 (Mega) has similar modes. ARM-based boards (Due, Zero, Nano 33 IoT, RP2040) have different sleep architectures and require board-specific libraries or CMSIS calls. The LowPower library supports several common Arduino boards beyond the ATmega328P.
Can I sleep for more than 8 seconds at a time?
The watchdog timer maximum period is 8 seconds. For longer sleep, either chain multiple SLEEP_8S calls (losing some accuracy due to WDT oscillator drift) or use an external RTC module like the DS3231 with its alarm output connected to INT0/INT1. The DS3231 can wake the Arduino after any duration from 1 second to 24 hours.
Why does my Serial output become garbled after waking from sleep?
Always call Serial.flush() before entering sleep. This blocks until the UART transmit buffer is empty. Without it, the sleep disables the clock mid-transmission, corrupting the output. After wake-up, there is a brief start-up period (a few milliseconds for the oscillator to stabilise) before Serial works reliably. If needed, add a short delay after wake-up before the first Serial print.
Can I use I2C or SPI sensors with sleep mode?
Yes, but sensors must be powered down or placed in their own low-power mode before the Arduino sleeps. Most I2C and SPI sensors have a shutdown/sleep command. Send the command, then put the Arduino to sleep. On wake-up, re-initialise the sensor. If the sensor does not have a sleep mode, use a MOSFET to cut its power supply during Arduino sleep.
What is BOD and should I always disable it?
Brown-Out Detection (BOD) monitors the supply voltage and resets the chip if it drops below a threshold (typically 1.8V or 2.7V). Disabling BOD saves ~25 µA in sleep. For most battery projects with a stable supply, BOD can be safely disabled (BOD_OFF in the LowPower library). If your power supply is noisy or you are using a deeply discharged battery, keep BOD enabled to prevent data corruption during undervoltage conditions.
Conclusion
Arduino sleep modes transform battery-hungry projects into year-long deployment systems. The key steps are: choose the right board (Pro Mini 3.3V for maximum savings), use Power-down mode for the lowest current, turn off peripherals including ADC and BOD, power down external sensors, and wake via watchdog timer or external interrupt. With these techniques, a small LiPo cell can power a sensor node for a year or more.
Find all the Arduino boards and sensors you need for your low-power build at Zbotic’s Arduino collection — India’s trusted source for quality electronics components delivered to your door.
Add comment