-1

I'm working on building a keyboard, and some of the firmware runs on a wireless module programmed in C. I'm trying to roll my own debounce algorithm, and could use some help. Essentially, here's how the code is layed out:

#define DEBOUNCE 5 - this value could be anything from 1(inadvisable, not really a debounce) to infinity (also inadvisable, for obvious reasons). I'm debouncing 32 buttons with this, so I next create an array of 32-bit ints using:

static uint32_t key_integration[DEBOUNCE];

On each scan of the inputs (1KHz poll rate), I move the second-to-last item of the array to the last, the 3rd-to-last to the 2nd-to-last, etc, etc, until I finally input the raw scan of the keys into the 0th array item. (Side question: easier way to do this than just iterating a loop from 0 to DEBOUNCE-2? If I had a (32*DEBOUNCE)-bit integer, I would just use bitwise shifting, but... anyway.)

Now the tricky part with which I'm having difficulty: Comparing the array results to the current (debounced) key state. Essentially, if bit X of the key_integration int is 1 is all of the arrays, I want to XOR it with the current (debounced) key state to see if it's changed. If every bit X of the key_integration int is 0 over all the arrays, I want to the do the same. If bit X is scattered 1 and 0 accross the arrays, then it's still debouncing and doesn't need to be compared.

I'm currently confused on how to compare the key_integration array with the debounced key state int. I would really appreciate advice on how to either A) Compare them, or B) Refactor the code to accomplish the same result in a simpler way. I'm definitely not in a position to believe that what I've thought up is the best way to do it.

Helpful
  • 702
  • 4
  • 16
  • Possible duplicate of [why does my debouncer not work?](https://stackoverflow.com/questions/39987772/why-does-my-debouncer-not-work) –  Jul 29 '17 at 02:48
  • @JarrodRoberson not a duplicate, these questions have essentially nothing in common other than the general goal of debouncing. – Chris Stratton Jul 29 '17 at 16:08
  • 2
    The described technique here doesn't seem to make much sense at all. Likely you want to define state variable[s] for each key which measure the amount of time they have been down, and act on changes accordingly, if you want full behavior of down, up, and repeat events. but if you don't need to support simultaneous inputs, up and down events, and repeat then it becomes very simple, as you just detect the first key down and then accomplish debouncing by ignoring the entire keyboard for a suitable fraction of a second. – Chris Stratton Jul 29 '17 at 16:11

1 Answers1

0

You can fairly easily calculate masks of which keys have been always zero or always one, (pseudo code)

alwaysZ = -1
alwaysO = -1
for (int i = 0; i < DEBOUNCE; i++)
    alwaysZ &= ~keys[i]
    alwaysO &= keys[i]

With that it is very simple to determine which keys have stayed the same (but in either polarity): stable = alwaysZ | alwaysO

Though this requires recomputation at every polling moment, which can be avoided. Clearly the bit stable[i] would be set iff the number of times the i'th bit was set is either 0 or DEBOUNCE (maybe DEBOUNCE - 1, depending on what you define that constant to mean, but the point is it will be either 0 or "everything"). So here's an alternative: keep an array of counts, that counts for each button how many times it was found to be in the down state over the whole debounce window. Add one to each currently pressed button, subtract one from each button that was pressed DEBOUNCE steps into the past.

With the array of counts you can tell for each button whether it was stable in constant time, independent of the amount of debouncing. As a down side, you would have to explicitly check every count, whereas with the bitmask you could immediately determine whether any button was stable and then early-exit.

As for the side question, you can use the standard circular buffer technique to avoid moving the data itself, just moving it virtually by adjusting indexes. But this isn't free either, for DEBOUNCE=5 I wouldn't do that. It scales really well to huge debounce values since the overhead is constant. You can usually avoid having actual modulo operations because you're only incrementing an index (so you can increment and go back to 0 if you reached the end), not randomly indexing into the middle of the buffer.

harold
  • 61,398
  • 6
  • 86
  • 164
  • Thank you for the direction and help! I'm changing the algorithm a little bit so the buffer array bits define "Is the key in a different state than the recorded/broadcast status?" That way I can just check for all 0s before I change the "state" variable. I'll probably implement the circular buffer just for consistent performance across any debounce constant, despite the overhead. – Helpful Jul 31 '17 at 21:17