Here is code I've used on ATtiny45s and 85s. Some notes:
This code assumes a momentary contact switch from PB2/INT0 to ground, this is used to wake the MCU.
Before calling goToSleep(), to minimize current consumption, I ensure that (a) output pins are set high or low as needed so that their loads do not draw current, and (b) all other pins are set as inputs with the pullup resistor enabled.
The 5V regulator will continue to draw quiescent current even if the AVR is in power-down mode, which defeats the whole purpose. A 7805 will typically draw 6mA even if it's not powering a load. LDO types can do quite a bit better, but I'd prefer just to run on two or three AA cells, which will last a lot longer than a 9V anyway.
#include <avr/sleep.h>
#include <avr/interrupt.h>
#define BODS 7 //BOD Sleep bit in MCUCR
#define BODSE 2 //BOD Sleep enable bit in MCUCR
uint8_t mcucr1, mcucr2;
...
void goToSleep(void)
{
GIMSK |= _BV(INT0); //enable INT0
MCUCR &= ~(_BV(ISC01) | _BV(ISC00)); //INT0 on low level
ACSR |= _BV(ACD); //disable the analog comparator
ADCSRA &= ~_BV(ADEN); //disable ADC
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
//turn off the brown-out detector.
//must have an ATtiny45 or ATtiny85 rev C or later for software to be able to disable the BOD.
//current while sleeping will be <0.5uA if BOD is disabled, <25uA if not.
cli();
mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE); //turn off the brown-out detector
mcucr2 = mcucr1 & ~_BV(BODSE);
MCUCR = mcucr1;
MCUCR = mcucr2;
sei(); //ensure interrupts enabled so we can wake up again
sleep_cpu(); //go to sleep
cli(); //wake up here, disable interrupts
GIMSK = 0x00; //disable INT0
sleep_disable();
sei(); //enable interrupts again (but INT0 is disabled from above)
}
ISR(INT0_vect) {} //nothing to actually do here, the interrupt just wakes us up!
Edit 22Feb2012: Added defines and declarations for mcucr1, mcucr2 at top of sample code.
[quote author=Jack Christensen link=topic=83826.msg628604#msg628604 date=1324300546]
//must have an ATtiny45 or ATtiny85 rev C or later for software to be able to disable the BOD.[/quote]
How do you tell which revision you have? The data sheet says that the revision numbers can be found on the back of the 8P3 (DIP) package, but all I see on the back are codes:
OF4 419
G5 1P
1025 e3
The reason I ask is because I tried testing this code using Arduino 0022 inside a minimal sketch (setup and loop empty), and it would not compile. The errors were:
sketch_feb22a.cpp: In function 'void goToSleep()':
sketch_feb22a.cpp: error: 'mcucrl' was not declared in this scope
sketch_feb22a.cpp: error: 'BODS' was not declared in this scope
sketch_feb22a.cpp: error: 'BODSE' was not declared in this scope
sketch_feb22a.cpp: error: 'mcucr2' was not declared in this scope
I could never make heads or tails out of the markings on the back of the package, either. I concluded that the ATtiny85s that I had were not revision C, since the current in power down mode only dropped to 20µA or so, whereas an ATtiny45 running the same code dropped to under 0.5µA.
Adding the following at the top of the sketch should address the compile errors. Not sure why the BODS and BODSE bits aren't already defined, I didn't look into it, just defined 'em myself.
#define BODS 7 //BOD Sleep bit in MCUCR
#define BODSE 2 //BOD Sleep enable bit in MCUCR
uint8_t mcucr1, mcucr2;