a hardware-independent software debouncer - Page 1
Forum section: electronics / general

author: dannyf
author_rank: Super Contributor
timestamp: June 06, 2016, 12:32:18 am
content: The Kuhn debouncer is well known for its simplicity and elegance: you simply integrate the incidents of key presses and non-presses - increment for key presses and decrement for non-presses.I took the approach and striped away the hardware specific elements so the routines themselves are now able to be compiled on any platform. The hardware-specific portion of reading a pin is done through a user-specified handler, as shown here:https://dannyelectronics.wordpress.com/2016/06/05/a-generic-software-debouncer/Full header and source files are available.The heart of the code is here:Code://update the integrator [0..CNT_MAX]if ((*(key->keyread))()==KEY_NOTPRESSED) key->cnt_key -= (key->cnt_key <= 0)?0:1;//decrement cnt_key if key is not pressedelse key->cnt_key += (key->cnt_key >= CNT_MAX)?0:1;//increment cnt_key if key is pressedAbout 30 ticks to execute on a PIC24F.To use it, you simply include the header + source files into your project, provide a handler to read the keys and call the key read routine, either in the main loop or through an interrupt (timer, or external interrupts or pin change interrupts).The code, as is, does not support fancier IO functions, like detection of key releases, double clicks, or long/short clicks. But they aren't difficult to add at all.Enjoy.edit: took out a typo.

author: nctnico
author_rank: Super Contributor
timestamp: June 06, 2016, 08:29:55 am
content: Why decrement when released? Just set the counter to zero when not pressed and when pressed count up to a maximum value and trigger at a certain value.

author: mikerj
author_rank: Super Contributor
timestamp: June 06, 2016, 10:20:17 am
content: Quote from: nctnico on June 06, 2016, 08:29:55 amThat's how I've always done it.

author: wraper
author_rank: Unknown
timestamp: June 06, 2016, 11:09:45 am
content: Quote from: nctnico on June 06, 2016, 08:29:55 amWhy??? Because it gives robust result when signal is not clean. Both presses and releases. The less clean signal is, the more time it take takes to trigger value. And signal don't need to completely settle for triggering the value. Allows very fast and reliable debounce even with very crappy switches.Quoteand that's the reason why many devices start to experience double/triple presses after the switches receive some wear when actually there was only one press.

author: dannyf
author_rank: Super Contributor
timestamp: June 06, 2016, 11:14:01 am
content: The stock key-get() returns two states right now, key pressed or keynotpressed.If you desire the detection of pin bounces (pin transitions), you can alter that routine to return keybounce as well.

author: wraper
author_rank: Unknown
timestamp: June 06, 2016, 11:19:45 am
content: Quote from: mikerj on June 06, 2016, 10:20:17 amThat's why sometimes I want beat up the people who made the debounce in some devices. Instant state change on button release = no debounce for it.

author: Kjelt
author_rank: Super Contributor
timestamp: June 06, 2016, 11:21:58 am
content: Quote from: nctnico on June 06, 2016, 08:29:55 amThat could work for short keypresses but not for long ones.So what if you have a requirement that the user should press the button for a long time , say 5s to reset the system and ten times the switch glitches. You will never get to the threshold or your software that lies underneath. You will get ten individual short keypresses with a different meaning.The integrator software should also allow for some overflow, so the threshold should IMO NOT be the maximum value as the Kuhn debouncer code has, it should be like a real hardware RC, which is below 0,8V it is not pressed and above 4V it is pressed for instance with a maximum of 5V. In the software we can make our own thresholds where in between it is a grey area and you don't know if the user was pressing the button and released it or is still pressing the button but not long enough for the threshold. Then you can correctly detect (very)long keypresses. Oh well in the end it is what you need and want, i like the contribution Danny.

author: dannyf
author_rank: Super Contributor
timestamp: June 06, 2016, 11:27:31 am
content: The detection of long pressed can be implemented if you use a lower threshold for short presses.For example, in the key get routine, you can return key-shortpressed or key-longpressed based on the value of the integrator.Detection of double clicks is a little more complicated and better suited for a fully implemented state machine.

author: wraper
author_rank: Unknown
timestamp: June 06, 2016, 11:30:55 am
content: Quote from: dannyf on June 06, 2016, 11:27:31 amJust noticed there is no low threshold after Kjelt mentioned it. It's no good without it. What you should do is trigger "1" when counter reaches max and trigger "0" when counter reaches zero. This way this is very robust, otherwise not robust at all.

