Arduino: Software Debouncing in Interrupt Function...

50,940

24

34

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) {
    Interrupt();
    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...

Teacher Notes

Teachers! Did you use this instructable in your classroom?
Add a Teacher Note to share how you incorporated it into your lesson.

Be the First to Share

    Recommendations

    • Made with Math Contest

      Made with Math Contest
    • Multi-Discipline Contest

      Multi-Discipline Contest
    • Robotics Contest

      Robotics Contest

    34 Discussions

    None
    snakeboy69

    1 year ago

    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!

    1 reply
    None
    delphino-999snakeboy69

    Reply 5 months ago

    Hey, glad I could help. :-)
    I suspect your bucket tipping not to happen quickly enough for you to necessarily need an interrupt for it though. Of course if you have an interrupt capable pin left over why not. But if you ever need to accomplish this without an interrupt, I'm sure reading the input in the main loop would do the trick (assuming you don't use delays and your main loop runs quickly).

    None
    wirthx

    5 months ago


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

    When micros() is overflow (after 70 minutes of idle stage), last_micros will larger than micros() at that time. The interrupt will not work until reach to last_micros again. To fix this issue, add below in loop().
    if (micros()<last_micros) last_micros = micros();

    1 reply
    None
    delphino-999wirthx

    Reply 5 months ago

    Hey there thanks for the feedback, your concerns aren't an issue though. The code should work perfectly fine as is.
    It is true that the "long" value of micros() will overflow after around 70 minutes due to the limited amount of numbers that can be expressed using 32 bits of memory. But this also applies when you subtract a very big number from a very small number with 32 bits of memory. 10-4294967290 would normally equal -4294967280 but a long type variable can't hold that value. Therefore long(10-4294967290) equals 16. I hope this explanation helps you understand overflows a little better.

    None
    GuusV

    3 years ago

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

    3 replies
    None
    GuusVGuusV

    Reply 3 years ago

    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"

    None
    GuusVGuusV

    Reply 3 years ago

    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.

    None
    TheOriginalNerdGuusV

    Reply 11 months ago

    GuusV, for the SR latch you don't necessarily need to buttons, but you would need to pins. You can use 1 button attached and use a pin attached to the latch's input to reverse the latch.

    None
    ArthurR19

    3 years ago

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

    void debounceInterrupt() {
    noInterrupts();
    delayMicroseconds(15000);
    interrupts();
    // do something
    }

    4 replies
    None
    delphino-999ArthurR19

    Reply 3 years ago

    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.

    None
    ArthurR19delphino-999

    Reply 3 years ago

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

    None
    delphino-999ArthurR19

    Reply 3 years ago

    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. ;-)

    None
    XazhuaR

    2 years ago

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

    None
    duwageM

    2 years ago

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

    None
    MinhTuanT

    3 years ago

    Thank you very much :)

    None
    pisicaverde

    3 years ago

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

    1 reply
    None
    delphino-999pisicaverde

    Reply 3 years ago

    Wow, thanks!

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

    (one time would have been enough though)

    None
    pisicaverde

    3 years ago

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

    None
    pisicaverde

    3 years ago

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