Problem debouncing multiple buttons

I'm trying to program a menu system into my project and I need to debounce multiple buttons. I tried modifying the debounce function to receive a pin number and debounce that pin, but for whatever reason it wouldn't debounce more than one button, now i tried making a separate debounce function for each button and calling each one and it works. The problem is the buttons aren't very responsive and there is a delay before I can press the button again or a different button quickly. Is there a problem with my code getting delayed or is the program at a different spot when a another button is pressed. I don't know if I should go back and make a combined debounce function that receives a pin or if I can fix this. I can't post the code here since its too big. So i uploaded the file for everyone to see. Thank you in advance for any responses.

menu_buttons_debouce_forum.ino (16.1 KB)

Here is my attempt to make a debounce function that receives a pin number. It works when its called once if its called again neither button works.

const int buttonPin6 = 6; // the number of the pushbutton pin
const int buttonPin7 = 7; // the number of the pushbutton pin
const int buttonPin8 = 8; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin

int buttonState; // the current reading from the input pin
int lastButtonState=HIGH; // the previous reading from the input pin
long lastDebounceTime = 0; // the last time the output pin was toggled
int ledState=LOW; // the current state of the output pin
long debounceDelay = 50; // the debounce time; increase if the output flickers

void setup() {
pinMode(buttonPin6, INPUT);
pinMode(buttonPin7, INPUT);
pinMode(buttonPin8, INPUT);
pinMode(ledPin, OUTPUT);
}

void loop()
{
debounce(buttonPin8);
debounce(buttonPin9);

}

int debounce(int buttonPin)
{
int reading = digitalRead(buttonPin);
if (reading != lastButtonState)
{lastDebounceTime = millis();}

if ((millis() - lastDebounceTime) > debounceDelay)
{
if (reading != buttonState)
{
buttonState = reading;

if (buttonState == LOW)
{
ledState = !ledState;
}
}
}

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

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

indiYou only have a single lastDebounceTime variable. You need one for each button. You also need a previousState for each button, and a buttonState variable for each individual button.

In my first post I have a variable for each debounce function for each pin.

I've done some more testing and i figured out that i have to hold the button down longer for debounce to notice it. I tried changing debouncedelay down and up and it doesn't affect it.

I also tried putting debounce call functions in a switch case but the same thing happens.

sketch_feb27a.ino (15.5 KB)

You have to use arrays to hold everything, button pins, last states and previous times. Have a counter based on the number of buttons you have ie 2. Use an IF statement to increment the counter if it is less then the number of buttons, and reset counter to 0 if it goes over the number of buttons.

You can use the same debounce sketch you have for the one button, but now make everything arrays.

So I put all the variables for debounce into arrays along with any other variables I have that have similar functions. I only have one debounce function that gets sent a pin and it debounces that pin and it works and sees all the pins and I'm able to display it on my GLCD and the LED pin 13 lights up when I press it the buttons, BUT the response time is very slow for the buttons and I still have to keep the button pushed down an second for two for it to read. I think there is something wrong with the way i'm testing the debounce pins. Because its the same if there is separate functions for if the variables are in arrays or not. I think the code is lagging behind as it makes each look to test the buttons, so it i press a button normally it might not be in the section of the loop that's testing that button. Do i need to setup interrupts or change the for/switch setup for debounce? I posted my so that you can see it. I posted the file of my and the code itself (I hope it doesn't look too awkward in the forum or break any forum rules.) Thanks in advance for any responses.

/00000000 Libraries included 00000000/

#include <SerialGraphicLCD.h>
#include <SoftwareSerial.h>

/00000000 GLCD screen size 00000000/

#define maxX 127//159
#define maxY 63 //127

/00000000 variables for PINS 00000000/

//Bup Bdown Bleft Bright Bcenter But1 But2 But3
const int buttonPin[8]={4,5,6,7,8,9,10,11};
const int ledPin13 = 13; // the number of the LED pin

/00000000 variables for debounce 00000000/