author: AndyC_772
author_rank: Super Contributor
timestamp: June 06, 2016, 11:42:20 am
content: I don't like this method. It inherently adds delay between pressing a key and action actually being taken, which makes for a potentially frustrating user experience. A responsive UI is a hallmark of a well designed product, IMHO.Instead, I use a technique in which the very first time a button is detected as being pressed, it's acted upon. At the same time, a timer is initialised with a blanking interval, during which time no further changes in button state will be processed. Only when that blanking interval has elapsed will the button be enabled again. This eliminates the initial delay, and allows a relatively long debounce period to be used.The debounce period limits the time between consecutive button presses, not the time it takes for a single press to be recognised.Code:uint8_t blank_time = 0;uint8_t debounced_button = 0;void timer_isr (void){if (blank_time == 0){b = get_button_state();if (b != debounced_button){debounced_button = b;blank_time = DEBOUNCE_TIME;}}else{blank_time--;}}

author: wraper
author_rank: Unknown
timestamp: June 06, 2016, 11:44:30 am
content: Here is what I do for multiple inputs. Hopefully there are no errors because I just partially rewrote this right now because there was also some hardware related bit rearranging going in between in the code I copied it from.EDIT: button_data and Button_integrator are variables which holds the value between debounce cycles. Other variables can be reinitialized.Quote

author: Kjelt
author_rank: Super Contributor
timestamp: June 06, 2016, 11:47:03 am
content: Quote from: AndyC_772 on June 06, 2016, 11:42:20 amSo you don't debounce the switch then. You are only mitigating keypress bounces but if you're input is not really low ohms, a relais or other inductive noise source could trigger a false button press ?Better add a RC then.

author: AndyC_772
author_rank: Super Contributor
timestamp: June 06, 2016, 11:55:36 am
content: Debounce: yes!Filter short duration spikes that are nothing to do with contact bounce: no, obviously.If, in a given application, the switch inputs are prone to noise pick-up, then I agree that a timer is a good way to filter those. I've not personally found this to be a problem, but perhaps if the switches are remote from the processor then it would be more of an issue.Of course, in that case, you'd probably want to include an ESD or other transient suppressor near the CPU anyway, and possibly a current limiting resistor.Either way, I don't think it's good to have an inherent response delay equal to the worst-case contact bounce time. Noise spikes would - I'd expect - tend to be much shorter in duration, and could be filtered with a much shorter time constant than would be needed for reliable debouncing.

author: wraper
author_rank: Unknown
timestamp: June 06, 2016, 12:01:29 pm
content: Quote from: AndyC_772 on June 06, 2016, 11:55:36 amWith a code I posted above I can debounce 50-100 of presses per second with close to 100% reliability (tested with signal gen outputting bouncy crap). It is used where very small delay between presses is possible. Something similar to double click in mouses. If you make a delay between the presses, it would completely suck.

author: AndyC_772
author_rank: Super Contributor
timestamp: June 06, 2016, 12:08:27 pm
content: There's no way round the fact that, with any switch, the minimum time between consecutive clicks that can be recognised is a function of the worst-case contact bounce interval.All I'm doing is swapping the time when action is taken, and the waiting interval which we use to tell the difference between contact bounce and real clicks.Act, then wait, as opposed to wait, and then act.

author: Kjelt
author_rank: Super Contributor
timestamp: June 06, 2016, 12:12:27 pm
content: I do agree that the "waiting" or better integration time should be less than the human acceptable threshold, just as if you are for instance multiplexing led displays you don't want them to give a visible flickering.

author: wraper
author_rank: Unknown
timestamp: June 06, 2016, 12:22:15 pm
content: Quote from: AndyC_772 on June 06, 2016, 12:08:27 pmFor instant act on press you need additional delay after previous switch release. Otherwise your next press may be just some bounce on switch release. In my case I want both presses and releases registered as fast as possible. Not just press and then wait 0.1 s after release because with such delay you will miss fast double click on PC mouse, for example.

author: AndyC_772
author_rank: Super Contributor
timestamp: June 06, 2016, 12:34:49 pm
content: If your switch really might bounce for 100ms on release, then surely you have no choice?If you wanted to get really cute, you could impose a different waiting interval for press vs release. I'd expect a switch to bounce for longer on press than release, so you could do:Code:uint8_t blank_time = 0;uint8_t debounced_button = 0;const uint8_t debounce_time  = {50, 10}; // longer debounce time after a press than after a releasevoid timer_isr (void){if (blank_time == 0){b = get_button_state();if (b != debounced_button){debounced_button = b;blank_time = debounce_time ;}}else{blank_time--;}}

