Introduction: Arduino: Software Debouncing in Interrupt Function...

Picture of Arduino: Software Debouncing in Interrupt Function...

Hi everybody!

So recently i was working on a Project where i wanted to meassure the RPM of one of the Wheels on my Car, and from that calculate the Speed, keep track of the Driven distance etc. with an Arduino.
I wanted to use a Magnet and a Reed Switch to meassure the RPM, for that i needed to debouce the Signal from the Reed Switch, since i couldn't find any way to debouce a signal in interrupt functions that didn't require additional hardware for debouncing the signal on the Internet, here is how i debounced the Signal comming from the Reed Switch...

//Software debouncing in Interrupt, by Delphiño K.M.

long debouncing_time = 15; //Debouncing Time in Milliseconds
volatile unsigned long last_micros;

void setup() {
  attachInterrupt(0, debounceInterrupt, RISING);

void loop() {

void debounceInterrupt() {
  if((long)(micros() - last_micros) >= debouncing_time * 1000) {
    last_micros = micros();

void Interrupt() {
  //Do Something

You could also "Do Something" in the main function, instead of calling a second function that then does something, i just liked it better this way...

Note: I've only tried this on an Arduino Mega (ATmega1280), with Arduino 0022.
Also, this isn't a perfect solution, the interrupt function is stil called multiple times, the follwing calls, in the next 15ms are just ignored, but hey, it does the job, so screw it!

Well, thats about it, i hope this helps someone...

P.S. This is my first Instructable, so if you don't have anything nice to say, don't say anything at all, allthough corrections, improvements, etc. are of course allways welcome...


snakeboy69 (author)2017-12-07

I have a rain gauge that uses a tipping bucket with a reed switch/magnet to calculate fallen rain and have been having issues with random interrupt triggering. I tried this code and after updating the value to 30 milliseconds, I've been able to eliminate this problem. Thank you!

ArthurR19 (author)2015-12-31

Why not simply do this to avoid needless interrupts during bouncing:

void debounceInterrupt() {
// do something

SouravB22 (author)ArthurR192017-03-15

Wow, this solution is so elegant.

delphino-999 (author)ArthurR192016-01-12

Interrupts should execute as fast as possible though, so the microcontroller/computer can go back to the main loop. This especially plays a role when you have multiple hardware interrupts, since you can only have one triggered at a time. While your code would also work, it may 'cause problems in certain situations, 'cause the interrupt causes the program to pause for 15ms each time the interrupt is triggered. So if the interrupt is triggered 50 times per secons for example, your program would be waiting doing nothing 75% of the time.

ArthurR19 (author)delphino-9992016-01-13

I use the routine only for debouncing a tactile switch. It's no problem to pause the main program for 15 ms.

delphino-999 (author)ArthurR192016-01-13

In that case you can do it that way, it's good practice though to keep your main loop (and especially interrupts) running as fast as possible. In some cases you will need every last spare moment your microcontroller has and in that case it's not a particularly good idea, to have it sit and wait though delays all the time. ;-)

XazhuaR (author)2016-11-24

Thank you, it seems to work well! But for my buttons I had to make the delay 300micros to get a good result.

duwageM (author)2016-10-24

Hi thanks for tutorial. I tested with Esp 12E and work great.

MinhTuanT (author)2016-06-17

Thank you very much :)

pisicaverde (author)2016-03-10

I signed up to Instructables just to say Thanks for this tutorial :)

delphino-999 (author)pisicaverde2016-03-10

Wow, thanks!

I'm glad if it helped you. :-)

(one time would have been enough though)

pisicaverde (author)2016-03-10

I signed up to Instructables just to say Thanks for this tutorial :)

pisicaverde (author)2016-03-10

I signed up to Instructables just to say Thanks for this tutorial :)

pisicaverde (author)2016-03-10

I signed up to Instructables just to say Thanks for this tutorial :)

pisicaverde (author)2016-03-10

I signed up to Instructables just to say Thanks for this tutorial :)

matti.virta.1 (author)2016-01-12

hi, i try adding thats my project manytime and change code but not working,'

