Beginner needs help with debounce logic

From an OO perspective, a button is an objet user can understand - so it makes sense to create a class for it. a button can report its sate individually.

What you propose is to create a class for a group of pins to which buttons are attached so that you can group the polling into the class and you return only one button even if multiple were pressed at the same time.

From an OO perspective I don't see it.... it's not an object I have in mind.

From a programing perspective, you also check all the buttons at once, even if you don't need to update some buttons which is not needed in some cases (Say you have a mobile on a rail, when you move forward you want to only check the limit switch that is at the end of the rail and if you move backward, you only want to check the one that is at the start).

If you really want one function to poll buttons and not have a loop in your main code (hide the loop that goes through all the buttons inside the class), a typical trick to not have dynamic allocation of a container is to organize a linked list of instances as you create them and have a class function that goes through the link list

here is an example

class Car {
public:
  Car(const char* n) : name(n), next(head) { head = this; }
  static void printAll() {
    for (const Car* c = head; c != nullptr; c = c->next) Serial.println(c->name);
  }
private:
  const char* name;
  Car* next;
  static Car* head;
};

Car* Car::head = nullptr;

Car myCars[] = { "Ferrari", "Porsche", "Rolls-Royce" };

void setup() {
  Serial.begin(115200);
  Car::printAll(); 
}
void loop() {}


how would you handle a 4x4 matrix or keyboard, as separate buttons? isn't a matrix an object?

:+1:

You would need to define a bit more the exact behavior you want to see (describe the ramp) and is there a cap to the "acceleration" ?

The “acceleration” rate is subjective and difficult for me to describe.

It’s better to describe the end goal: to rapidly traverse a count of (absolute worst case) half a million counts in a reasonably short amount of time (thirty seconds or so would be good; sixty seconds would still be acceptable) yet be able to stop the rapidly changing count at or near the desired value. The user might overshoot the target, that’s ok because we can go up or down, and it wraps through zero. For example if you have an existing count of 800,000 and you want to set it to 80,000 you would go up. Then, press and hold the appropriate button again to get a little closer, repeat as required.

So there is a rate cap, and it’s chosen to be appropriate for the count range (zero to a million or so). I imposed a reasonable limit — see my “limit max delta” comment in the code.

Think about setting a digital clock, except they’re easier since they only have a “count” value of so many minutes in a day.

It would also be perfectly ok to implement an “accel” function that changes the ones digit at a fixed rate, followed by changing the tens digit at the same rate, followed by changing the hundreds digit at the same rate, and so forth. The less significant digits can even be blanked or have dashes to indicate they’re not important when the user wants to change the count a few thousand at a time.

Having said all that… @ec2021 ‘s “accel” algorithm as adapted in the Wokwi simulation in post #38 above is nearly perfect. Load it and it illustrates what I want better than I just described it.

Oh and one more thing that I mentioned only once before — neither one of those buttons (inputs) represents the actual mechanical counter input. That will be a separate input, which ought to be trivial to add even for me :grinning_face_with_smiling_eyes:

Fair question

I can see a matrix as an object too - esp if reading the buttons involves Understanding the full grid layout

Your class is not about that though

Thanks for that explanation. I tried to use snprintf in the past but gave up. Your explanation cleared things up for me.

That plus some insignificant edits:

Shorter and a little more concise.

Can’t get the onboard LED to behave with @gcjr ‘s much more elegant code though. Still learning.

it handles buttons. I don't see a benefit for handling buttons individually. after a 5 buttons, it's more efficient to handle them as a matrix. would you prefer to have different interface to handle buttons in a matrix and not in a matrix.

Certainly if the matrix was implement as a Row / Column scan kind of thing where you drive the rows with a GPIO output and read the columns with a GPIO input (or vice versa).

A keypad / button matrix is different than a momentary button both from a user or wiring perspective. You commonly find the keypad class for a matrix and a there are countless button libraries.

If you want to deal with a collection of something in an OO way, you use containers generally.

It depends on your code and what buttons are for. If handling the press or release events for each of them is always relevant, a class function like I showed can do that without having to maintain a specifically allocated dynamic container . At the end of the day you have somewhere a loop going through the pins.

1 Like

but funcitonally a button is a button. why should the class depend on the hardware?

it seems there are right/wrong ways to implement classes, depending on hardware and use, which i find discouraging, are object really that obvious.

rather than seeing different approaches

you made no comments with by non-class implementation, only when i implementated that approach in a class.

