Forum: µC & Digital Electronics Atmega328PU wake up with a long button press

Author: Maurice Wirth (iciwi)
Posted on:

Rate this post
0 useful
not useful
Hello there,

I'm working on a new project. One important topic is to save power in 
standalone Atmega 328PU. The microcontroller is into a deep sleep mode 
and should only wake up after the button was pressed for over 3 seconds. 
I wrote the following two codes.

#define LED_PIN 13
void setup() {
// put your setup code here, to run once:
//Save Power by writing all Digital I0 LOW 
for(int i=0; i<20; i++){
  if(i != 2)//just because the button is hooked up to digital pin 2
    pinMode(i, OUTPUT);

  attachInterrupt(0, digitalInterrupt, FALLING); //interrupt for waking up

void loop() {
  // put your main code here, to run repeatedly:
digitalWrite(LED_PIN, HIGH);
digitalWrite(LED_PIN, LOW);

ADCSRA &= ~(1<<7);
SMCR |= (1<<2); //power down mode
SMCR |= 1; //enable sleep

MCUCR |=(3 << 5); //set both BODS and BODSE at the same time
MCUCR = (MCUCR & ~(1 << 5)) | (1<< 6); //then set the BODS bit and clear the BODS bit at the same time
__asm__ __volatile__("sleep");

void digitalInterrupt(){
  //needed for the digital input interrupt

int inPin = 2;  // the pin number for input (for me a push button)
int ledPin = 13; 

int current;         // Current state of the button
                     // (LOW is pressed b/c i'm using the pullup resistors)
long millis_held;    // How long the button was held (milliseconds)
long secs_held;      // How long the button was held (seconds)
byte previous = HIGH;
unsigned long firstTime; // how long since the button was first pressed 

void setup() {
  pinMode(ledPin, OUTPUT);
  digitalWrite(inPin, HIGH);  // Turn on 20k pullup resistors to simplify switch input

void loop() {
  current = digitalRead(inPin);

  // if the button state changes to pressed, remember the start time 
  if (current == LOW && previous == HIGH) {
    firstTime = millis();

  millis_held = (millis() - firstTime);
  secs_held = millis_held / 1000;

    if (current == LOW && previous == LOW) {

      // If the button was held for more then 3 seconds blink LED 1 time
      if (secs_held >= 3) {


  previous = current;


// Just a simple helper function to blink an led in various patterns
void ledblink(int times, int lengthms, int pinnum){
  for (int x=0; x<times;x++) {
    digitalWrite(pinnum, HIGH);
    delay (lengthms);
    digitalWrite(pinnum, LOW);

The first code is for the deep sleep mode and wakes the Atmega 328PU up 
after an external interrupt.
The second code is a normal code (without any power saving option) and 
reads the digital input and sets a timer if the button was pressed. If 
the timer is over 3 seconds and the button is still pressed something 
will happen (for example a LED will flash).

So now my question is how to combine them? Is there any way to do that?
I hope somebody can help me :) I'm looking forward to your replies.

Best regards

Maurice W.

: Moved by Moderator
Author: Stefan Us (Guest)
Posted on:

Rate this post
0 useful
not useful
You have to wake up immediately when the button interrupt comes in. Then 
you can measure how long it is pressed and go back to sleep when the 
time was too short.


Entering an e-mail address is optional. If you want to receive reply notifications by e-mail, please log in.

Rules — please read before posting

  • Post long source code as attachment, not in the text
  • Posting advertisements is forbidden.

Formatting options

  • [c]C code[/c]
  • [avrasm]AVR assembler code[/avrasm]
  • [code]code in other languages, ASCII drawings[/code]
  • [math]formula (LaTeX syntax)[/math]

Bild automatisch verkleinern, falls nötig