my project have 1 button make led pwm ,25 on/off, and 2 button make same leds pwm 255 and flash plinking led on 100 and off 150, but debouncer not working ,sometime code do leds have on alltime and sometime leds plink alltime and buttons not do anythink, how i made thats working right ? i no understand help please, i use buttons whit pull up, +5 volt--resistor---button and ardunio, other side button have ground. leds normal arduino---resistor--tip 120 transistor--led---ground.

I don't know, did you try increasing the debounce time to 100ms or so?
If you're debouncing a button, you probably don't need such a short
debounce time, since you're likely not gonna push the button it more than 10 times
a second...

P.S. Most Arduinos have internal pull up resistors on the majority of their pins, that can be activated using "pinMode(pin, INPUT);
digitalWrite(pin, HIGH);" or "pinMode(pin, INPUT_PULLUP);" depending on which IDE version you're using. So unless you need a specific pull up resistance or a pull down resistor for some reason, you can save yourself the effort of hooking up a pull up resistor by using the internal one. ;-)

delphino-999 (author)2016-01-12

Since a couple of people have apparently been using this to debounce buttons, I would like to note that in most cases, you won't necessarily need an interrupt for a button. Since you can't possible push the button fast enough for the Arduino to miss it (if your code runs rasonably fast), you could just digitalRead(); the pin the button is connected to somewhere in the main loop and make sure it only reacts to it if the button wasn't pushed in the last 100ms or so.
Since you have a limited number of hardware interrupt pins, it's good practice, to try and save them for when you really need them. ;-)

GuusV (author)2015-11-01

I tried this code in combination with hardware debouncing like described in this article: When I keep the button pressed the interrupt is keep getting called. Why is this, when it is triggered on RISING edge?

GuusV (author)GuusV2015-11-01

Currently I switched to using an SR latch to toggle a state ON or OFF, but it requires 2 buttons. But I have not yet seen it fail and trigger multiple interrupts. And the interrupt routine now only requires 1 line: "state = !state"

GuusV (author)GuusV2015-11-01

On second thought, not happy with SR switch as the initial state of Q is unknown and can be either 1 or 0. Also I used 2 buttons and 2 interrupts.

I am now using a 555 in monostable mode (.5 sec output pulse width) which uses 1 button and is consistent when triggering a switch on RISING edge. I have not yet been able to trigger the interrupt multiple times.

AndreaM21 (author)2015-07-09

Hello! I'm fighting with a 220V desktop light that introduce a big bounce in the net. My arduino is connected to the pc with the usb cable. The PC and the light are on the same source. I find a solution with a bouncing incremental variable that is confronted with a bounced tolerance. My project is different but this solution should be useful for projects that required long intervaled interrupt.

//#include <Button.h>
#include <MaxMatrix.h>
#include <avr/pgmspace.h>