should the cookbook present a # of different implementations

1 Like

I think it's more fine grain than this question. There are no obligations as long as the intent is clear to the software programmer.

A keypad is not a button, it's multiple buttons wired in a specific way. So they appear differently to the person building the hardware. You wire a 16 button keypad in a different way than you would wire 16 individual buttons or 16 buttons with a resistor ladder.

You could choose to see those as a group of buttons and create a generic class that will adjust to the layout and offer a uniform interface to handle the events on the buttons. That's possible indeed but the programmer will have to provide in some way the type of layout upon definition of the group.

a 4x4 matrix will need 8 pins in the constructor and you'll distinguish rows and columns.
16 individual buttons will require 16 pins in the constructor
16 buttons on a resistor ladder will require only one pin but with ADC capabilities

➜ the programmer has to be aware of what's physically attached to the Hardware.

The code for handling detection will then be different for each case, even if the class presents a uniform API.

So I think from a developper perspective it feels simpler to have 3 classes that are specialized for the hardware you have. That's why you see a Keypad library and a button library etc.... The API can also be tailored to common usage. You might want to offer double click or triple click on a single button API whereas it's not so common to see that use case on a keypad.

1 Like

you seem to be arguing right/wrong, matrix vs buttons vs button.

no. you missed my earlier point. 16 individually located buttons requires just 8 pins. they don't need to be arranged in a matrix. A row/col matrix is a method for handling many buttons. It's not necessarily a grid

1 Like

I think we are getting lost in what we mean

16 individually located buttons requires just 8 pins if they are wired as a matrix, even if physically they are not arranged as a matrix. You'll need diodes if you want to safely detect multiple buttons being held down at the same time etc...

You could decide to wire 16 individually located buttons with 16 pins (each their own INPUT_PULLUP pin) and be done with it.

Or as I said you could decide to use a resistor ladder and have only 1 analog pin to read the state given a good ADC/

➜ it's a hardware design decision, the programmer will need to adjust to what has been done.

1 Like

your discussion of use of diodes and resistors is irrelavent.

guess you strongly believe hardware implementaion dictates the class functions (not implementation) ... again right/wrong instead of different approach

1 Like

it is somewhat - I'm just trying to express that there is a given hardware situation with a fixed wiring that the software programmer needs to know about.

➜ You can't write a generic class that will adjust automagically to whatever is connected.
➜ You can't write a generic API that can reliably notify of simultaneous multiple button press in the matrix case unless you have diodes.

The point I'm trying to make is that wether you have one generic class that adjusts to all the possible layouts and capabilities or 3 dedicated classes is a software development decision but the programer will have to provide the details of the wiring in any case. If you have 3 Classes, the developer specifies the type of wiring by picking the right class (keypad, button, resistance ladder), if you have a generic class, that class will need a way to express which type of layout is used.

The decision to write a single class or multiple class is a coding decision, both probably have merit. I'm saying that I see more merit into 3 distinct classes than one class.

aren't you arguing that there should be a Button, not Buttons class and that a matrix is a separate case.

the hardware is irrelavent.

I'm saying that given what is in my drawers and I see out there in projects, a Keypad class, a Button Class and a ButtonLadder (or whatever name) class make a lot of sense to me. When coding for a project, I pick the class that matches the hardware.

I've yet to come across a unified class with a meaningful API that would cover all those cases (if this is what you mean by a Buttons (with an s) class. I don't know of any and I don't feel inclined to develop one as I don't see its merit against the 3 class approach.

Even if you want a single class to handle an arbitrary number of buttons like @gcjr's code, there's no need to use dynamic allocation. Since the number of buttons is known at compile time, a templated class would be the way to go.

i wasn't advocating a common class

i am advocating a Buttons not Button class. You seem strongly opposed to a Buttons class because you strongly see a Button being "the" object.

Don’t want to get in the middle of your gentlemanly discussion but it is helping me appreciate the valid points you’re bringing up.

I did not originally discuss the addition of the “prox switch” I added in the latest Wokwi (see above) but the value of a button class is becoming apparent. As the code evolves, there will be the need to add a specific function when it transitions from one state to another. That’s in addition to the obvious requirement of incrementing the count value (as opposed to presetting a starting value).

That code hasn’t been implemented yet, but if I understand you correctly, the button class will simplify that addition. It’s just another button to add to the class. Is my understanding correct?

Let me ask differently : what's the API going to be and with what type of wiring does it deal with? (ie are you reinventing the keypad library ?)