//Bup Bdown Bleft Bright Bcenter But1 But2 But3
int buttonNumber[8]={0,1,2,3,4,5,6,7};
int buttonState[8];
int lastButtonState[8]={HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH};
long lastDebounceTime[8];
long debounceDelay[8]={10,10,10,10,10,10,10,10};
int reading[8];
int ledState=LOW; // the current state of the output pin

/00000000 buttonlook variables for buttons 00000000/

int buttonlook[8]={0,0,0,0,0,0,0,0}; //variables to store if button is pressed for pin10

/00000000 variables for menus 00000000/

int menustack[6]={1,0,0,0,0,0}; //array acting as stack for menu porder when hopping from one menu to the other.
// set array size to number of menus desired
int currentmenuspot=1;
int prevmenuspot=1;
int menustackspot=0;
int menunumber;

int menupage=0; //0=Mainmenu 1=AirQ 2=TEMP 3=HEART 4=MORE
int optionrow[4][4]={{11,12,13,14},{21,22,23,24},{31,32,33,34},{41,42,43,44}}; //2D array as a map for menu options
int optionspotx=0;
int optionspoty=0;

int enterbuttons[4]={0,0,0,0}; //debounce puts a 1 to be later tested if button was pressed 1=pressed 0=not pressed

/00000000 LCD class declaration 00000000/
LCD LCD;
/00000000 SETUP 00000000/

void setup()
{
pinMode(buttonPin[0], INPUT); //button on pin 4
pinMode(buttonPin[1], INPUT); //button on pin 5
pinMode(buttonPin[2], INPUT); //button on pin 6
pinMode(buttonPin[3], INPUT); //button on pin 7
pinMode(buttonPin[4], INPUT); //button on pin 8
pinMode(buttonPin[5], INPUT); //button on pin 9
pinMode(buttonPin[6], INPUT); //button on pin 10
pinMode(buttonPin[7], INPUT); //button on pin 11

pinMode(ledPin13, OUTPUT); // pin 13 on board LED
LCD.setBacklight(20);
LCD.clearScreen();

LCD.setHome();
LCD.printStr(" Program starts in "); //displays "program is starting in 10/9/8 etc"

for(int i = 5; i >= 0; i--) //splash screen
{
LCD.setX(113);
LCD.setY(0);
LCD.printNum(i);
delay(500);
}
LCD.clearScreen();
delay(500);
}

/00000000 LOOP 00000000/

void loop()
{

selectmove(); //retrieves states of buttons to see if they were pressed
optionrowdisplay(); //display if buttons were pressed

}

/00000000 displays when buttons are pressed 00000000/

void optionrowdisplay()
{
LCD.setHome();
LCD.printStr("x spot ");
delay(50);
LCD.setX(50);
LCD.setY(00);
LCD.printNum(optionspotx);
delay(50);

LCD.setX(0);
LCD.setY(9);
LCD.printStr("y spot ");
delay(50);
LCD.setX(50);
LCD.setY(9);
LCD.printNum(optionspoty);
delay(50);

LCD.setX(0);
LCD.setY(18);
LCD.printStr("center but ");
delay(50);
LCD.setX(70);
LCD.setY(18);
LCD.printNum(enterbuttons[1]);
delay(50);

LCD.setX(0);
LCD.setY(27);
LCD.printStr("button 1 ");
delay(50);
LCD.setX(70);
LCD.setY(27);
LCD.printNum(enterbuttons[0]);
delay(50);

}

