How to deep sleep ATtiny/ATmega (to run for years with batteries) but still detect a button press? Question (TL;DR): what is the optimal method to deep sleep (to run an ATtiny45 or ATmega on batteries for 1+ year) but still be able to detect a button press? Is it possible to deep sleep until a button is pressed?

I'm using a classic "debounce" method to detect a button press:

int buttonState;
int lastButtonState = LOW;
unsigned long lastDebounceTime = 0; 
unsigned long debounceDelay = 50;  

void setup() {
  pinMode(2, INPUT);
}

void loop() {
  int reading = digitalRead(2);
  if (reading != lastButtonState) { lastDebounceTime = millis(); }
  if ((millis() - lastDebounceTime) &gt; debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == HIGH) {
         // Button pressed, do something here! 
         // In my actual code, it sends a packet via RF 433 Mhz 
      }
    }
  }
  lastButtonState = reading;
  // snore(20);          // TinySnore here
}


My ATtiny45 should run during 1 year on 3 AA batteries, so I added a deep sleep using TinySnore. It works, and made the consumption go from more than 1mA to 0.2mA (@1 Mhz).

I know it's possible to go down to 5 µA if I snore(1000); but then obviously it won't be able to detect a button press.

I tried various sleep values: snore(10);, snore(20);, snore(50);, etc. but I didn't get consistent results.

Thus the question: how to deep sleep until a button is pressed?



I was thinking about using attachInterrupt() but then what kind of sleep should we use? snore()? delay()?
ATTINY's are designed to easily do this since they can wake from power down sleep mode by a pin change...

 

Basically you want to...


Connect a normally-open push button between an IO pin and ground.
Enable the pull-up on the IO.
Enable the pin change interrupt on the IO pin.
Enable interrupts.
Enter "power down" sleep mode.


When the button is pushed, it will connect the IO pin to ground, which will cause a pin change interrupt, which will wake the chip from sleep.

Note that you do not need to do anything in the pin change ISR (you can use the EMPTY_INTERRUPT compiler macro). If the ISR is empty, execution will pick up on the line after the sleep upon waking.

While in deep sleep, the chip will use an astonishingly small amount of power.  For example, an ATTINY25/45/85 running off of a 3V coin cell at room temp will use less than 0.2uA...



A typical CR2032 coin cell is rated for 235mAh to 2V, so at this rate we'd expect to be able to wait for a button press like this for 100+ years.

IRL the battery will likely self discharge and physically deteriorate long before then (rated at 1% per year), but still not too shabby.