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 ?
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 ?
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:
// 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 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)
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