void selectmove()
{

for(int i=0; i<8; i++)
{
cleardebounce(); //clears debounces variables
debounce(buttonNumber*); //debounces input pins*
if(buttonlook*==1) //loops through all the pins*
{
* switch(i)*
* {*
* case 0: //action for when Bup button is pressed*
* if(optionspoty!=3)*
* {*
* optionspoty=optionspoty+1;*
* }*
* break;*
* case 1: //action for when Bdown button is pressed*
* if(optionspoty!=0)*
* {*
* optionspoty=optionspoty-1; *
* }*
* break;*

* case 2: //action for when Bleft button is pressed*
* if(optionspotx!=0)*
* {*
* optionspotx=optionspotx-1;*
* }*
* break;*

* case 3: //action for when Bright button is pressed*
* if(optionspotx!=3)*
* {*
* optionspotx=optionspotx+1;*
* }*
* break;*

* case 4: //action for when Bcenter button is pressed*
* enterbuttons[0]=1;*
* break;*

* case 5: //action for when But1 button is pressed*
* enterbuttons[1]=1;*
* break;*

* case 6: //action for when But2 button is pressed*
* enterbuttons[2]=1;*
* break;*

* case 7: //action for when But3 button is pressed*
* enterbuttons[3]=1;*
* break;*

* }*
}
}
}
/00000000 debounce functions 00000000/
void cleardebounce() //clears variables so that they may be retested. Must be called before each debounce.
{
* for(int i=0; i<7; i++)*
* {*
_ buttonlook*=0;
}*_

* for(int i=0; i<3; i++)*
* {*
_ enterbuttons*=0;
}
}
/00000000 debounce 00000000/
int debounce(int buttonNumber) //recieves a pin and debounces that pin
{
reading[buttonNumber] = digitalRead(buttonPin[buttonNumber]);
if (reading[buttonNumber] != lastButtonState[buttonNumber])
{lastDebounceTime[buttonNumber] = millis();}*_

* if ((millis() - lastDebounceTime[buttonNumber]) > debounceDelay[buttonNumber])*
* {*
* if (reading[buttonNumber] != buttonState[buttonNumber])*
* {*
* buttonState[buttonNumber] = reading[buttonNumber];*
* if (buttonState[buttonNumber] == LOW)*
* {*
* ledState = !ledState;*
* buttonlook[buttonNumber]=1; //changes variable to 1 to be later tested if true*
* }*
* }*
* }*

* // set the LED:*
* digitalWrite(ledPin13, ledState);// lights the LED so you know button was pressed*
* // save the reading. Next time through the loop,*
* // it'll be the lastButtonState:*
* lastButtonState[buttonNumber] = reading[buttonNumber];*
}
GLCD_first_demo_v7.ino (5.78 KB)

Those delay even though they are small, they will slow the code down incorrectly. Look into the Blink without Delay sketch to replace those delays.

As for the debounce code.

/* 
 Debounce
 This example code is in the public domain.
 http://www.arduino.cc/en/Tutorial/Debounce
 */

// constants won't change. They're used here to 
// set pin numbers:
const byte MAX_PINS = 4; // how many buttons to look for
const byte buttonPin[MAX_PINS] = {A0,A1,A2,A3}; // Number of buttons
const byte ledPins[MAX_PINS] = {13,12,11,10}; // the number of the LEDs
const long debounceDelay = 50; // the debounce time; increase if the output flickers

byte counter=0;
boolean currentState[MAX_PINS]; // Initial storage for the state of the button
boolean buttonState[MAX_PINS]; // the current state from the input pin
boolean lastButtonState[MAX_PINS] = {LOW,LOW,LOW,LOW}; // the previous state from the input pin
long lastDebounceTime[MAX_PINS] = {0,0,0,0}; // the last time the output pin was toggled

void setup() 
{
  for(byte i = 0; i <= MAX_PINS; i++)
  {
    pinMode(buttonPin[i], INPUT); //set button states
    pinMode(ledPins[i], OUTPUT); // set LED states
  }
}

void loop() 
{
  counter < MAX_PINS? counter++ : counter = 0;

  currentState[counter] = digitalRead(buttonPin[counter]);// look at button input and record it.
  
  if (currentState[counter] != lastButtonState[counter]) // Check to see if the state has changed, indicating button is not held
    lastDebounceTime[counter] = millis(); 

  if ((millis() - lastDebounceTime[counter]) > debounceDelay) // check debounce time
    buttonState[counter] = currentState[counter];
  
  digitalWrite(ledPins[counter], buttonState[counter]); // light specific LED
  
  lastButtonState[counter] = currentState[counter]; // save current state to last state
  //Serial.print("counter: ");
  //Serial.print(counter);
  //Serial.println();

}