author: nctnico
author_rank: Super Contributor
timestamp: June 06, 2016, 01:53:49 pm
content: Quote from: Kjelt on June 06, 2016, 11:21:58 amTrue but you have to ask yourself how well a device works if the switches are that flaky. And how does it tell the difference between 2 short presses and one long press? BTW I always put the counter on a tens of milliseconds interval so very short interruptions are likely to be missed anyway.@AndyC_772: It is true that this method introduces a short delay but the trick is to make it so short the user doesn't notice it. When dealing with a switch I want to see it's signal active at least 3 times during 50ms to 100ms before letting the firmware do something. It depends on the application but in many cases you really need to be sure a button is pressed and it is not moisture playing games with your device.

author: wraper
author_rank: Unknown
timestamp: June 06, 2016, 02:24:07 pm
content: Quote from: nctnico on June 06, 2016, 01:53:49 pmAlmost all of the tact switches are that flaky, especially as time passes. If the switch is not pressed at exacly at the right angle, not pressed hard, and user's finger is not stiff enough, it will produce gibberish during the long press. I personally don't want to rely on quality of the switches used. I prefer design working reliably even with crappiest of them.From my experience in repairing things - When tact switches get flaky, a glaring example is when people start pressing them very hard (literally with full strength) and by this completely destroying them very fast (membrane becomes flat). If there was decent debounce, they would survive much longer time.

author: AndyC_772
author_rank: Super Contributor
timestamp: June 06, 2016, 02:31:58 pm
content: Quote from: wraper on June 06, 2016, 02:24:07 pmIsn't this exactly what people do if a button doesn't appear to work immediately?Technical people might work out that the correct way to use a button, is to press and be patient.The other 99% would, I suspect, decide that 'press hard' is necessary. Hence my desire to ensure a button has an effect asap.

author: BravoV
author_rank: Super Contributor
timestamp: June 06, 2016, 02:32:58 pm
content: Post just to sub ..... carry on folks ..

author: suicidaleggroll
author_rank: Super Contributor
timestamp: June 06, 2016, 03:09:02 pm
content: Quote from: AndyC_772 on June 06, 2016, 02:31:58 pm"Immediately" in the human world and "immediately" in the button debounce world are two very different things. A user will not notice a 10ms delay that's been added to the button press to debounce it, and they certainly won't get frustrated to the point of hammering on the button because it's not reacting...

author: mikerj
author_rank: Super Contributor
timestamp: June 06, 2016, 03:57:26 pm
content: Quote from: wraper on June 06, 2016, 11:19:45 amIf you only need to detect the press event (rather than release event) I don't see the problem? Irrespective I have never made a device where contact bounce has caused user interface problems.

author: dannyf
author_rank: Super Contributor
timestamp: June 06, 2016, 08:33:19 pm
content: Having done all thee software denouncing work, I have to say that I'm not a fan of software denouncing.For one reason: simplicity. Forr all software denouncing could do, I can do it with AA simple RC filter. And the incremental woork there is to add a capacitor: I always put a serial resistor on mcu pins connected to the outside world, for protection. So addig a resistor to a schmitt trigger inout pin is all I need to do for a simple debouncer.

author: nctnico
author_rank: Super Contributor
timestamp: June 06, 2016, 08:36:52 pm
content: The schmitt trigger is what makes things hairy. Many microcontrollers don't have schmitt trigger inputs and some even have truly awfull logic level thresholds (like Atmel's Attiny).

author: jpanhalt
author_rank: Super Contributor
timestamp: June 07, 2016, 12:06:31 am
content: @dannyfThank you for the links to your blog and Kuhn's description. I have been unhappy with my software debouncer and wrote a small program for that approach (simulates, but not thoroughly tested). I only use Assembly, and the code requires one register and a couple of rotates. This is for a switch (PORTC,0) that is low when open and waits for a low before returning from the ISR.EDIT: Couldn't get the code to format, so added as image attachment.EDIT2: Was worried about a step and in fact, it is a bug with a more complex simulation.Disregard code, it doesn't work. If fixed, I will repost.EDIT3: Fixed that bug. There may be others. Updated image attachment. Changed rlf debounce,w to rlf debounce,f and added step.I realize this may be of interest to only 13 people in the world. But when you are retired, that doesn't matter.JohnEdit: That code looks horrible, but looked fine in the "preview." What is the preview for if it doesn't work? Tried pasting from MPLAB, as I usually do and skipped preview. That wasn't much better. Attached image. Sorry for inconvenience.

