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:
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?
-
Just to clarify, there is no delay between any of - any of what?Nick Gammon– Nick Gammon ♦2017年08月19日 00:31:13 +00:00Commented Aug 19, 2017 at 0:31
-
Be careful using delay functions in an ISR!!! Read the italics: arduino.cc/en/Reference/AttachInterruptlemontwist– lemontwist2017年08月23日 09:23:39 +00:00Commented Aug 23, 2017 at 9:23
4 Answers 4
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
-
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?patrick jackson– patrick jackson2017年08月22日 19:09:27 +00:00Commented Aug 22, 2017 at 19:09
-
No, it isn't essential to use an interrupt. Interrupts are not for lengthy pauses. See my extended answer above.2017年08月22日 21:51:48 +00:00Commented Aug 22, 2017 at 21:51
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");
}
}
}
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.
-
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?patrick jackson– patrick jackson2017年08月18日 23:03:34 +00:00Commented Aug 18, 2017 at 23:03
-
No, but you can record the time the interrupt occurred (hint hint)Majenko– Majenko2017年08月18日 23:09:03 +00:00Commented Aug 18, 2017 at 23:09
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.
-
2Please 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!2017年08月19日 00:35:21 +00:00Commented Aug 19, 2017 at 0:35