I'm using an atmega328 on AVR. I haven't done any coding yet but I am planning. How I will do so in my head. So I want to be able to wake up the ATmega328 via a button press, and go to sleep after I've pressed the same button. How will I do that?

In my head, it is similar to this.

I will place the sleep code in the main function, and also a while loop in the ISR function. When it detects a button press, it will break out of the while loop and go back to sleep.

Will this work? How does an ATmega handle button press while it is in the interrupt service routine function? Or how does it distinguish between a button press to interrupt the sleep and a button press to go to sleep?

  • 4
    \$\begingroup\$ You shouldn't put a while loop in an ISR, that's kind of a really janky approach. An ISR is intended to be a short quick burst of code. You should just have a boolean flag in the ISR that just gets toggled on every button press. Then in the main loop, do a check on the status of the flag. If it is True, then go to Sleep. \$\endgroup\$ Commented Sep 28, 2015 at 12:39
  • 1
    \$\begingroup\$ Make sure to declare your flag as volatile (so the compiler knows it can change in the ISR and doesn't optimise it away). For example: volatile boolean flag; \$\endgroup\$ Commented Sep 28, 2015 at 13:20
  • \$\begingroup\$ @TomCarpenter this is defined as a global variable, not a local variable yes? i.e when i do the function declarations etc \$\endgroup\$ Commented Sep 28, 2015 at 14:24
  • \$\begingroup\$ Yes, global variable - so that it is in scope (visible) both in your ISR and main() function. You can either put it at the top of your .c file if everything is in one file, or declare it in a .h file. \$\endgroup\$ Commented Sep 28, 2015 at 14:28
  • \$\begingroup\$ Hey @TomCarpenter, Thanks for the advice. I've successfully implemented a program that calls the interrupt and lights the LED for 10 sec, before going back to the original code. This is using a volatile flag. Im now looking to get into sleep mode. my question is, when a microcontroller is in sleep and an interrupt changes the flag... does the microcontroller wake up? \$\endgroup\$ Commented Sep 29, 2015 at 6:34

1 Answer 1


Interrupts and button pushes don't mix AT ALL. Buttons have a phenomenon knows a bounce. Just before the contacts close they "bounce" making and breaking contact. If for example using a pin change interrupt with a button you may enter and exit sleep mode a bunch of times before the button stabilizes. Buttons need debounced, a technique that makes sure that the button state is stable before reading that button.

The best way to debounce a button is to read the state of the button in regular intervals, 1ms for example. If the state of the button stays constant for at least 50ms the button can be considered stable.

The way i normally write such a routine is check the button every 1ms. If a debounce event is not in progress and the current button state does not match the past button state, start a debounce event. Continue checking the button every 1ms but increment a counter every time a button read occurs. Normally i'll start at 50. If the button is lows i'll decrement and if the button is high i'll increment. If you get to 100 then the button is high and if you get to 0 the button is low. Reset the start variable back to 50 and set debounce event to false.

In your case i would use the pin change interrupt to wake the micro but then impose a mandatory debounce. If the debounce passes then stay awake. If the debouce fails, meaning that a button was not pushed, then fall back to sleep.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.