author: dannyf
author_rank: Super Contributor
timestamp: June 07, 2016, 12:30:12 am
content: jpanhalt: i'm happy that it is of use to you.

author: Alex Eisenhut
author_rank: Super Contributor
timestamp: June 08, 2016, 12:22:14 am
content: Quote from: wraper on June 06, 2016, 11:09:45 amLike my Breville toaster oven... grrrrr....

author: obiwanjacobi
author_rank: Super Contributor
timestamp: June 08, 2016, 07:45:57 am
content: I like the adaptive nature of an integrator, provided it is called frequently enough - you don't want to starve it - which in some apps may require some thought... If the switch gets old and bounces more, it'll just take longer to make out a steady state. Sounds fine.I like the argument that Andy brought forth about reacting on first sign of change and doing the debouncing afterwards...I also like the argument that you could really solve this easily in hardware too (do you really need a schmitt-trigger input?) which saves you some software complexity. This however, is not adaptive with the switch's wear....I have written an implementationthat uses approximate time to debounce (and detect hold). I would not mind making a 'better' or alternative implementations...So how would you consolidate these aspects into a solid implementation?

author: nctnico
author_rank: Super Contributor
timestamp: June 08, 2016, 07:59:49 am
content: Quote from: Alex Eisenhut on June 08, 2016, 12:22:14 amStill you have to consider what can happen if a switch starts to make contact by itself due to moisture or dirt. Do you want your toaster to start toasting by itself with the chance of setting the bread crumbs inside on fire and burning down your house? One of the systems I worked on was for dispensing drinks in bars and restaurants. Replacing a flaky switch is much cheaper than cleaning up a 2000 liter beer spill.

author: KL27x
author_rank: Super Contributor
timestamp: June 09, 2016, 07:38:08 pm
content: +1 to Andy C. For human input switches, I prefer the action to occur immediately, then time out long enough for the switch bounces to end. This is where the noise from the switch, itself, and not other devices on the power rail, are the only concern, of course. If the circuit is getting false signals outside of switch transition that are big enough to register state change, I would probably try to fix the hardware. Many of the micros I use have Schmitt trigger inputs available. I don't often have such problems.

author: wraper
author_rank: Unknown
timestamp: June 09, 2016, 07:43:11 pm
content: Quote from: KL27x on June 09, 2016, 07:38:08 pm<20-30 milliseconds delay is not fast enough for you?

author: dannyf
author_rank: Super Contributor
timestamp: June 09, 2016, 11:58:27 pm
content: There is some merit in responding to the leading edge of key bounces, if you assume that a key wouldn't bounce unless it is pressed. To me, however, that is not a robust enough of an assumption, as there could be line noise, or accidental but short key presses (from mechanical shock for example). But I certainly understand how others may choose that approach.If so, the Kuhn debouncer can be easily adapted to capture most (but not all) such cases, by changing the key_get() routine to this:Code://return key stateKEY_STATE key_get(KEY_TypeDef *key) {return (key->cnt_key != 0)?KEY_PRESSED:KEY_NOTPRESSED;//could be made to return KEY_BOUNCE}Essentially it is saying that as long as the debouncer is working (key->cnt_key !=0), the key must have been pressed.That logic fails if the duration of signal KEY_NOTPRESSED is longer than the duration of signal KEY_PRESSED, which statistically speaking is not as likely as the other way around conditional on the key having been pressed.

author: Kjelt
author_rank: Super Contributor
timestamp: June 10, 2016, 05:34:59 am
content: What i have seen done multiple times on adc inputs and could also work for switches is using an moving average algorithm, the size of the buffer, sampling frequency and threshold will determine the debounce and response time. However these cost ram which usually is a scarce resource in embedded projects.

