LCD menu w/ buttons

You can take all debounce related code out of loop and write a function for the debouncing

/*
  debounce the button
  returns: the last debounced state of the button (HIGH or LOW)
*/
byte debounceButton()
{
  // remember the last button state
  static byte lastButtonState = LOW;
  // remember the debounced state
  static byte debouncedState = LOW;
  // remember the start time of the last bounce
  static unsigned long lastDebounceTime = 0;

  // read the button
  byte reading = digitalRead(buttonPin);

  // compare; if it's not the same as lastButtonState, the button is still bouncing
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  // if the lastDebounceTime did not change for N milliseconds
  //   we assume that the button stopped bouncing
  if ((millis() - lastDebounceTime) > debounceDelay) {
    debouncedState = reading;
  }

  // remember last real state of button
  lastButtonState = reading;

  return debouncedState;
}

I have renamed buttonState to debouncedState as I find it easier to understand. The three global variables that are used in the debouncing are moved to the function (and should be removed from the global section in the beginning of the code). The other change is that the code uses bytes instead of integers for the 'state' variables saving some memory.

You need one function like above for each button that you want to debounce.

Below the framework for two buttons; I have renamed the button pins so they reflect a little more their purpose (position on the breadboard in this case).

const byte buttonPinLeft = 6;
const byte buttonPinRight = 7;

const unsigned long debounceDelay = 50;

// operation mode; should probably be moved to loop()
byte mode = 0;

// other variables (like LCD) here
...
...

void setup()
{
  Serial.begin(9600);
  pinMode(buttonPinLeft, INPUT);
  pinMode(buttonPinRight, INPUT);

  // other initialisation here
  ...
  ...
}

void loop()
{
}

/*
  debounce the left button
  returns: the last debounced state of the button (HIGH or LOW)
*/
byte debounceButtonLeft()
{
  // remember the last button state
  static byte lastButtonState = LOW;
  // remember the debounced state
  static byte debouncedState = LOW;
  // remember the start time of the last bounce
  static unsigned long lastDebounceTime = 0;

  // read the button
  byte reading = digitalRead(buttonPinLeft);

  // same as shown in debounceButton
  ...
  ...

  // remember last real state of button
  lastButtonState = reading;

  // return last debounced state
  return debouncedState;
}

/*
  debounce the right button
  returns: the last debounced state of the button (HIGH or LOW)
*/
byte debounceButtonRight()
{
  // remember the last button state
  static byte lastButtonState = LOW;
  // remember the debounced state
  static byte debouncedState = LOW;
  // remember the start time of the last bounce
  static unsigned long lastDebounceTime = 0;

  // read the button
  byte reading = digitalRead(buttonPinRight);

  // same as previous
  ...
  ...


  // remember last real state of button
  lastButtonState = reading;

  // return last debounced state
  return debouncedState;
}

Instead of digitalRead() in loop(), you can now use debounceButtonLeft and debounceButtonRight as shown below

void loop()
{
  byte leftButtonState = debounceButtonLeft();
  if (leftButtonState == HIGH)
  {
    mode++;
    if (mode > 2)
    {
      mode = 0;
    }
  }

  // do something with mode here
  ...
  ...
}

This is not a perfect solution; you can use a library for the debouncing that supports multiple buttons or write some more complicated code (relatively easy) but for this it will do.

Next post will be the state change detection.

The below loop() code demonstrates a way of implementing a state change detection. It’s basically prepared for your two buttons.

void loop()
{
  // remember the last state of both buttons
  static byte prevLeftBtnState = LOW;
  static byte prevRightBtnState = LOW;

  // debounce the buttons
  byte leftBtnState = debounceButtonLeft();
  byte rightBtnState = debounceButtonRight();

  // if there was a change for the left button (either high to low or low to high)
  if (leftBtnState != prevLeftBtnState)
  {
    // remember for next time
    prevLeftBtnState = leftBtnState;

    // if left button is pressed, update mode
    if (leftBtnState == HIGH)
    {
      mode++;
      if (mode > 2)
      {
        mode = 0;
      }
    }
  }

  // if there was a change for the right button (either high to low or low to high)
  if(rightBtnState != prevRightBtnState)
  {
    ...
    ...
  }
}

I think that it is all self-explaining. If you don’t understand it, don’t use it :wink: Ask for more explanation.