2

I'm using a simple microswitch on pin 2, to activate an external interrupt.

void pause()
{
  Serial.print("\n\nPause\n\n");
  delay(1000);
}

void setup()
{
  pinMode(2, INPUT_PULLUP);
  attachInterrupt(0, pause, RISING);
  Serial.begin(9600);
  delay(1000);
}

void loop()
{
  Serial.print("\nGoing");
  delay(100);
}

When I tap the micro switch, some reason, my serial monitor output looks like this:

enter image description here

Just to clarify, there is no delay between any of

Is this just some serious debouncing, causing my Arduino to find lots of rising instances? or is there some kind of problem in my code?

2
1

I have a page about using switches but since I don't want to give a link-only answer I'll summarize here.


Detect switch changes

What is needed is to detect a transition. That is, either:

  • It was closed and is now open.

Or:

  • It was open and is now closed.

To do that you need to "remember" the previous state of the switch and detect a change, like this:

const byte switchPin = 8;
byte oldSwitchState = HIGH;  // assume switch open because of pull-up resistor

void setup ()
  {
  Serial.begin (115200);
  pinMode (switchPin, INPUT_PULLUP);
  }  // end of setup

void loop ()
  {
  // see if switch is open or closed
  byte switchState = digitalRead (switchPin);

  // has it changed since last time?
  if (switchState != oldSwitchState)
    {
    oldSwitchState =  switchState;  // remember for next time 
    if (switchState == LOW)
       {
       Serial.println ("Switch closed.");
       }  // end if switchState is LOW
    else
       {
       Serial.println ("Switch opened.");
       }  // end if switchState is HIGH
    }  // end of state change

  // other code here ...

  }  // end of loop

This code looks for changes, and only displays something when the switch changes.


By the way, you should be doing neither delay nor Serial.print inside an interrupt, as both of the rely upon interrupts being active, and interrupts are not active inside an ISR.


Debouncing

A simple technique is just to build in a short delay, for example 10 milliseconds (ms). For example:

const byte switchPin = 8;
byte oldSwitchState = HIGH;  // assume switch open because of pull-up resistor
const unsigned long debounceTime = 10;  // milliseconds

void setup ()
  {
  Serial.begin (115200);
  pinMode (switchPin, INPUT_PULLUP);
  }  // end of setup

void loop ()
  {
  // see if switch is open or closed
  byte switchState = digitalRead (switchPin);

  // has it changed since last time?
  if (switchState != oldSwitchState)
    {
    oldSwitchState =  switchState;  // remember for next time 
    delay (debounceTime);   // debounce
    if (switchState == LOW)
       {
       Serial.println ("Switch closed.");
       }  // end if switchState is LOW
    else
       {
       Serial.println ("Switch opened.");
       }  // end if switchState is HIGH
    }  // end of state change

  // other code here ...

  }  // end of loop

In the above code the delay is inside loop (where it is OK to use it) and causes a short pause to allow the switch to stop bouncing.


Debouncing without delay

The above code is fine in simple applications, and if you test it, you should find that the message "Switch closed." and "Switch opened." should only occur once per switch press. But, there's a problem. If you hang around the Arduino forums for a little while you will probably see people telling you "don't use delay". There are various reasons for this, not the least is which that using delay stops your code from doing anything else useful (like testing sensors, controlling motors, flashing LEDs, etc.).

The code below does not use delay, but rather checks for the time that has elapsed after you hit the switch, and sees if the "debounceTime" (in this case 10 ms) has elapsed. If not, it ignores the transition.

const byte switchPin = 8;
byte oldSwitchState = HIGH;  // assume switch open because of pull-up resistor
const unsigned long debounceTime = 10;  // milliseconds
unsigned long switchPressTime;  // when the switch last changed state

void setup ()
  {
  Serial.begin (115200);
  pinMode (switchPin, INPUT_PULLUP);
  }  // end of setup