author: jpanhalt
author_rank: Super Contributor
timestamp: June 10, 2016, 08:06:45 am
content: Let's say you have a press and release, like most button switches. Of course, you can respond to the first change, but if you are going into an interrupt, don't you still have to wait for the release bounce to end before exiting? (Or use some other mechanism to delay enabling that interrupt.)The SR method with cross-connected NAND's actually removes bounce rather than waits for it to be over. Unfortunately, that method requires a double-throw switch, which are hard to find.After a bit more reading, I have decided to try using the "release" edge of a button switch to initiate an interrupt, rather than the first change, and to go with hardware debounce. Hardware plus interrupt on release avoids having to poll the switches and/or to wait in the interrupt.John

author: AndyC_772
author_rank: Super Contributor
timestamp: June 10, 2016, 08:14:40 am
content: In the ISR, you set a flag which indicates that a button has been pressed, do whatever you want to do with timers and counters to de-bounce the switch, then exit. It should be a very quick process.In some foreground task, you poll the flag at a convenient time to see if it's been set since last time you checked. If it has, then you clear the flag, and do whatever the button is meant to do. This could take quite a long time, so it's not something you want to be doing in an ISR anyway.

author: jpanhalt
author_rank: Super Contributor
timestamp: June 10, 2016, 08:25:20 am
content: Quote from: AndyC_772 on June 10, 2016, 08:14:40 amThat (underlined) is what I want to avoid. Debounce usually has a wait of 10ms to 40ms. At 16 MHz with a PIC, even 10 ms is equal to a lot of instructions. That seems to be contrary to the advice to keep interrupts short.On the other hand, if you don't even enter the ISR until all bouncing is over, then time there can be short. As for the flags being set and so forth, that is what I do.John

author: AndyC_772
author_rank: Super Contributor
timestamp: June 10, 2016, 08:36:15 am
content: I think you misunderstand how debouncing is done.The ISR is entered each time the switch input changes state. This is exactly once per press and once per release for a 'perfect' switch, and maybe 2 or 3 times per change for a bouncy one.The purpose of the de-bouncing code is to make a decision as to whether each state change is due to an actual press or release, or whether it's just contact bounce. Once that decision has been made, the ISR exits. Since the code to make that decision is simple, the actual time spent in the ISR is minimal.There's clearly some differences of opinion on what the criteria should be, but I think we're all in agreement that you don't just sit in the ISR doing nothing until the debounce period has elapsed.

author: jpanhalt
author_rank: Super Contributor
timestamp: June 10, 2016, 09:35:53 am
content: @AndyC_772Assume you enter the ISR on the first rising edge as has been suggesed and the switch bounces for 10 ms. A short ISR will exit and re-enable the interrupt well before that bouncing ends. So, you have the potential to get multiple interrupts.Now, if you wait until the bouncing is over, then you are stuck in the routine for a long time. Hardware debounce will delay entering the routine, but it doesn't carry a risk of exiting while the switch is still bouncing.John

author: AndyC_772
author_rank: Super Contributor
timestamp: June 10, 2016, 10:08:37 am
content: Quote from: jpanhalt on June 10, 2016, 09:35:53 amYes, you do, absolutely. Intentionally so, by design. Each individual change in state of the button input causes a jump to the ISR.Your ISR in turn makes a decision about whether the state change was 'real' or not.If it's 'real', then the ISR signals to some other process that the button state has really changed, and requires action. That other process updates the UI, changes a setting, or whatever else the button was meant to do.If not, and the switch is deemed to simply be bouncing, the ISR exits with no further action taken.

author: dannyf
author_rank: Super Contributor
timestamp: June 10, 2016, 10:33:11 am
content: QuoteThe Kuhn debouncer is a moving average algorithm.QuoteRelease-based actions are more reliable, obviously. But it is a little counter-intuitive for the user, and it also requires debouncing: the buttons bounces on both presses and releases.If you are simply detecting on the first release, and ignoring the subsequent bounces, the Kuhn debouncer can be modified easily to detect that too.

author: jpanhalt
author_rank: Super Contributor
timestamp: June 10, 2016, 11:08:09 am
content: Right now, I have re-designed the circuit to use hardware debounce.Even with testing only for first release, you are still talking about a of time in the ISR, unless you somehow delay re-enabling that interrupt.BTW, the code I posted earlier is not really Kuhn's method. It looks for consecutive ones or zeros, which is what the MAX681x and MC14490 also do. I later wrote some code for averaging that actually uses Kuhn's method and works pretty well. Each routine is 9 instructions, excluding the delay call or macro.Will these debouncing delays actually affect what I am doing now? Probably not. The only time-critical interrupt in my code is caused by a TMR0 overflow.Regards, John