const byte A[] = {
4, 8, B1111110, B0010001, B0010001, B1111110 //A

const byte empty[] = {
8, 8, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000 // all leds off

const byte full[] = {
8, 8, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111 // all leds on

const byte face[] = {
8, 8, B00000000, B00000000, B00000000, B00011000, B00011000, B00000000, B00000000, B00000000, // ONE
8, 8, B00000011, B00000011, B00000000, B00000000, B00000000, B00000000, B11000000, B11000000, // TWO
8, 8, B11000000, B11000000, B00000000, B00011000, B00011000, B00000000, B00000011, B00000011, // THREE
8, 8, B11000011, B11000011, B00000000, B00000000, B00000000, B00000000, B11000011, B11000011, // FOUR
8, 8, B11000011, B11000011, B00000000, B00011000, B00011000, B00000000, B11000011, B11000011, // FIVE
8, 8, B11011011, B11011011, B00000000, B11011011, B11011011, B00000000, B11011011, B11011011, // SIX


int din_pin = 0; // atmega = PD0(RXD) = 0 | arduino mapping = pin 0
int load_pin = 1; // atmega = PD1(TXD) = 1 | arduino mapping = pin 1
int clock_pin = 2; // atmega = PD2(int0) = 2 | arduino mapping = pin 2

int interrupt_pin_real = 1; //atmega = PD3(int1) = 1 | arduino mapping = pin 3 (write the real one)
int interrupt_pin_mapped = 3;

int matrix_number = 4;

volatile int bounce_tol = 300;
volatile int bounce = 0;

int i = 0;

volatile int state = LOW;

MaxMatrix m(din_pin, load_pin, clock_pin, matrix_number);

void setup()
m.setIntensity(15); // dot matix intensity 0-15


attachInterrupt(interrupt_pin_real, state_changer, LOW);


void state_changer(){
if(bounce >= bounce_tol){
state = !state;
bounce = 0;

void magic_box(int sleep){

int num_1 = random(6);
int num_2 = random(6);
int num_3 = random(6);
int num_4 = random(6);

m.writeSprite(0, 0, &face[num_1*10]);
m.writeSprite(8, 0, &face[num_2*10]);
m.writeSprite(16, 0, &face[num_3*10]);
m.writeSprite(24, 0, &face[num_4*10]);


void rolling(){







void clear_matrix(){
m.writeSprite(0, 0, empty);
m.writeSprite(8, 0, empty);
m.writeSprite(16, 0, empty);
m.writeSprite(24, 0, empty);

void loop() {

//digitalWrite(interrupt_pin_mapped, HIGH); // no pull up needed

if(state == HIGH){

if(bounce < bounce_tol){

state = LOW;
bounce = 0;


JadinA2 (author)2015-04-12

Thanks, this was a nice temporary alternative to hardware debouncing.
Probably not perfect, but it works well for simple push button stuff.

markzielon (author)2015-03-16

This is very simple and works quite well. Thank you for posting.

If anyone is looking to use this code with a push button, I would recommend setting the debouncing_time to "150", potentially even slightly higher. Lower than this could still give you bouncing issues with certain buttons; I find it to be a happy medium between relatively fast button presses and errors.

That being said, 150 definitely wouldn't be suitable in a video game controller.

heltonbiker1 (author)markzielon2015-03-29

You are right, I've chosen 200ms to turn a blinking bike light on and off. Less than that would be unstable.

One thing to consider is that button bouncing should not happen in the first place, if there was an "ideal" button. So I guess for video games, and PC keyboards I guess, the electrical contact of the button must be better (or at least they perform hardware debouncing, while here we are doing software debouncing).

All in all, I found this instructable very instructive! And I don't think it is a big problem, as the OP says, in the function being called but ignored, I suppose every debouncing tutorial I've seen so far use the same technique, with some variations. But this one is very straightforward, and works exactely as expected!

Derek J (author)2014-08-04

There are two bugs here.

1. If the interrupt occurs just before micros() overflows, Interrupt() is not called, but should be. (last_micros is greater than micros(), giving a negative value that will not be larger than the debounce time.)

2. Calling micros() twice. It should be called once and the value stored in a local variable, before the expression is evaluated.

Also poor strategy to call another function from an ISR (which should get finish work fast) and hides the fact from another programmer that adding work in Interrupt() might be bad...

Derek J (author)Derek J2014-08-04

Oops, the first one is not a bug, because of the way C handles unsigned long arithmetic...

amandaghassaei (author)2012-10-24

cool, check out how I set up my bike speedometer, I used interrupts, but I found that I didn't need to debounce, maybe because the bike moves much slower and I was only checking the reed switch at 1ms intervals:

Sorry for the super late reply... :)
Hmm, maybe you had a better reed switch then i, mine really sucked! ;)
I'm a little confused about you using interrupts but only checking the reed switch at 1ms intervals, i mean if you were using interrupts you wouldn't be checking the reed switch in certain intervals, the whole point of an interrupt is for the Arduino to run a small part of code everytime something happens. Or were you using timer interrupts to check if the reed switch is closed at 1ms intervals? I guess that would explain why you didn't need to debounce. Your reed switch probably just bounced less than 1ms... :)

Anyhow, thanks for your comment! ;)

yes, timer interrupts, and yes, you're probably right about the debouncing.

About This Instructable




More by delphino-999:Arduino: Software debouncing in interrupt function...
Add instructable to: