Beginner needs help with debounce logic

You handle that typically in the state machine.

Here is a small introduction to the topic: Yet another Finite State Machine introduction - might be of interest ?

1 Like

If it's not absolutely necessary to use pushbutton type switches a rotary encoder could also work for you. This one

handles debouncing AND includes an acceleration capability.

Here's an example of the acceleration feature:

1 Like
    // check for button press, adjust count
    switch (buts.getBut ())  {
    case 0:
        counter += Increment;
        break;

    case 1:
        counter -= Increment;
        break;
    }

in this case, just a buttons wired individually to pins

how do you handle both buttons pressed ?

in my example I had

  if (plus) counter++;
  if (minus) counter--;

but I could (probably) do (with a bit of modification to return the state rather than the one time action)

  if (plus && minus) counter = 0; // reset

I may ultimately abandon the effort to adapt the prox switch input to the button class since the “accel” feature will not apply to it, but before I do that I wonder if there is some way I can make it work.

I’ll insert some code snippets here to illustrate how I added that input (not shown in the existing wokwi).

The first change was to assign the prox sw input. I surmised that the up / down buttons (connected to inputs 3 and 4 respectively) are assigned in that order:

constexpr byte buttonPin[] {3, 4, 2};

So far so good, the up / down button operation remained unaffected by that change.

  • The prox switch is connected to digital pin 2, so 2 needs to be third one in the ordered list, correct?

The next change was necessary to omit the prox sw from the little “array” of two buttons, so I commented out the init assignment for-next code and added them explicitly instead:

    // the following button[i].init procedure ONLY applies to buttons that you want to repeat
// otherwise apply the idea only to specific buttons 
// as shown immediately below these commented lines
// for (int i = 0; i < buttons; i++) {
//      Pin No, minInterval, maxInterval, decrement
// button[i].init(buttonPin[i], 50, 400, 100);
// }


    button[0].init(buttonPin[0], 50, 400, 100);
    button[1].init(buttonPin[1], 50, 400, 100);

Again, so far so good. Those two buttons do exactly what they have been doing.

But as you can see I boxed myself into a corner because I need to perform the equivalent init for the remaining “button” — the one assigned to the prox sw input.

It would be something like

button[2].init(buttonPin[2] ... but now what?

As it is now that prox button has no function. Everything else works though.

Should I abandon the attempt, omit it from the button class, and handle it as a separate routine?

Corollary question: Can the accel button class parameters be set or changed so it does nothing when held down, other than to register a button press and a button release?

@dougp thanks. I will have a look at that code. Much appreciated.

The counter is indeed for a machine that requires maintenance at certain intervals, and the ability to preset a counter is needed because certain machine cycles (cycles that do not affect maintenance) may be counted accidentally. In those cases the operator wants to reset it to a proper, valid count. Ironically that need will be seldom, but it has to be an option.

I love rotary encoders but the requirement for a simple up / down toggle switch is a design constraint I have to live with.

I may ultimately abandon the effort to adapt the prox switch input to the button class since the “accel” feature will not apply to it, but before I do that I wonder if there is some way I can make it work.

Breakthrough! I think you’re laughing at me but that’s ok:

    // the following button[i].init procedure ONLY applies to buttons that you want to repeat
// otherwise apply the idea only to specific buttons 
// as shown immediately below these commented lines
// for (int i = 0; i < buttons; i++) {
//      Pin No, minInterval, maxInterval, decrement
// button[i].init(buttonPin[i], 50, 400, 100);
// }


    button[0].init(buttonPin[0], 50, 400, 100);
    button[1].init(buttonPin[1], 50, 400, 100);
    button[2].init(buttonPin[2], 50, 400, 0);

Simple as that. The minInterval, maxInterval values can obviously be modified too.

Wokwi updated. It’s nearing completion. Tell me what you think!

when the first button is pressed, it returns the button index and starts the debounce timer, When the timer expires is recognizes that the 2nd button is pressed and returns its index.

You know, I just realized there are in fact four “buttons” in the mature design. The one I had not considered was the count / don’t count toggle switch. It would be advantageous to add that switch to the “button” class because I need to do certain things upon a state transition — namely, write the present count value to EEPROM, regardless if that value was the result of presetting the counter or a normal increment via the prox switch. The button class should be able to handle that easily.

I’d welcome thoughts about just when to write to EEPROM, knowing it has a finite write cycle limit.

What processor? The datasheet for the UNO chip EEPROM gives 100,000 writes per location, minimum. Do you anticipate that many changes over the life of the device?

With a wear-leveling algorithm you can extend that manyfold.

There's already a function in the button class that reacts on a state change from open to closed: You can call it for any of the buttons like

if (button[0].pressed()){
 // Do something 
}

You can create a further button where you use .pressed() instead of .down() that will only return true once for a state change when pressed. You have to release it before it will return true again. The acceleration parameters do not affect the pressed() function.

BTW: If pin and increment are the only parameters that change you could create another const array for the latter and init the buttons in a for-loop ...

For maximum flexibility you could create an array of size [buttonNumber][parameterNo] where each entry covers pin number, minInterval, maxInterval and increment value and use the appropriate entry in the for-loop.

buttonNo = number of buttons to be defined
parameterNo = 4

Good luck!
ec2021

I get that - your function still returns one button’s status. If your class is about buttons (with an s) may be it should return an array with all the states updated? That would be more coherent maybe ?

the user would now need to loop thru the array to check which, if any button was pressed.

what are you trying to say with "coherent"? what are ou striving for?

i don't understand your preference for
Isn't theis better than

if (button0.pressed() {
}
if (button1.pressed() {
}
if (button2.pressed() {
}
...

it depends what you want to do.

how do you know if two buttons got pressed since the last check without having to wait for a whole debounce delay and possibly hundreds spins of the loop?

if your function was returning an array with the latest stable status, you could do

if (buts.getButs()[0] == PRESSED {...}
if (buts.getButs()[1] == PRESSED {...}
if (buts.getButs()[2] == PRESSED {...}

and have a true representation of the state of the buttons at a given point in time, not an arbitrary partial snapshot based on the order in which the buttons were defined.

I guess it's personal preference.

(we are polluting this thread with our side conversation, so I'll stop here. May be we can have a discussion separately on how to pick a OO design for buttons - although I think we both stated our views)

  • explain to me how a person could press 2 buttons synchronously within a debounce period of ~30ms and
  • why it would be necessary to recognize that specific case instead of just within a period of ~100ms?

If you are fine with the limitation, then it's a design decision. that's fine.

Say you have a whack a mole game with two players each trying to hit their moles. in the same check you want to know if both players got a hit (it's a tie) or if only one managed to hit the mole (win).

You could do that with two instances of your Buttons class of course but does that defeats the initial purpose of grouping the buttons ?

If I had to design for this I would have a button class - each button has its own "life" and if you want to hide from the main code the group of buttons then you could have a class grouping those instances.

just for the record : I'm not saying your approach has no merit, I'm just saying that for practical purposes and flexible use I would not design it this way.

how is it a limitiation if it's next to impossible to expect a person to press 2 buttons within a debounce period? (this applies to buttons)

again this a human response time issue that i doubt requires such accuracy. Considering the the buttons are checked within ~100usec,

for something involving non-human input, a different approach might be necessary. If it were really necessary to check for multiple inputs becoming simultaneously active, you could return a bit map indicating which input became active simlutaneously (similar, but not really the same as your array suggestion)

    switch (buts.getBut ())  {
    case 1<<0:
        something1 ();
        break;

    case 1<<1:                   // bit 2
        something2 ();
        break;

    case 1<<2:
        something4 ();
        break;

    case 6:                     // 2 inputs active simultaneousdly
        something6 ();
        break;
    }

the above is just anothet example of a more specific need requiing more sophisticated code, similar to using a non-blocking timer to debounce buttons instead of a simple delay.

message me if you want, but i discussion is still somewhat relavent to the thread

What about two people or ten fingers on a piano? it's definitely possible and saying it's not implemented because likely not useful is a limiting factor.

In a whack a mole game with 2 players, for example as discussed here

if you have only one group for all the buttons and if you favor user 1 versus user 2 by checking him first, you are twisting the odds of winning.

(As I said, you could solve that with two buttons groups)

Anyway, I'm not trying to convince you. It's OK if we disagree.

My design would be a Button class and then using a container / array to group the buttons. If I need to abstract the group because the group has also some OO meaning, then I would consider a class for the group.

pretty sure electronic 88 key keyboards are wired as at least a 10x9 matix.

again, how accurate does it need to be?

i suggested an approach by reading the state of all inputs and returning a bitmap.

but bear in mind there are still a few microseconds between checking one pin and the next, so what is the required accuracy?

If you really need to be accurate, you would wire multiple inputs to the same hardware port and read the port, not individual pins. The response can be the same, a single function call returning a bitmap.

you seem pretty sure of what an object is or should be and of one approach, individual instances of a Button class, despite the extra processing of checking a timer for each button.

i've suggested different implementations depending on requirements but that all can be a single instance of a class that requires a single call to obtain results.

as i initially posted, a class isn't needed.

this discussion arose when i implented my code as a class and what an object is.

I missed that - I thought that's what I suggested.

yes, I agree there is a cost and a benefit to it (check only the buttons you want when you want it etc)

Anyway I leave it there — we have hijacked this thread too much