Home  /  Programming
Programming

ATtiny85 Sleep Modes: Make a Coin Cell Last for Years

Power-down mode, the watchdog timer, and the tricks that take your ATtiny85 from milliamps to microamps.

Last week we got an LED blinking on the ATtiny85. Fun, but here is the problem nobody mentions in the blink tutorial: that sketch draws around 5 milliamps, all day, every day. Put it on a CR2032 coin cell and the battery is dead in under two days. The chip never rests. It just sits there, burning power, waiting for the next delay() to finish.

This week we fix that. The ATtiny85 has sleep modes that drop its appetite from milliamps to microamps, literally thousands of times less. Done right, the same coin cell that died in two days can run your project for a year. This is the ATtiny85’s real superpower, and it is the reason this chip ends up inside so many battery-powered gadgets.

The three sleep modes (only one matters most)

The ATtiny85 offers three flavors of sleep:

  • Idle: the CPU naps but timers and the ADC keep running. Saves some power, not much. Rarely what you want.
  • ADC Noise Reduction: a specialty mode for taking cleaner analog readings. Niche.
  • Power-down: nearly everything stops. Only the watchdog timer and pin-change interrupts stay alive to wake the chip back up. This is the one. Current drops to around 5 microamps with the watchdog running, or about 0.1 microamps without it.

Power-down mode is the whole game. Your project sleeps, something wakes it (a timer, a button press, a sensor), it does its job in a fraction of a second, and it goes back to sleep. Most real ATtiny85 projects spend 99.9% of their lives asleep.

Before you sleep: kill the power hogs

Sleep mode stops the CPU, but a few peripherals keep sipping power unless you shut them off explicitly. Three culprits:

  1. The ADC. The analog-to-digital converter draws a few hundred microamps just sitting there. If your project does not read analog sensors, turn it off: ADCSRA &= ~(1 << ADEN);
  2. The brown-out detector (BOD). This safety circuit watches the supply voltage and draws around 20 microamps in sleep. You can disable it in software right before sleeping, or permanently via the BODLEVEL fuses (in ATtinyCore, set Tools > BOD to “Disabled” and Burn Bootloader).
  3. Floating pins. Unused pins left as floating inputs can draw parasitic current as they hover between high and low. Set every unused pin to INPUT_PULLUP.

Your first power nap: the watchdog wake-up

The watchdog timer is a separate little clock that keeps ticking in power-down mode. We configure it to fire an interrupt every 8 seconds, which yanks the chip awake. Here is the minimal skeleton. Read it slowly, because every line earns its place:

#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>

// This runs every time the watchdog fires. We don't need to
// do anything here -- waking up IS the job.
ISR(WDT_vect) {
}

void setup_watchdog() {
  wdt_reset();
  // Timed sequence: allow changes to the watchdog config
  WDTCR |= (1 << WDCE) | (1 << WDE);
  // 8-second timeout, interrupt mode (not reset mode)
  WDTCR = (1 << WDIE) | (1 << WDP3) | (1 << WDP0);
}

void go_to_sleep() {
  // Shut down the ADC
  ADCSRA &= ~(1 << ADEN);
  // Park unused pins so they don't float
  for (byte i = 0; i <= 4; i++) {
    pinMode(i, INPUT_PULLUP);
  }
  // Deepest sleep available
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sei();          // make sure interrupts are on, or we'll never wake
  sleep_cpu();    // goodnight -- execution stops here
  sleep_disable(); // ...and resumes here 8 seconds later
}

void setup() {
  setup_watchdog();
}

void loop() {
  go_to_sleep();
  // Woke up! Do your work here, then loop back to sleep.
}

A few things worth noticing. WDIE (not WDE) puts the watchdog in interrupt mode: it wakes the chip instead of resetting it, which is the classic beginner trap. The WDCE dance is a safety interlock from the datasheet; skip it and your prescaler settings silently do nothing. And sei() before sleep_cpu() is non-negotiable: if interrupts are off, the watchdog fires into the void and your chip sleeps forever.

Tip: before you touch a breadboard, lay the circuit out in your browser with cirkitry.app – it is a free visual circuit designer with breadboard, schematic, and PCB views. Sketch it there first, then build it for real.

Put it to work: the 8-second beacon

Theory is nice, but let us build the thing this is all for: a beacon that blinks an LED once every 8 seconds and sips power the rest of the time. Wire the LED exactly like last week’s blink project (PB0 through a 220 ohm resistor to GND), then upload this with Upload Using Programmer:

#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>

#define LED 0  // PB0, physical pin 5

ISR(WDT_vect) {
}

void setup() {
  pinMode(LED, OUTPUT);
  // Watchdog: 8-second interrupt
  wdt_reset();
  WDTCR |= (1 << WDCE) | (1 << WDE);
  WDTCR = (1 << WDIE) | (1 << WDP3) | (1 << WDP0);
  // Kill the ADC, park unused pins
  ADCSRA &= ~(1 << ADEN);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
}

void loop() {
  // Blink: the only work we do
  digitalWrite(LED, HIGH);
  delay(50);
  digitalWrite(LED, LOW);

  // Back to sleep for 8 seconds
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sei();
  sleep_cpu();
  sleep_disable();
}

The LED flashes for 50 milliseconds, then the chip vanishes into power-down for 8 seconds. Rinse and repeat, potentially for months.

Prove it: measure the current

Trust, but verify. Put your multimeter in current mode and wire it in series between your power supply and the chip’s VCC pin. You should see two distinct states:

  • Awake (blinking): a few milliamps, jumping briefly as the LED fires.
  • Asleep: roughly 5 microamps. If your meter reads higher, the usual suspects are the ADC left on, the brown-out detector, or a floating pin.

Seeing that meter drop from milliamps to single-digit microamps the moment the chip sleeps is one of the great little thrills of this hobby. Do it once and you will never write a battery-powered sketch without sleep again.

The battery math

Let us run the numbers for the beacon on a CR2032 (about 220mAh):

  • Awake: ~5mA for 50ms out of every 8 seconds = 0.6% duty cycle, averaging ~30uA
  • Asleep: ~5uA for the other 99.4%
  • Total average: roughly 35 microamps
  • 220mAh / 0.035mA = ~6,200 hours, or about 8 months

From under two days to the better part of a year, on the same battery, with the same LED. That is what sleep mode buys you. And if your project wakes on a button press instead of a timer, you can drop the watchdog too and push toward 0.1uA, where the battery’s own shelf life becomes the limit, not the chip.

Gotchas worth knowing

  • Watchdog interrupt vs. reset: WDE resets the chip, WDIE wakes it. Set WDE by accident and your project reboots every 8 seconds instead of sleeping. Ask me how I know.
  • delay() still works when awake, but obviously there is no delaying while asleep. Structure your code as wake, work, sleep.
  • The 8-second maximum is per watchdog cycle. Need longer? Count wake-ups and go back to sleep: wake 7 times, then do your hourly task.
  • Brown-out fuses: if your meter still shows ~20uA in sleep after killing the ADC, the BOD is your leftover. Disable it in the ATtinyCore Tools menu and Burn Bootloader.

Where this goes

With sleep in your toolbox, a whole category of projects opens up: door sensors that run for years on a coin cell, soil moisture monitors that phone home once a day, wildlife cameras, mail slot notifiers. The pattern is always the same: sleep hard, wake briefly, do one job well.

Next up: reading the real world with the ADC, the right way. See you Saturday.

S
Shane

Want the next build in your inbox?

One email a week: a tested project, one programming trick, the parts worth buying. Free forever.

Subscribe free