Debounce + push button as a toggle switch trouble

Hello,
I am working on my first Arduino project and could use a bit of guidance with a code issue I am having.
I have an Adafruit ESP32 Feather wired to an Adafruit 1.27" Color OLED Breakout Board.
I would like to use a simple push button to turn the screen off and on.
So I tried using code that would treat the button as a toggle switch.
So far, it can turn the screen off as long as I hold the button, but the screen comes back on when I let go.
(the code also toggles the onboard LED, just as a backup way to verify the button press. I also have bits of code to debounce the button).

// Screen dimensions
#define SCREEN_WIDTH  128
#define SCREEN_HEIGHT 96 // Change this to 96 for 1.27" OLED.

// You can use any (4 or) 5 pins 
#define SCLK_PIN 5
#define MOSI_PIN 18
#define DC_PIN   19
#define CS_PIN   17
#define RST_PIN  16

// Color definitions
#define BLACK           0x0000
#define BLUE            0x001F
#define RED             0xF800
#define GREEN           0x07E0
#define CYAN            0x07FF
#define MAGENTA         0xF81F
#define YELLOW          0xFFE0  
#define WHITE           0xFFFF

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1351.h>
#include <SPI.h>
//#include <FreeSans18pt7b.h>


const int buttonPin = 22;
const int ledPin = 13;
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin


// Option 1: use any pins but a little slower
Adafruit_SSD1351 tft = Adafruit_SSD1351(SCREEN_WIDTH, SCREEN_HEIGHT, CS_PIN, DC_PIN, MOSI_PIN, SCLK_PIN, RST_PIN);


float p = 3.1415926;

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 200;    // the debounce time; increase if the output flickers

void setup(void) {
  Serial.begin(9600);
  Serial.print("hello!");
  tft.begin();

  Serial.println("init");
//void fillScreen(uint16_t color=BLACK);
tft.fillRect(0, 0, 128, 128, BLACK);
//delay(100);
//tft.fillRect(10, 10, 118, 86, RED);
delay(500);
tft.setCursor(10, 30);
tft.setTextColor(WHITE);
tft.setTextSize(4);
tft.println("LOW");
tft.setCursor(20, 65);
tft.setTextSize(2);
tft.println("mmol/L");

  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  // set initial LED state
  digitalWrite(ledPin, ledState);
  
}

void loop() {
  // put your main code here, to run repeatedly:

    // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        ledState = !ledState;
        Serial.write("Button");
      }
    }
  }

  // set the LED:
  digitalWrite(ledPin, ledState);

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;
}

If you scan your switches every ~50ms and then look for a change in state, your switch detection code should work solidly.

How is your button wired. Do you have a pull down resistor? Your logic is set for pressed = HIGH.

More common is to use INPUT_PULLUP for pinMode, and wire the switch so it is connecting the input to ground when it is pressed. Pressed will read LOW and not pressed HIGH.

How are you turning the display on and off?
Does the led toggle correctly with your code?

My button is wired to pin 22 and ground. I am not using a resistor. I didn't think I needed one based on something I read about arduino boards having a built in resistor... and now realize that might only mean "arduino" branded boards... and not this Feather... I'll look into that now.
With the code as-is, pressing the button turns off the display for a second, and then it comes back on. If I hold the button, the screen stays off. The LED turns on briefly when I let go of the button.

I tried changing pinMode from INPUT to INPUT_PULLUP but that didn't change the behavior of the button press.

Try a simple digitalRead() test sketch with the button and a pin set as INPUT_PULLUP. If the button is wired correctly then you should read HIGH when not pressed and LOW when pressed.

Wire diagonally across the button to pick up switched legs.

So I think I had a couple things wrong, but your comment helped me fix that.
First, I was using a pin on the Feather that did not have an internal resistor. I think there's only one that doesn't have the resistor, and that's the one I randomly chose.
And the button was wired as if I was using an external resistor, so it was shorting the board.
So now I have a button wired like the diagram, on a pin with the internal resistor... and it works.
At least, the LED stays off or on. Now I will try to make the screen stay on or off too.
Thanks!

If I may make a suggestion - why not just use a toggle switch connected in the supply to the display?

so, you can use a very weak pull-down resistor, extremely weak like 1 megaohm or more, and then turn on the internal pullup.... the internal will overcome the pull-down and prevent the button from turning off the unit on it's own, but when you go into your turn off sequence, you can disable the pull-up, and the pull-down will keep the latch until the power dissipates fully.

This project will be a "mock" glucometer for medical simulation.
With a real glucometer, the user would insert a test strip in the bottom of the unit, the device analyzes the blood and returns a value.
I want to be able to set a value and turn off the screen.
Then, when the learner goes through the motions and inserts a test strip in the housing I will design, it will push that button inside that will turn the screen back on, revealing the value.

So, if I understand correctly, you want a momentary switch that turns the unit on and off?

No reason why you can not use a lever operated microswitch.

If you MUST use a sensor then an opto switch would perhaps be suitable

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