void loop ()
  {
  // see if switch is open or closed
  byte switchState = digitalRead (switchPin);

  // has it changed since last time?
  if (switchState != oldSwitchState)
    {
    // debounce
    if (millis () - switchPressTime >= debounceTime)
       {
       switchPressTime = millis ();  // when we closed the switch 
       oldSwitchState =  switchState;  // remember for next time 
       if (switchState == LOW)
          {
          Serial.println ("Switch closed.");
          }  // end if switchState is LOW
       else
          {
          Serial.println ("Switch opened.");
          }  // end if switchState is HIGH

       }  // end if debounce time up

    }  // end of state change

  // other code here ...

  }  // end of loop

More information on the Arduino site: http://arduino.cc/en/Tutorial/Debounce


It is essential for me to use an interrupt, because I need to be able to pause my entire program, at the push of a button, then resume it when the button is pushed again. I heard from other people that I cannot use any type of delay in the interrupt, is this true?

You don't really pause a program with delay, it is now just doing something else (waiting for a timer to reach a certain time). Timers depend on interrupts to update counters as the hardware timer will overflow (roll over) very rapidly.

I suggest a redesign. In your main loop, for example, you could detect the switch press, and then not do anything until it is pressed again. For example, where I had "other code here" in my example:

static bool switchWasPressed;

if (switchWasPressed)
  {
  // do nothing
  }
else
  {
  // do what you want to do continuously
  }

Now, in the code which detects switch presses you toggle switchWasPressed. So instead of:

Serial.println ("Switch closed.");

You put:

switchWasPressed = !switchWasPressed;  // toggle switch press state
2
  • It is essential for me to use an interrupt, because I need to be able to pause my entire program, at the push of a button, then resume it when the button is pushed again. I heard from other people that I cannot use any type of delay in the interrupt, is this true? Aug 22 '17 at 19:09
  • No, it isn't essential to use an interrupt. Interrupts are not for lengthy pauses. See my extended answer above.
    – Nick Gammon
    Aug 22 '17 at 21:51
1

Do you really need to use an interrupt to debounce a switch? If not, this library may work for you: https://playground.arduino.cc/uploads/Code/Debounce.zip. It is easy to use and assumes you are using a normally open switch with one connection to ground and the other connected to pin 4 on the Arduino.

    #include <Debounce.h>
    const byte SWITCH = 4;

    Debounce debouncer = Debounce(50, SWITCH);

    void setup(){
      Serial.begin(9600);
      pinMode(SWITCH, INPUT_PULLUP);
    }

    void loop(){
      if(debouncer.update()){
        if(debouncer.read() == 0){
          Serial.println("Button Pressed");
        }
        else if(debouncer.read() == 1){
          Serial.println("Button Released");
        }
      }
    }
0

Yes, it is bouncing of your button.

You are seeing it because delay() does not work, and cannot be used, in an interrupt.

Also delaying in an interrupt is completely opposite to the whole ethos of interrupt programming.

2
  • Thanks, but is there a way for me to put a delay in the interrupt, so the second I press the button it just pauses before any debouncing can occur? Aug 18 '17 at 23:03
  • No, but you can record the time the interrupt occurred (hint hint)
    – Majenko
    Aug 18 '17 at 23:09
0

your code works as coded - whether it works as expected is unknown.

basically the isr is triggered on the first edge, and the execution loops around in the isr, and the execution returns one second later.

As a result, your code missed most of the "bouncing", actually it missed all bounces other than the very first one.

not an effective debouncing strategy.

yes, delays or while loops can be used in an isr, so long as you know what you are doing.

1
  • 2
    Please take the time to use proper English on this site. Proper English includes starting sentences with capital letters. As a reasonably high-rep user, who posts a lot of useful answers, you are setting standards for others to follow. Please take the time to capitalize your sentences correctly. Thanks!
    – Nick Gammon
    Aug 19 '17 at 0:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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