This can be made into a function like how you have yours, then all you need to return is "buttonState[counter]"

so i took the blinknodelay and turned it into a function. The on board LED now responses very well proving you right HazardsMind. The only thing now is the screen is now going crazy with the things its suppose to display and displaying the desired text all over the screen in random spots. Here is the function below.

const int ledPin = 13; // the number of the LED pin
int ledState = LOW; // ledState used to set the LED
long previousMillis[100]; // will store last time LED was updated
unsigned long currentMillis[100];
int actionstate; //variable to check if request time has been passed
long interval; // interval at which to blink (milliseconds)

void setup()
{
pinMode(ledPin, OUTPUT); // set the digital pin as output:
for(int i=0; i>99; i++){previousMillis*=0;}// fills array with zeros*
}
void loop()
{
actionstate=timecheck(1000, 1); //first number is amount to be delayed second is to change array spot for each call of function
if(actionstate==1){ledswap();} //if sent time has passed if statement is true function will be run. Insert delayed function here
}
int timecheck(long interval, int i)
{
_ currentMillis = millis();_

if(currentMillis - previousMillis > interval)
* {*
previousMillis = currentMillis*; // save the last time function was performed*
* actionstate = 1;*
* }*
* else*
* {actionstate = 0;}*

return actionstate;
}
void ledswap() // test function to call and do something
{
* if (ledState == LOW)*
* ledState = HIGH;*
* else*
* ledState = LOW;*
* // set the LED with the ledState of the variable:*
* digitalWrite(ledPin, ledState);*
}

Here is an example of how i am using it. (whole code is included in attached file.)

actionstate=timecheck(50, 0);
if(actionstate==1)
{
LCD.setHome();
LCD.printStr("x spot ");
}

actionstate=timecheck(50, 1);
if(actionstate==1)
{
LCD.setX(50);
LCD.setY(00);
LCD.printNum(optionspotx);
}

GLCD_first_demo_v8.ino (7.16 KB)

i noticed that it display numbers correctly, like when i use LCD.printNum(optionspoty), but when i try to print out a string using LCD.printStr("x spot "); it bugs out. Maybe there is something with the buffer or something when i try to display text at high speeds. I also tried displaying the text once and then the values repetitively. and it still bugs out.

Can you please fix you post and put your code inside code tags. Its the # symbol above the smiley faces.

did i fix it correctly?

Post your full code in code tags.

Whole code was too big for one comments I split it among two comments

/00000000 Libraries included 00000000/

#include <SerialGraphicLCD.h>
#include <SoftwareSerial.h>

/00000000 GLCD screen size 00000000/

#define maxX 127//159
#define maxY 63 //127

/00000000 variables for PINS 00000000/

//Bup Bdown Bleft Bright Bcenter But1 But2 But3
const int buttonPin[8]={4,5,6,7,8,9,10,11};
const int ledPin13 = 13; // the number of the LED pin

/00000000 variables for debounce 00000000/

//Bup Bdown Bleft Bright Bcenter But1 But2 But3
int buttonNumber[8]={0,1,2,3,4,5,6,7};
int buttonState[8];
int lastButtonState[8]={HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH};
long lastDebounceTime[8];
long debounceDelay[8]={10,10,10,10,10,10,10,10};
int reading[8];
int ledState=LOW; // the current state of the output pin

/00000000 delay replacement is timecheck variables 00000000/

long previousMillis[100]; // will store last time LED was updated
unsigned long currentMillis[100];
int actionstate;
long interval;
int optionrowTextDisplayCounter=false;

/00000000 buttonlook variables for buttons 00000000/

int buttonlook[8]={0,0,0,0,0,0,0,0}; //variables to store if button is pressed for pin10

/00000000 variables for menus 00000000/