author: dannyf
author_rank: Super Contributor
timestamp: June 10, 2016, 11:23:17 am
content: QuoteThe Kuhn debouncer can be made to do that too. For example, rather than decrementing the integrator on KEY_NOTPRESSED, you reset it. Under that scheme, KEY_PRESSED is returned by key_get() if and only if a consecutive number of KEY_PRESSED is detected.The beauty of this particular implementation is the separation of the integration and the detection of the key's states.

author: nctnico
author_rank: Super Contributor
timestamp: June 10, 2016, 01:51:38 pm
content: Quote from: AndyC_772 on June 10, 2016, 08:36:15 amThat is a very, really very bad idea! I've seen embedded applications come to a grinding halt (*) due to interference on a switch input. If you use an interrupt to flag a switch then you'll also need to disable the interrupt at that point and enable it from the main process. This also kinda negates the need for using interrupts because what is the difference between polling a flag and a GPIO? Interrupts are for stuff which needs a timely response which cannot be guaranteed by the main loop. A switch is unlikely to need an interrupt since a response time below 100ms to 200ms is perceived as immediately.* Worst example I've seen is several meters of wire connected to a doorbell on an unprotected I/O pin. At some point the system started to become flaky but my co-workers tasked with that project could not figure out what was wrong. I just never realised they where so stupid to use an interrupt for detecting a key switch input.-out of hands and faces error-

author: jpanhalt
author_rank: Super Contributor
timestamp: June 10, 2016, 02:16:33 pm
content: Just and FYI to add. I was browsing the new 3rd edition of Horowitz and Hill and came across this "debouncer" on page 730. There is a brief discussion of why it works there. So far as I can tell, it is not in the 2nd edition.I had not seen such a simple version before. Would be interested in testing it, but I can't find a bad switch to do it with.John

author: nctnico
author_rank: Super Contributor
timestamp: June 10, 2016, 03:01:30 pm
content: Pretty useless since 99.999% of the pushbuttons is single pole.

author: bingo600
author_rank: Super Contributor
timestamp: June 10, 2016, 03:04:44 pm
content: I'm debouncing in a 10ms timer IRQUsing Peter D's code , that implements (if remember corect) a 4bit barrelshifterPeter's code (attached)http://community.atmel.com/projects/efficient-key-debounceThreads (German)https://www.mikrocontroller.net/topic/tasten-entprellen-bulletproof#newI never had any problems , and even extended it to so a 4 x 3 keyboard wo. problems./Bingo

author: nctnico
author_rank: Super Contributor
timestamp: June 10, 2016, 03:10:09 pm
content: The golden rule is: don't use lines from buttons or switches as interrupt sources! Ofcourse you can use a timer interrupt to poll keys. The only (extra) problem you'll have is parallel thread synchronisation to convey the switch value to the main process.

author: dannyf
author_rank: Super Contributor
timestamp: June 10, 2016, 03:35:07 pm
content: QuoteThe following change in the Kuhn debouncer would do the same thing:Code://update the integrator [0..CNT_MAX]if ((*(key->keyread))()==KEY_NOTPRESSED) key->cnt_key = 0;//reset cnt_key if key is not pressedelse key->cnt_key += (key->cnt_key >= CNT_MAX)?0:1;//increment cnt_key otherwiseThe rest remains unchanged.Under XC8 Free, the Kuhn version compiles to 17 instructions and the Peter version compiles to 36 instructions. However, it does have the advantage of being able to read multiple buttons at once, assuming that they are on the same port.

author: klunkerbus
author_rank: Unknown
timestamp: June 10, 2016, 03:38:08 pm
content: Quote from: bingo600 on June 10, 2016, 03:04:44 pmI've been meaning to mention the Danni/Dannegger debounce myself. It was developed for AVR, but there's no reason why the algorithm couldn't be used on any hardware with some sort of periodic housekeeping interrupt where the switch inputs can be sampled. I usually have one running at 1mSec or 5mSec intervals. Crazy efficient; the code supports 8 inputs with the same processing cycles as one input.There's not much to the code but it can hard to understand, and sometimes I wish for more than 4 matching states in the vertical adder before change of state is detected. But it usually works pretty good except on my crappiest switches. Gurus and moderators in the AVRFreaks forum have a heyday blasting any other scheme.