How it works
Battery runtime is determined by one number: average current draw. For a device with discrete power states, this is:
I_avg = I_sleep × D_sleep + I_active × D_active + I_tx × D_tx
Where D is the duty cycle fraction for each state (must sum to 1). Runtime is then:
Runtime (hours) = C_eff / I_avg
C_eff is effective capacity — the nameplate mAh derated by regulator efficiency and temperature effects. A typical LDO at 80% efficiency means 500 mAh becomes 400 mAh effective.
The dominant state
On a BLE beacon transmitting every second, the TX event might last 3 ms at 7 mA:
D_tx = 3ms / 1000ms = 0.003 (0.3%)
I_tx contribution = 7mA × 0.003 = 21 µA
Sleep at 3 µA for the remaining 99.7%:
I_sleep contribution = 3µA × 0.997 = 3 µA
I_avg ≈ 24 µA
A CR2032 (225 mAh) lasts 225,000 µAh / 24 µA ≈ 9,375 hours ≈ 13 months. Cut sleep current in half and you get 18+ months. That’s why sleep current dominates — the math punishes any waste there ruthlessly.
CR2032 limitations
The CR2032 has an internal resistance of 15–25 Ω. At 1 mA average this is fine. At 5 mA peak TX current (e.g., nRF52 at +4 dBm), the voltage sag is 5 mA × 20 Ω = 100 mV — tolerable. At 40 mA (SX1276 LoRa TX at +14 dBm), the sag is 40 mA × 20 Ω = 800 mV, which can cause brownouts.
The fix: add a 10–100 µF electrolytic or tantalum bulk capacitor on the supply rail near the radio. The cap supplies peak current, the coin cell slowly recharges it between TX events.
Temperature derating
Alkaline and Li-MnO₂ (CR2032) capacity drops significantly below 0°C:
| Battery | −20°C capacity | +20°C capacity |
|---|---|---|
| CR2032 | ~130 mAh | 225 mAh |
| AA alkaline | ~1200 mAh | 2500 mAh |
| LiPo | ~80% | 100% |
For outdoor deployments, derate by 30–50% and add a brown-out reset to recover gracefully from supply dips.
MCU sleep modes
The “sleep current” field is the total system draw in lowest-power state — not just the MCU. Everything on the board leaks:
- Voltage supervisor with open-drain output: 1–5 µA
- Unpowered GPIO with internal pull-up: ~50 µA (if floating input is toggling)
- Unpowered sensor with I2C address resistors: 1–10 µA per resistor to logic-high
- Crystal oscillator left running: 20–100 µA
Measure sleep current with a Nordic PPK2 or a µCurrent + DMM in series. Simulation is not a substitute.
Common mistakes
Using nameplate capacity without derating. A CR2032 rated 225 mAh cannot deliver 225 mAh through a 3.3V LDO at low temperature. Use 70% of nameplate for realistic field estimates.
Ignoring the quiescent current of external ICs. Every IC on the board that isn’t power-gated draws current. A BME280 environmental sensor consumes 0.1 µA in sleep — negligible. A µSD card left powered draws 200 µA in idle — project-killing.
Miscounting duty cycles. If the device wakes every 5 seconds and spends 100 ms active, active duty = 100/5000 = 2%. If you enter 2% active and 2% TX and 96% sleep but TX only happens 10% of active time, the TX duty should be 0.2%, not 2%.
Not accounting for self-discharge. LiPo cells lose ~2–5% capacity per month at room temperature. A 12-month project on a 500 mAh LiPo loses 60–150 mAh before the device even uses it. Size the battery for self-discharge too.