int menustack[6]={1,0,0,0,0,0}; //array acting as stack for menu porder when hopping from one menu to the other.
// set array size to number of menus desired
int currentmenuspot=1;
int prevmenuspot=1;
int menustackspot=0;
int menunumber;

int menupage=0; //0=Mainmenu 1=AirQ 2=TEMP 3=HEART 4=MORE
int optionrow[4][4]={{11,12,13,14},{21,22,23,24},{31,32,33,34},{41,42,43,44}}; //2D array as a map for menu options
int optionspotx=0;
int optionspoty=0;

int enterbuttons[5]={0,0,0,0,0}; //debounce puts a 1 to be later tested if button was pressed 1=pressed 0=not pressed
int enterbuttoncounter[5]={0,0,0,0,0};

/00000000 LCD class declaration 00000000/
LCD LCD;
/00000000 SETUP 00000000/

void setup()
{

pinMode(buttonPin[0], INPUT); //button on pin 4
pinMode(buttonPin[1], INPUT); //button on pin 5
pinMode(buttonPin[2], INPUT); //button on pin 6
pinMode(buttonPin[3], INPUT); //button on pin 7
pinMode(buttonPin[4], INPUT); //button on pin 8
pinMode(buttonPin[5], INPUT); //button on pin 9
pinMode(buttonPin[6], INPUT); //button on pin 10
pinMode(buttonPin[7], INPUT); //button on pin 11

pinMode(ledPin13, OUTPUT); // pin 13 on board LED

for(int i=0; i>99; i++){previousMillis*=0;}*

  • LCD.setBacklight(20);*

  • LCD.clearScreen();*

  • LCD.setHome();*

  • LCD.printStr(" Program starts in "); //displays "program is starting in 10/9/8 etc"*

  • for(int i = 5; i >= 0; i--) //splash screen*

  • {*

  • LCD.setX(113);*

  • LCD.setY(0);*

  • LCD.printNum(i);*

  • delay(500);*

  • } *

  • LCD.clearScreen();*

  • delay(500);*
    }
    /00000000 LOOP 00000000/
    void loop()
    {

selectmove(); //retrieves states of buttons to see if they were pressed
optionrowValueDisplay(); //display if buttons were pressed
optionrowTextDisplay();
}
/00000000 displays when buttons are pressed 00000000/
void optionrowValueDisplay()
{
*actionstate=timecheck(200, 1); *
if(actionstate==1)
{

  • LCD.setX(50);*
  • LCD.setY(00);*
  • LCD.printNum(optionspotx);*
    }
    *actionstate=timecheck(200, 3); *
    if(actionstate==1)
    {
  • LCD.setX(50);*
  • LCD.setY(9);*
  • LCD.printNum(optionspoty);*
    }
    *actionstate=timecheck(200, 5); *
    if(actionstate==1)
    {
  • LCD.setX(70);*
  • LCD.setY(18);*
  • LCD.printNum(enterbuttoncounter[0]);*
    }
    *actionstate=timecheck(200, 7); *
    if(actionstate==1)
    {
  • LCD.setX(70);*
  • LCD.setY(27);*
  • LCD.printNum(enterbuttoncounter[1]);*
    }
    *actionstate=timecheck(200, 12); *
    if(actionstate==1)
    {
  • LCD.setX(70);*
  • LCD.setY(36);*
  • LCD.printNum(enterbuttoncounter[2]);*
    }
    *actionstate=timecheck(200, 13); *
    if(actionstate==1)
    {
  • LCD.setX(70);*
  • LCD.setY(45);*
  • LCD.printNum(enterbuttoncounter[3]);*
    }
    }
    [/quote]

void optionrowTextDisplay()
{

if(optionrowTextDisplayCounter==true)
{
actionstate=timecheck(125, 0);
if(actionstate==1)
{
LCD.setHome();
LCD.printStr("x spot ");
}
actionstate=timecheck(125, 2);
if(actionstate==1)
{
LCD.setX(0);
LCD.setY(9);
LCD.printStr("y spot ");
}
actionstate=timecheck(125, 4);
if(actionstate==1)
{
LCD.setX(0);
LCD.setY(18);
LCD.printStr("center but ");
}
actionstate=timecheck(125, 6);
if(actionstate==1)
{
LCD.setX(0);
LCD.setY(27);
LCD.printStr("button 1 ");
}
optionrowTextDisplayCounter=true;
}
}

