Go Down

Topic: Problem debouncing multiple buttons (Read 12959 times) previous topic - next topic

Yigiter007

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.

Yigiter007

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.

Quote

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;
}


Jiggy-Ninja

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.
Hackaday: https://hackaday.io/MarkRD
Advanced C++ Techniques: https://forum.arduino.cc/index.php?topic=493075.0

Yigiter007

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

Yigiter007

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.

Yigiter007

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


HazardsMind

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.
My GitHub:
https://github.com/AndrewMascolo?tab=repositories

Yigiter007

#7
Feb 27, 2014, 08:05 pm Last Edit: Feb 27, 2014, 08:10 pm by Yigiter007 Reason: 1
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.

Yigiter007

#8
Feb 27, 2014, 08:09 pm Last Edit: Feb 27, 2014, 08:17 pm by Yigiter007 Reason: 1
/*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];
}

HazardsMind

#9
Feb 27, 2014, 08:55 pm Last Edit: Feb 27, 2014, 09:50 pm by HazardsMind Reason: 1
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.
Code: [Select]
/*
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]"
My GitHub:
https://github.com/AndrewMascolo?tab=repositories

Yigiter007

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);
}

Yigiter007

#11
Feb 28, 2014, 02:36 am Last Edit: Feb 28, 2014, 02:39 am by Yigiter007 Reason: 1
Here is an example of how i am using it. (whole code is included in attached file.)

Quote

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);
}


Yigiter007

#12
Feb 28, 2014, 03:16 am Last Edit: Feb 28, 2014, 05:34 am by Yigiter007 Reason: 1
i noticed that it display numbers correctly, like when i use
Code: [Select]
LCD.printNum(optionspoty), but when i try to print out a string using
Code: [Select]
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.

HazardsMind

Can you please fix you post and put your code inside code tags. Its the # symbol above the smiley faces.
My GitHub:
https://github.com/AndrewMascolo?tab=repositories

Yigiter007


Go Up