# Low-power and Sleep Modes — Arduino & Embedded C

Source: https://www.geekswithgeeks.com/en/arduino-embedded-c/low-power

> Do work, then sleep.

## Most of the time, do nothing

Battery projects last longest when the MCU **sleeps** between short bursts of work. Sleep modes switch off parts of the chip: on the ATmega328P, **idle** stops the CPU but keeps peripherals and timers running, while **power-down** stops almost everything and wakes on an external interrupt, pin change or the watchdog timer. ESP32 boards offer light sleep and **deep sleep**, where most of the chip is off and wake-up behaves like a reset (use RTC memory or flash for state). Board-level parts also matter: a power LED, USB-serial chip or linear regulator can draw far more than the sleeping MCU, so a bare chip or a low-power board helps. Turn off unused peripherals (ADC, Wi-Fi) and measure current with a meter rather than trusting estimates. API details differ by core version; check the docs.

## Power-down until a button press (ATmega328P)

avr-libc sleep functions; wake-up via external interrupt on pin 2 (Uno R3).

```cpp
#include <avr/sleep.h>

const uint8_t WAKE_PIN = 2;

void wakeUp() { /* nothing: waking is the point */ }

void setup() {
  pinMode(WAKE_PIN, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // "work" briefly
  delay(200);
  digitalWrite(LED_BUILTIN, LOW);

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  noInterrupts();
  sleep_enable();
  attachInterrupt(digitalPinToInterrupt(WAKE_PIN), wakeUp, LOW);
  interrupts();
  sleep_cpu();                       // sleeps here until the interrupt
  sleep_disable();
  detachInterrupt(digitalPinToInterrupt(WAKE_PIN));
}
```

## ESP32 deep sleep with a timer wake-up

ESP32 Arduino core; function names from the ESP-IDF sleep API, check the docs for your core version.

```cpp
RTC_DATA_ATTR int bootCount = 0;   // survives deep sleep (RTC memory)

void setup() {
  Serial.begin(115200);
  bootCount++;
  Serial.printf("Boot number %d\n", bootCount);

  // ... take a reading, send it ...

  esp_sleep_enable_timer_wakeup(60ULL * 1000000ULL);  // 60 s in microseconds
  esp_deep_sleep_start();          // never returns; wake-up restarts setup()
}

void loop() {}
```

## In power-down, millis() stops

On the ATmega328P, Timer0 stops in power-down sleep, so millis() does not advance while sleeping. Use the watchdog or an external RTC if you need to keep track of time.

**Quiz:** What happens when an ESP32 wakes from deep sleep?

- [ ] It continues from the line after esp_deep_sleep_start()
- [x] It restarts and runs setup() again, keeping only data stored in RTC memory or flash
- [ ] All variables keep their values automatically
- [ ] It waits for a USB connection

*Answer:* It restarts and runs setup() again, keeping only data stored in RTC memory or flash. Deep-sleep wake-up behaves like a reset.