void selectmove()
{

for(int i=0; i<8; i++)
{
cleardebounce(); //clears debounces variables
debounce(buttonNumber*); //debounces input pins*
if(buttonlook*==1) //loops through all the pins*
{
* switch(i)*
* {*
* case 0: //action for when Bup button is pressed*
* if(optionspoty!=3)*
* {*
* optionspoty=optionspoty+1;*
* }*
* break;*
* case 1: //action for when Bdown button is pressed*
* if(optionspoty!=0)*
* {*
* optionspoty=optionspoty-1; *
* } *
* break;*

* case 2: //action for when Bleft button is pressed*
* if(optionspotx!=0)*
* {*
* optionspotx=optionspotx-1;*
* } *
* break;*

* case 3: //action for when Bright button is pressed*
* if(optionspotx!=3)*
* {*
* optionspotx=optionspotx+1;*
* } *
* break;*

* case 4: //action for when Bcenter button is pressed*
* enterbuttons[0]=1;*
* ++enterbuttoncounter[0];*
* break;*

* case 5: //action for when But1 button is pressed*
* enterbuttons[1]=1;*
* ++enterbuttoncounter[1];*
* break;*

* case 6: //action for when But2 button is pressed*
* enterbuttons[2]=1;*
* ++enterbuttoncounter[2];*
* break;*

* case 7: //action for when But3 button is pressed*
* enterbuttons[3]=1;*
* ++enterbuttoncounter[3];*
* break;*

* }*
}
}
}
/00000000 debounce functions 00000000/
void cleardebounce() //clears variables so that they may be retested. Must be called before each debounce.
{
* for(int i=0; i<7; i++)*
* {*
_ buttonlook*=0;
}*_

* for(int i=0; i<4; i++)*
* {*
_ enterbuttons*=0;
}
}
/00000000 debounce 00000000/
int debounce(int buttonNumber) //recieves a pin and debounces that pin
{
reading[buttonNumber] = digitalRead(buttonPin[buttonNumber]);
if (reading[buttonNumber] != lastButtonState[buttonNumber])
{lastDebounceTime[buttonNumber] = millis();}*_

* if ((millis() - lastDebounceTime[buttonNumber]) > debounceDelay[buttonNumber])*
* {*
* if (reading[buttonNumber] != buttonState[buttonNumber])*
* {*
* buttonState[buttonNumber] = reading[buttonNumber];*
* if (buttonState[buttonNumber] == LOW)*
* {*
* ledState = !ledState;*
* buttonlook[buttonNumber]=1; //changes variable to 1 to be later tested if true*
* }*
* }*
* }*

* // set the LED:*
* digitalWrite(ledPin13, ledState);// lights the LED so you know button was pressed*
* // save the reading. Next time through the loop,*
* // it'll be the lastButtonState:*
* lastButtonState[buttonNumber] = reading[buttonNumber];*
}
/00000000 timecheck 00000000/
int timecheck(long interval, int i)
{
_ currentMillis* = millis();*_

if(currentMillis - previousMillis > interval)
* {*
previousMillis_ = currentMillis*; // save the last time function was performed*
* actionstate = 1;
}
else*

* {actionstate = 0;}*_

return actionstate;
}
[/quote]

For whatever reason when I post the code in the comments in forum code format it took out the brackets next to my variables. in int timecheck(long interval, int i) each variable is a spot in an array, so currentMillis is actually currentMillis[i] where the function sends i a place in the array for that particular call so that the values of timecheck are stores and different from other times the function is called.

Have a look on boards schematics (Arduino, Texas, NXP, ST etc....) all use hardware debouncing , not software debouncing.
Put a capacitor in parallel with switch button (100nF) it will works simply.