Attiny85, low power mode and interrupts

Hi!
I have a really simple project that I need to do and I need some help.

I switched from Arduino to ARM (using chips from STM and Nordic) years ago but I had a bunch of unused Attiny85s laying around and since the project is pretty simple I said why not.

My project is a battery powered device that has a single switch as an input. When the switch is pressed the device needs to do some stuff, then wait a specific amount of time (not always the same - but around 5 minutes max) then after that do some other stuff. Then return back to sleep. If at any time the switch is released it should just return back to sleep (without completing the final task).

My idea is to basically sleep the CPU until I get an interrupt from the switch. And also sleep the CPU when waiting for the time to pass. But I can't figure out how to do that.

I've seen quite a bit of code floating around that does either sleeping x amount of time or reading an external interrupt. But never both. Most of that code is also writing some bits in some registers directly and I have no idea what some of them do.

Any help on how to achieve this will be greatly appreciated.

I must say this though... SDKs for ARM chips from STM and Nordic make stuff like this really easy and the resulting code much more readable than this magic that people use with AVRs.

Most of that code is also writing some bits in some registers directly and I have no idea what some of them do.

The datasheet will tell you.

I've seen quite a bit of code floating around that does either sleeping x amount of time or reading an external interrupt. But never both.

Both act on an interrupt. You just have to react in th ISR to do what you need to if that interrupt source woke the processor up.

Show us what code you already have and we try to add the necessary stuff that's missing. Implement one of the two cases (sleep with no button presses or sleep while waiting), so we have to help you adding just the other one.

Sometimes I am a bit of an idiot. I've later figured out that I can just wire the power through the switch itself to achieve the same goal. So I only need the watchdog timer without external interrupts.

But for anyone interested... Here is the code for Watchdog sleep timer that wakes the CPU every second. It's a bit of a combination of various sources. Though if I remember correctly it is mostly from some Sparkfun project.

#include <avr/sleep.h>

#include <avr/interrupt.h>

volatile int desiredSleepTime = 30;
volatile int currentSleepTime = 0;

void setup() {
 //Power down various bits of hardware to lower power usage  
 set_sleep_mode(SLEEP_MODE_PWR_DOWN); //Power down everything, wake up from WDT
 sleep_enable();

}

void loop() {
 watchdogSleep1s();

// do stuff with sleepTime
}

void watchdogSleep1s() {
   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
}

//This runs each time the watch dog wakes us up from sleep
ISR(WDT_vect) {
 currentSleepTime++;
}

//Sets the watchdog timer to wake us up, but not reset
//0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms
//6=1sec, 7=2sec, 8=4sec, 9=8sec
//From: http://interface.khm.de/index.php/lab/experiments/sleep_watchdog_battery/
void setup_watchdog(int timerPrescaler) {

if (timerPrescaler > 9 ) timerPrescaler = 9; //Limit incoming amount to legal settings

byte bb = timerPrescaler & 7;
 if (timerPrescaler > 7) bb |= (1<<5); //Set the special 5th bit if necessary

//This order of commands is important and cannot be combined
 MCUSR &= ~(1<<WDRF); //Clear the watch dog reset
 WDTCR |= (1<<WDCE) | (1<<WDE); //Set WD_change enable, set WD enable
 WDTCR = bb; //Set new watchdog timeout value
 WDTCR |= _BV(WDIE); //Set the interrupt enable, this will keep unit from resetting after each int
}