Hi, need a little design help. I have 3 buttons, Select, Up, Down. I have 3 config bytes, ranged 0 to 100.
While running, if Select is pushed, the app will need to allow the user which variable to edit. If Up or Down is pushed, whatever the current variable is selected will be incremented or decremented.
Maybe writing this question makes it more clear for me...
#include <EEPROM.h>
#define BUTTON_SELECT 51
#define BUTTON_UP 52
#define BUTTON_DOWN 53
#define NUMCONFIG 3
int8_t config[NUMCONFIG] = {50, 50, 50}; // Initialize all config bytes to 50
uint8_t v = 0;
void setup() {
Serial.begin(9600);
pinMode(BUTTON_SELECT, INPUT_PULLUP);
pinMode(BUTTON_UP, INPUT_PULLUP);
pinMode(BUTTON_DOWN, INPUT_PULLUP);
// Read config values from EEPROM
for (int i = 0; i < NUMCONFIG; i++) {
config[i] = EEPROM.read(i);
if (config[i] > 100 || config[i] < 0) config[i] = 50; // Ensure valid range
}
}
bool selectButton() {
return digitalRead(BUTTON_SELECT) == LOW;
}
bool upButton() {
return digitalRead(BUTTON_UP) == LOW;
}
bool downButton() {
return digitalRead(BUTTON_DOWN) == LOW;
}
void loop() {
if (selectButton()) {
// Save to EEPROM if the current configuration value has changed
if (EEPROM.read(v) != config[v]) {
EEPROM.write(v, config[v]);
}
v++; // Increment the selection index
if (v >= NUMCONFIG) v = 0; // Reset to 0 if it exceeds the number of config variables
while (selectButton()) {} // Wait until the button is released
delay(100); // Debounce delay
} else if (upButton()) {
if (++config[v] > 100) config[v] = 100;
//while (upButton()) {} // Wait until the button is released
delay(100); // Debounce delay
} else if (downButton()) {
if (config[v] >0) config[v]--;
//while (downButton()) {} // Wait until the button is released
delay(100); // Debounce delay
}
// For debugging purposes, print the current variable and its value
Serial.print("Config[");
Serial.print(v);
Serial.print("] = ");
Serial.println(config[v]);
delay(100); // Loop delay to prevent bouncing issues
}
I'm thinking that up and down buttons, do not need a forced finger lift?
Also thinking that since the buttons are only configuration, perhaps delay the regular loop activity for 2 seconds in case the user is not done setting stuff up? Or maybe if a user pushes up or down, they must push select in order to resume? Mmm...
Your code now does the button handling in a crude manner that does require a certain way of pressing.
This would sing better if you implemented state change detection and proper debouncing, then switch actions would be one per press, no matter if it was I or my mother doing the pressing.
It would not keep you from doing something more, like observing independently that a button is being held and the current selected value shoukd begin to change automatically and maybe even speed up as it does. I am sure you have used annoying button UI things like that, they work.
See this thread
or use a button library. ezButton (small e small z big Button) gets my highest praise, it doesn't suck, and is in fact very easy to use.
Thanks for the tips. I have my sans-interrupt driven button logic working good enough. I intentionally didn't want to use interrupts as I am monitoring traffic with interrupts where it puts results in a ring buffer.
For more complex input, the ezButton would definitely be the way to go. My simple logic could easily miss events. But from using it, I have yet to be annoyed.
TBH, if I would have known about that earlier, I would have simply used it. Something I'll use for future projects.
@jim-p the up and down buttons are simply held to increment or decrement config settings at 10 per second. In the actual code, there is a LCD display to give feedback. I haven't found it annoying that there isn't a key buffer. If someone would tap the buttons, there could be lost "events" but in practice, I haven't found it annoying.
I use it. I use my own even easier sucks less than "doesn't" and the nice thing about my own is that I know what it is doing.
There may be value in rolling your own button handler at some point. Not that it hasn't been done, or that there is any real reason to.
But it does inevitably drag you over some very basic problems that are solved with some widely applicable techniques.
Debouncing and state change detection show up in disguise in quite a few problems areas; some would actually be amenable to being solved with a good button library, but many more are just enough different that it would be the skillz you honed having done your own deep look into the two concepts that would let you quickly design a similar solution.
Button handling is a nice exercise, the step after total understanding and mastery of the "blink without delay" idiomatic pattern.
@alto777 indeed, I've made many games that rely on polling the keyboard and I find them more responsive when not using a key buffer. (IBM PC MSDOS and TI-85 z80 games.)
If my project grows to require finer inputs, ezButton is in my back pocket.