H2OhNo!
This Tutorial is Retired!
This tutorial covers concepts or technologies that are no longer current. It's still here for you to read and enjoy, but may not be as useful as our newest tutorials.
Low-Power ATtiny
The firmware behind H2OhNo! is simple in theory and long in practice. We need to establish that when water is present then sound the alarm. But what do we do for the weeks and months when there is no water detected? Let's go to sleep and save power!
We've written some lengthier tutorials on getting the ATmega328 into very low power sleep. In this tutorial we will show you how to get the ATtiny into sleep mode as well.
Under normal conditions the ATtiny will consume 10-12mA running at 8MHz. Assuming the CR2032 battery contains 200mAh, that gives us (200mAh / 20mA) 10 hours of run time. Pretty good. But what if I told you I could get you 4,000 hours?
Watchdog Sleepy Time
The ATtiny can reach about 1uA in low-power sleep. Because we only need to periodically check for water let's put the ATtiny into sleep and wake it up every once and awhile.
A watchdog timer is good for two things:
- A watchdog can reset the processor when it gets locked into an endless loop - also known as going off into the weeds. This is a good way to protect a project needs to run all the time without user intervention. If the device ever gets locked up, the watchdog can cause the system to reset and (hopefully) return to regular operation.
- A watchdog can wake the processor from deep sleep. When we put a microcontroller into deep sleep, we can use the watchdog timer as an interrupt, causing the processor to return to normal 8MHz (without a full reset).
The watchdog is just a counter. When that counter gets to the size the user specifies, the processor will either reset or an interrupt will fire. Reset can be useful (as explained above), but an interrupt is what we need.
This table is key to the whole operation. If the watchdog is enabled (WDE) and the watchdog interrupt enable (WDIE) is not set, then the processor will reset. However, if the interrupt enable is set (WDIE = 1), then an interrupt occurs. As long as we set WDIE before we go to sleep, we'll wake up from an interrupt, and the program will continue from the point in the code where the sleep command was issued.
Here's the program operation we're aiming for:
- Go to sleep for a few seconds
- When the watchdog counter overflows use the interrupt to wake us up (not reset)
- Once awake, take a analog reading to check for water
- If there's no water, go back to sleep until the watchdog wakes us up again
Additional information about how to configure the watchdog timer can be found on the AVR Libc page on sleep.h. While sleep.h is good for getting us to sleep, it was Lab III's tutorial that provided the code that allows us to use the watchdog without resetting.
Here's the basic code that puts the ATtiny to sleep in the main loop():
language:c
setup_watchdog(6); //Setup watchdog to go off after 1sec
sleep_mode(); //Go to sleep! Wake up 1sec later and check water
Putting the ATtiny to sleep for a second then waking up and doing something means it will be at 0.250mA for 1sec and 10mA for 0.0001 second. Overall, this is much lower power than the original 10mA.
But we can go even lower! There are a few peripherals that also use power, namely the analog to digital converter. Because we will not be doing any ADC while sleeping, we can shut it down as well:
language:c
void loop()
{
ADCSRA &= ~(1<<ADEN); //Disable ADC, saves ~230uA
setup_watchdog(6); //Setup watchdog to go off after 1sec
sleep_mode(); //Go to sleep! Wake up 1sec later and check water
ADCSRA |= (1<<ADEN); //Enable ADC
//Now check for water!
checkForWater();
}
This is basically how H2OhNo! works. Power everything off, go to sleep, wakeup, do something useful (check for water), go back to sleep. By disabling the ADC during sleep, we can get the sleep current consumption down to 5uA! That's 0.005mA, or 2000 times lower than our original rate.
Remember that while the ATtiny is doing work (checking for water or making noise or blinking an LED) it will use the normal 10mA while it's awake. So between sleeping at 0.005mA and doing work every second at 10mA, on average we found the H2OhNo! uses about 50uA. That means on a 200mAh coin cell we should expect the board to run for (200mAh / 0.050mA = ) 4,000 hours or about 167 days.
The H2OhNo! will wake up every second and check for water. This is probably far more often than a real-world application needs. The longest period the watchdog can be configured to fire is 8 seconds. To sleep for longer periods of time and squeeze even longer battery life from your board, try using a counter within the watchdog interrupt:
language:c
//This runs each time the watch dog wakes us up from sleep
ISR(WDT_vect) {
watchdog_counter++;
}
void loop()
{
sleep_mode(); //Go to sleep!
if(watchdog_counter > 30)
{
watchdog_counter = 0;
alarmSound(); //Make noise!!
digitalWrite(buzzer1, LOW);
digitalWrite(buzzer2, LOW);
}
}
This will wake the board up every second but immediately go back to sleep until 30 seconds have gone by.