Button reading philosophy

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...

Why assign a button value, just digitalRead button 1,2 or3.

I don't understand, can you clarify the question?

Button up/down are actually increment and decrement buttons.

What is the task of the sketch in real life?

do you mean the Select will activate the up / down for one of the 3 values you want to change?
Each push on Select will activate the "next" value?

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.

a7

1 Like

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.

How was that accomplished?

The ezButton library does look very nice. GitHub - ArduinoGetStarted/button: Button library supports debounce, pressed/released events. It is easy to use with multiple buttons. It is designed for not only beginners but also experienced users

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.

HTH. Good luck!

a7

@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. :wink:

Really appreciate the insights.

Thank you all

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.