From the task, we understand that the system needs to stay in a low-power state and perform the following tasks:
To achieve power efficiency and time accuracy, we will use Timer1, which is both power-efficient and provides accurate timing for periodic wake-ups.
The Arduino UNO (ATmega328P) supports six sleep modes, each offering different power-saving levels:
Given the need for periodic wake-ups with precise timing, we will use IDLE Mode, which allows Timer1 to trigger interrupts for periodic wake-ups while keeping the system in a low-power state. This balances power efficiency with accurate timing for the task.
Here is a comparison of all sleep modes available in the Arduino UNO (ATmega328P):
The system is implemented using sleep modes and timer interrupts to ensure efficient power management.
To achieve a 1-minute time-based event, a watchdog timer can be used. However, it has an accuracy of 10%. It will be very inaccurate.
Thus, we will utilize Timer1, which has a duration limit of approximately 4 seconds per cycle. Therefore, the system performs 15 wake-up cycles (15 × 4s = 60s) before executing the main task.
🔹 Timer1 Configuration (CTC Mode)
🔹 Sleep Mode (Idle Mode)
🔹 Wake-Up and ADC Measurement
This approach ensures accurate timing while optimizing power consumption.
#include <avr/sleep.h> // Library for sleep modes
#include <avr/interrupt.h> // Library for interrupts
#include <avr/power.h> // Library for power management
volatile uint8_t sleepCounter = 0; // Counts 4-second intervals for a total of 60 seconds
// Function to configure Timer1 in CTC mode to wake up the CPU every 4 seconds
void setupTimer1() {
cli(); // Disable global interrupts while configuring
TCCR1A = 0; // Set Timer1 to Normal mode
TCCR1B = (1 << WGM12) | (1 << CS12) | (1 << CS10); // CTC Mode, Prescaler = 1024
OCR1A = 62500; // Compare Match A value for 4-second interval (16MHz clock)
TIMSK1 = (1 << OCIE1A); // Enable Timer1 Compare Match A interrupt
sei(); // Enable global interrupts
}
// Function to disable all unnecessary peripherals to save power
void disableUnusedPeripherals() {
power_adc_disable(); // Disable ADC (Analog to Digital Converter)
power_spi_disable(); // Disable SPI (Serial Peripheral Interface)
power_twi_disable(); // Disable TWI (I2C)
power_timer0_disable(); // Disable Timer0 (Used for delay and millis functions)
power_timer2_disable(); // Disable Timer2 (Used for PWM on pins 3 and 11)
// Note: Timer1 remains enabled as it's used for wake-up
}
// Function to put the MCU into sleep mode (Idle mode)
void enterIdleMode() {
delay(10); // Short delay before entering sleep mode
disableUnusedPeripherals(); // Disable unused peripherals to save power
noInterrupts(); // Disable interrupts while configuring sleep
set_sleep_mode(SLEEP_MODE_IDLE); // Set CPU to Idle mode (Timer1 remains active)
sleep_enable(); // Enable sleep mode
interrupts(); // Re-enable interrupts
sleep_mode(); // Put CPU to sleep (execution pauses here)
// Execution resumes here after wake-up
sleep_disable(); // Disable sleep mode after waking up
power_all_enable(); // Re-enable all peripherals
}
void setup() {
Serial.begin(115200);
pinMode(13, OUTPUT);
digitalWrite(13, LOW); //Turning off the on board LED for power saving
Serial.println("System Initialized.");
setupTimer1(); // Initialize Timer1 for periodic wake-ups
}
void loop() {
enterIdleMode(); // Enter Idle Mode (CPU sleeps, wakes up every 4 seconds)
// Every 15 wake-up cycles (~60 seconds), read ADC and print the value
if (sleepCounter == 15) {
int adcValue = analogRead(A0); // Read ADC value
Serial.print("ADC Value: ");
Serial.println(adcValue); // Print ADC value
sleepCounter = 0; // Reset counter for the next 60-second cycle
delay(10); // Short delay to stabilize
}
}
// Timer1 Compare Match Interrupt (Executes every 4 seconds, wakes CPU)
ISR(TIMER1_COMPA_vect) {
sleepCounter++; // Increment counter every 4 seconds
TCNT1 = 0; // Reset Timer1 counter
}
Setup Function (setup()
):
Serial.begin(115200)
).setupTimer1()
) for 4-second interrupts.Timer1 Configuration (setupTimer1()
):
cli()
) to prevent setup conflicts.WGM12 = 1
) for precise timing.OCR1A = 62500
for a 4-second interval.TIMSK1 |= (1 << OCIE1A)
).sei()
).Power Optimization (disableUnusedPeripherals()
):
Entering Sleep Mode (enterIdleMode()
):
sleep_mode()
to pause execution until an interrupt occurs.Main Loop (loop()
):
Timer1 Compare Match Interrupt (ISR(TIMER1_COMPA_vect)
):
Power Saving Analysis
ADC values are printing after every 1 minute