Build a power-efficient system using the microcontroller with the following functionality:
Sleep mode in a microcontroller is a power-saving state where the CPU stops, but selected peripherals can keep running.
They reduce power consumption while maintaining the ability to wake up from wake sources
Why We Need Sleep Mode:
Sleep mode is needed in microcontrollers to save power when the CPU is idle. It extends battery life.
ATmega328P supports six sleep modes:
In AVR microcontrollers (like ATmega328P), sleep modes are controlled using the SMCR (Sleep Mode Control Register). This 8-bit register allows you to select and enable sleep behavior.
This register is responsible for managing power modes in AVR microcontrollers.
NOTE: Similar types of registers are present in other microcontrollers for controlling the sleep modes. More advanced registers like SYST_CSR in ARM manage sleep and system tick behaviour, offering finer control.
To set up sleep modes in AVR microcontrollers like the ATmega328P, follow these steps:
The microcontroller remains in sleep until a valid interrupt or event triggers a wake-up.
| Type | Name | Description |
|---|---|---|
Include Headers
| <avr/sleep.h> | Sleep mode control functions. |
<avr/power.h> | Power reduction functions for peripherals. | |
Functions
| set_sleep_mode(mode) | Sets the desired sleep mode (e.g., SLEEP_MODE_PWR_DOWN). |
sleep_enable() | Enables sleep mode. | |
sleep_mode() | Puts MCU to sleep. | |
sleep_disable() | (Optional) Disables sleep after waking. |
Library: #include <avr/power.h>
| Function | Description |
|---|---|
power_adc_disable() / power_adc_enable() | Disable/enable ADC. |
power_timer0_disable() / power_timer0_enable() | Disable/enable Timer0. |
power_timer1_disable() / power_timer1_enable() | Disable/enable Timer1. |
power_timer2_disable() / power_timer2_enable() | Disable/enable Timer2. |
power_twi_disable() / power_twi_enable() | Disable/enable I2C (TWI). |
power_spi_disable() / power_spi_enable() | Disable/enable SPI. |
power_usart0_disable() / power_usart0_enable() | Disable/enable USART. |
sleep_bod_disable() | Disables BOD before sleep |
1. Example of using Power-down sleep mode with external interrupt wake-up to toggle an LED on Arduino UNO.
Code
#include <avr/sleep.h>
#include <avr/interrupt.h>
#define LED 12
volatile bool wakeFlag = false;
void setup() {
pinMode(2, INPUT_PULLUP); // INT0
pinMode(LED, OUTPUT); // LED pin
attachInterrupt(digitalPinToInterrupt(2), wakeISR, LOW);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sei();
}
void loop() {
sleep_mode(); // MCU sleeps here
// After waking up
if (wakeFlag) {
wakeFlag = false;
digitalWrite(LED, !digitalRead(LED)); // Toggle LED
}
// Optional delay to avoid bouncing issues
delay(50);
}
void wakeISR() {
wakeFlag = true; // Set flag to handle logic after wake
}
2. Code to blink the LED three times when the Arduino wakes up. The Arduino goes to sleep and wakes up every 8 seconds using the Watchdog Timer (WDT) as the interrupt-based wake-up source.
Code
#include <avr/sleep.h>
#include <avr/wdt.h>
const int ledPin = 13;
void setup() {
pinMode(ledPin, OUTPUT);
// Disable ADC to save power
ADCSRA &= ~(1 << ADEN);
// Setup Watchdog Timer
setupWatchdogTimer();
// Enable sleep mode
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
// Ensure interrupts are globally enabled
sei();
}
void loop() {
// Blink the LED three times on wakeup
for (int i = 0; i < 3; i++) {
digitalWrite(ledPin, HIGH);
delay(200);
digitalWrite(ledPin, LOW);
delay(200);
}
// Go to sleep again
sleep_mode();
}
// WDT interrupt service routine
ISR(WDT_vect) {
// This interrupt wakes the MCU from sleep
}
void setupWatchdogTimer() {
// Clear WDRF in MCUSR
MCUSR &= ~(1 << WDRF);
// Set up WDT for interrupt mode only, every 8 seconds
// Step 1: Enable configuration change
WDTCSR |= (1 << WDCE) | (1 << WDE);
// Step 2: Set for interrupt mode, 8s timeout
WDTCSR = (1 << WDIE) | (1 << WDP3) | (1 << WDP0); // 8s
}To reduce power consumption in microcontrollers like the ATmega328P, several effective techniques can be used:
In ATmega328P, the Power Reduction Register (PRR) allows selective disabling of clock signals to specific peripherals. Turning off modules like ADC, USART, or Timers through PRR is especially useful in sleep modes, where it can significantly extend battery life.


where:
Here’s an example of estimating battery life based on given conditions:
First, calculate the average current:
Average Current = (20 * 5 / 60) + (1 * 55 / 60) = 2.58 mA
Then, estimate the battery life:
Battery Life = 2000 mAh / 2.58 mA ≈ 775.1 hours ≈ 32.29 days
This means the battery will last approximately 32.29 days with the given usage pattern.