New to arduino here. How do I debounce multiple buttons?

Hi im new to arduino and i’m working on a project that produces sound through button combinations. I felt the need of having to debounce my module because there are times that the reading is inconsistent but the problem is I don’t know how to debounce it when it comes to multiple buttons. Can you guys please help me?
Here is my code:

#include "pitches.h"

int swiPin [] = {23,24,25,26,27,28,29};

int speakerPin = 8;


//Grouping of combinations
int groupA;
void setup(){
  
  for(int x = 0; x<7; x++){
    pinMode(swiPin[x], INPUT);
    pinMode(swiPin2[x], INPUT);
    //digitalWrite(swiPin[x], 1);
    //digitalWrite(swiPin2[x], 1);
  }
  for(int x = 0; x<2; x++){
    pinMode(swiPin3[x], INPUT);
    //digitalWrite(swiPin3[x], 1);
  }
  Serial.begin(9600);
}

void check_fingering(){
   //Check keys pressed
  groupA = 1*(digitalRead(swiPin[0])) + 2*(digitalRead(swiPin[1])) + 4*(digitalRead(swiPin[2])) + 8*(digitalRead(swiPin[3]));
}

void loop(){
  check_fingering();
  if (groupA == 1){
   Serial.println("Button 1 is pressed");
  tone(speakerPin, NOTE_C4 );
  }
  else if (groupA == 2){
     Serial.println("Button 2 is pressed");
 tone(speakerPin, NOTE_D4);
  }
  else if (groupA == 4){
     Serial.println("Button 3 is pressed");
  tone(speakerPin, NOTE_E4);
  }  
 else if (groupA == 3){
   Serial.println("Button 1 and 2 is pressed");
  tone(speakerPin, NOTE_G4);
  }
  else if (groupA == 5){
   Serial.println("Button 1 and 3 is pressed");
   tone(speakerPin, NOTE_A4);
  }
    else if (groupA == 6){
   Serial.println("Button 2 and 3 is pressed");
  tone(speakerPin, NOTE_B4);
  }
      else if (groupA == 7){
   Serial.println("Button 1 and 2 and 3 is pressed");
 tone(speakerPin, NOTE_C5);
  }
      else if (groupA == 8){
   Serial.println("Button 4 is pressed");
 tone(speakerPin, NOTE_F4);
  }
        else if (groupA == 9){
   Serial.println("Button 4 and 1 is pressed");
 tone(speakerPin, NOTE_C3);
  }
        else if (groupA == 10){
   Serial.println("Button 4 and 2 is pressed");
 tone(speakerPin, NOTE_D3);
  }
        else if (groupA == 11){
   Serial.println("Button 4 and 2 and 1 is pressed");
 tone(speakerPin, NOTE_E3);
  }
        else if (groupA == 12){
   Serial.println("Button 4 and 3 is pressed");
 tone(speakerPin, NOTE_F3);
  }
        else if (groupA == 13){
   Serial.println("Button 4 and 3 and 1 is pressed");
 tone(speakerPin, NOTE_G3);
  }
        else if (groupA == 14){
   Serial.println("Button 4 and 3 and 2 is pressed");
 tone(speakerPin, NOTE_A3);
  }
      else if (groupA == 15){
   Serial.println("Button everything is pressed");
 tone(speakerPin, NOTE_B3);
  }
   else{
     noTone(speakerPin);
   }
  //delay(500);
  
}

Anybody? :(

Hi

There are lots of ways to do most things, but here’s a way that I often use to software debounce multiple buttons.

int swiPin [] = {23,24,25,26,27,28,29};  // no change to your declaration
boolean currentButtonVal[7];          
  
void setup() {
  // if you have active low using pull-up resistors, initial state is high on all buttons
  for(int i = 0; i<7; i++) currentButtonVal[i] = true;

}

void loop() {
  // do stuff  
}

void check_fingering(){
   //Check keys pressed...now calls to debounce rather than a digitalRead each time
  groupA = 1*(debounce[0])) + 2*(debounce[1])) + 4*(diebounce[2])) + 8*(debounce[3]));
}
}

// ---------------------------------------------------------------------------------
// returns a debounced value for our button
//
boolean debounce(int thisButton) {
  boolean current = digitalRead(swiPin[thisButton]);
  if (currentButtonVal[thisButton] != current) {
    delay(5);
    current = digitalRead(swiPin[thisButton]);
  }
  currentButtonVal[thisButton] = current;  // store new state for your pin
  return current;
}

Note that by removing the line in the debounce function currentButtonVal[thisButton] = current; you could check for changes to a button outside of your code. A slightly different implementation I frequently use is boolean buttonHasChanged(int thisButton) which just returns if currentButtonVal[thisButton] no longer matches the debounced digitalRead, which means you work off the currentButtonVal values for logic in the code.

Hope this helps,
Geoff

Hi thanks for your reply kind sir.
Here is my updated code.

#include "pitches.h"

int swiPin [] = {23,24,25,26,27,28,29};
boolean currentButtonVal[7];

int speakerPin = 8;

//Grouping of combinations
int groupA;

void setup(){
  for(int x = 0; x<7; x++){
   currentButtonVal[x] = true;
  }
  Serial.begin(9600);
}


void check_fingering(){
   //Check keys pressed
   groupA = 1*(debounce[0])) + 2*(debounce[1])) + 4*(debounce[2])) + 8*(debounce[3]));
}

boolean debounce(int thisButton) {
  boolean current = digitalRead(swiPin[thisButton]);
  if (currentButtonVal[thisButton] != current) {
    delay(5);
    current = digitalRead(swiPin[thisButton]);
  }
  currentButtonVal[thisButton] = current;  // store new state for your pin
  return current;
}

void loop(){
  check_fingering();
  if (groupA == 1){
   Serial.println("Button 1 is pressed");
  tone(speakerPin, NOTE_C4 );
  }
  else if (groupA == 2){
     Serial.println("Button 2 is pressed");
 tone(speakerPin, NOTE_D4);
  }
  else if (groupA == 4){
     Serial.println("Button 3 is pressed");
  tone(speakerPin, NOTE_E4);
  }  
 else if (groupA == 3){
   Serial.println("Button 1 and 2 is pressed");
  tone(speakerPin, NOTE_G4);
  }
  else if (groupA == 5){
   Serial.println("Button 1 and 3 is pressed");
   tone(speakerPin, NOTE_A4);
  }
    else if (groupA == 6){
   Serial.println("Button 2 and 3 is pressed");
  tone(speakerPin, NOTE_B4);
  }
      else if (groupA == 7){
   Serial.println("Button 1 and 2 and 3 is pressed");
 tone(speakerPin, NOTE_C5);
  }
      else if (groupA == 8){
   Serial.println("Button 4 is pressed");
 tone(speakerPin, NOTE_F4);
  }
        else if (groupA == 9){
   Serial.println("Button 4 and 1 is pressed");
 tone(speakerPin, NOTE_C3);
  }
        else if (groupA == 10){
   Serial.println("Button 4 and 2 is pressed");
 tone(speakerPin, NOTE_D3);
  }
        else if (groupA == 11){
   Serial.println("Button 4 and 2 and 1 is pressed");
 tone(speakerPin, NOTE_E3);
  }
        else if (groupA == 12){
   Serial.println("Button 4 and 3 is pressed");
 tone(speakerPin, NOTE_F3);
  }
        else if (groupA == 13){
   Serial.println("Button 4 and 3 and 1 is pressed");
 tone(speakerPin, NOTE_G3);
  }
        else if (groupA == 14){
   Serial.println("Button 4 and 3 and 2 is pressed");
 tone(speakerPin, NOTE_A3);
  }
      else if (groupA == 15){
   Serial.println("Button everything is pressed");
 tone(speakerPin, NOTE_B3);
  }
   else{
     noTone(speakerPin);
   }
  //delay(500);
  
}

I can’t really test it out right now because my groupmate has our Arduino and is working on another module, I just want to ask a few more questions…

void check_fingering(){
   //Check keys pressed...now calls to debounce rather than a digitalRead each time
  groupA = 1*(debounce[0])) + 2*(debounce[1])) + 4*(diebounce[2])) + 8*(debounce[3]));
}

does using the “debounce” return 1 or 0 like it used to when I used digitalRead? and what’s the difference in using the debounce then digitalRead? i’m still new to this so pls. forgive my lack of knowledge…

boolean debounce(int thisButton) {
  boolean current = digitalRead(swiPin[thisButton]);
  if (currentButtonVal[thisButton] != current) {
    delay(5);
    current = digitalRead(swiPin[thisButton]);
  }
  currentButtonVal[thisButton] = current;  // store new state for your pin
  return current;
}

I also noticed there is a “return current” in this function, where can I use “current” on my code sir? on the void loop?

Thank you so much in advance for your help sir strykeroz!

stojt3: I can't really test it out right now because my groupmate has our Arduino and is working on another module, I just want to ask a few more questions..

No problems. I didn't test it either :) You know you can test compile it in the IDE? If you did, you'd find this typo won't compile:

4*(diebounce[2]))

Sorry 'bout the typo. Should be debounce(2) of course.

stojt3: void check_fingering(){   //Check keys pressed...now calls to debounce rather than a digitalRead each time  groupA = 1*(debounce[0])) + 2*(debounce[1])) + 4*(diebounce[2])) + 8*(debounce[3])); }

does using the "debounce" return 1 or 0 like it used to when I used digitalRead? and what's the difference in using the debounce then digitalRead? i'm still new to this so pls. forgive my lack of knowledge..

Yes it does. Actually it returns a true or false since I declared it should return a boolean, but true = 1 and false = 0 in C-like languages, so it will work the same way.

stojt3: boolean debounce(int thisButton) { //snip

I also noticed there is a "return current" in this function, where can I use this on my code sir?

Read up on functions in C and you'll see what this is doing. This is a function, it returns a boolean when called (as I mentioned above) and the return statement here tells it to end the function and present the content of the variable current as the result of the function (documentation for return statement from the Arduino reference).

Remember to include that whole block of code from the boolean debounce... line in your code or it won't compile either.

Cheers ! Geoff

Read up on functions in C and you’ll see what this is doing. This is a function, it returns a boolean when called (as I mentioned above) and the return statement here tells it to end the function and present the content of the variable current as the result of the function (documentation for return statement from the Arduino reference).

Read some basics on function sir, so what you are meaning to say sir that on the void loop I should call this function boolean debounce?

Finished compiling with the fixed typo sir. Here is my new code sir geoff.

#include "pitches.h"

int swiPin [] = {23,24,25,26,27,28,29};
boolean currentButtonVal[7];

int speakerPin = 8;

//Grouping of combinations
int groupA;

void setup(){
  for(int x = 0; x<7; x++){
   currentButtonVal[x] = true;
  }
  Serial.begin(9600);
}


void check_fingering(){
   //Check keys pressed
   groupA = 1*(debounce[0])) + 2*(debounce[1])) + 4*(debounce[2])) + 8*(debounce[3]));
}

boolean debounce(int thisButton) {
  boolean current = digitalRead(swiPin[thisButton]);
  if (currentButtonVal[thisButton] != current) {
    delay(5);
    current = digitalRead(swiPin[thisButton]);
  }
  currentButtonVal[thisButton] = current;  // store new state for your pin
  return current;
}

void loop(){
  check_fingering();
  boolean debounce(); //Is this what you mean sir?
  if (groupA == 1){
   Serial.println("Button 1 is pressed");
  tone(speakerPin, NOTE_C4 );
  }
  else if (groupA == 2){
     Serial.println("Button 2 is pressed");
 tone(speakerPin, NOTE_D4);
  }
  else if (groupA == 4){
     Serial.println("Button 3 is pressed");
  tone(speakerPin, NOTE_E4);
  }  
 else if (groupA == 3){
   Serial.println("Button 1 and 2 is pressed");
  tone(speakerPin, NOTE_G4);
  }
  else if (groupA == 5){
   Serial.println("Button 1 and 3 is pressed");
   tone(speakerPin, NOTE_A4);
  }
    else if (groupA == 6){
   Serial.println("Button 2 and 3 is pressed");
  tone(speakerPin, NOTE_B4);
  }
      else if (groupA == 7){
   Serial.println("Button 1 and 2 and 3 is pressed");
 tone(speakerPin, NOTE_C5);
  }
      else if (groupA == 8){
   Serial.println("Button 4 is pressed");
 tone(speakerPin, NOTE_F4);
  }
        else if (groupA == 9){
   Serial.println("Button 4 and 1 is pressed");
 tone(speakerPin, NOTE_C3);
  }
        else if (groupA == 10){
   Serial.println("Button 4 and 2 is pressed");
 tone(speakerPin, NOTE_D3);
  }
        else if (groupA == 11){
   Serial.println("Button 4 and 2 and 1 is pressed");
 tone(speakerPin, NOTE_E3);
  }
        else if (groupA == 12){
   Serial.println("Button 4 and 3 is pressed");
 tone(speakerPin, NOTE_F3);
  }
        else if (groupA == 13){
   Serial.println("Button 4 and 3 and 1 is pressed");
 tone(speakerPin, NOTE_G3);
  }
        else if (groupA == 14){
   Serial.println("Button 4 and 3 and 2 is pressed");
 tone(speakerPin, NOTE_A3);
  }
      else if (groupA == 15){
   Serial.println("Button everything is pressed");
 tone(speakerPin, NOTE_B3);
  }
   else{
     noTone(speakerPin);
   }
  //delay(500);
  
}

Going to test this code out after the new year sir, if ever there is something wrong is it okay if I PM you about this matter?
Thanks again for the big help you gave me! Merry Christmas and a happy new year to you sir!

Yes it does. Actually it returns a true or false since I declared it should return a boolean, but true = 1 and false = 0 in C-like languages, so it will work the same way.

okay sir thanks, i understand. But what does make it unique rather using digitalRead sir? knowing that they give the same output as you've said.

One of the problems with a software debounce is that you're introducing delays into your code and also unnecessarilly consuming execution cycles on the AVR. You also are prevented from debouncing inside an ISR (interrupt service routine) as delay() is not allowed to be used there (although there are some ugly ways to get around that too).

Check out this video tutorial on how to wire up hardware debounce in your button projects - it'll save you time and effort later in code: https://www.youtube.com/watch?v=CRJUdf5TTQQ

Regards,

Leigh

Sir Geoff, when I compiled it has an error with this line of code

groupA = 1*(debounce[0])) + 2*(debounce[1])) + 4*(debounce[2])) + 8*(debounce[3]));

saying: "integration_debounce2:45: error: pointer to a function used in arithmetic" what does this mean sir?

  groupA = 1*(digitalRead(swiPin[0])) + 2*(digitalRead(swiPin[1])) + 4*(digitalRead(swiPin[2])) + 8*(digitalRead(swiPin[3]));

...

 else if (groupA == 3){
   Serial.println("Button 1 and 2 is pressed");

I don't understand why you are combining those reads altogether into one variable, and then pulling those bits out again later.


As for the error message:

void check_fingering(){
   //Check keys pressed
   groupA = 1*(debounce[0])) + 2*(debounce[1])) + 4*(debounce[2])) + 8*(debounce[3]));
}

boolean debounce(int thisButton) {

debounce is a function. You can't index into it like that. Do you mean to call it? Then use round brackets.

Sir Nick, im using binary to decimal conversion so that it would be easy to identify the button combinations.

I revised my code already and here is the newly update one.

#include "pitches.h"

int swiPin [] = {23,24,25,26,27,28,29};
boolean currentButtonVal[7];

int speakerPin = 8;

//Grouping of combinations
int groupA;

void setup(){
  for(int x = 0; x<7; x++){
   currentButtonVal[x] = true;
  }
  Serial.begin(9600);
}


void check_fingering(){
   //Check keys pressed
   groupA = 1*(debounce(0)) + 2*(debounce(1)) + 4*(debounce(2)) + 8*(debounce(3));
}

boolean debounce(int thisButton) {
  boolean current = digitalRead(swiPin[thisButton]);
  if (currentButtonVal[thisButton] != current) {
    delay(5);
    current = digitalRead(swiPin[thisButton]);
  }
  currentButtonVal[thisButton] = current;  // store new state for your pin
  return current;
}

void loop(){
  check_fingering();
  boolean debounce(); //Is this what you mean sir?
  if (groupA == 1){
   Serial.println("Button 1 is pressed");
  tone(speakerPin, NOTE_C4 );
  }
  else if (groupA == 2){
     Serial.println("Button 2 is pressed");
 tone(speakerPin, NOTE_D4);
  }
  else if (groupA == 4){
     Serial.println("Button 3 is pressed");
  tone(speakerPin, NOTE_E4);
  }  
 else if (groupA == 3){
   Serial.println("Button 1 and 2 is pressed");
  tone(speakerPin, NOTE_G4);
  }
  else if (groupA == 5){
   Serial.println("Button 1 and 3 is pressed");
   tone(speakerPin, NOTE_A4);
  }
    else if (groupA == 6){
   Serial.println("Button 2 and 3 is pressed");
  tone(speakerPin, NOTE_B4);
  }
      else if (groupA == 7){
   Serial.println("Button 1 and 2 and 3 is pressed");
 tone(speakerPin, NOTE_C5);
  }
      else if (groupA == 8){
   Serial.println("Button 4 is pressed");
 tone(speakerPin, NOTE_F4);
  }
        else if (groupA == 9){
   Serial.println("Button 4 and 1 is pressed");
 tone(speakerPin, NOTE_C3);
  }
        else if (groupA == 10){
   Serial.println("Button 4 and 2 is pressed");
 tone(speakerPin, NOTE_D3);
  }
        else if (groupA == 11){
   Serial.println("Button 4 and 2 and 1 is pressed");
 tone(speakerPin, NOTE_E3);
  }
        else if (groupA == 12){
   Serial.println("Button 4 and 3 is pressed");
 tone(speakerPin, NOTE_F3);
  }
        else if (groupA == 13){
   Serial.println("Button 4 and 3 and 1 is pressed");
 tone(speakerPin, NOTE_G3);
  }
        else if (groupA == 14){
   Serial.println("Button 4 and 3 and 2 is pressed");
 tone(speakerPin, NOTE_A3);
  }
      else if (groupA == 15){
   Serial.println("Button everything is pressed");
 tone(speakerPin, NOTE_B3);
  }
   else{
     noTone(speakerPin);
   }
  //delay(500);
  
}

what do you think?

Sir Hart, so what you are saying that using debounce is not advisable and using interrupts is preferable in this situation? How do I use interrupts when I'm planning to use 20 button combinations?

stojt3: so what you are saying that using debounce is not advisable and using interrupts is preferable in this situation? How do I use interrupts when I'm planning to use 20 button combinations?

I was suggesting that hardware debounce might be easier than trying to software debounce that many buttons. I wasn't suggesting that interrupts are preferable, just that they become difficult to use if you use software debounce.

stojt3: what do you think?

Does it work?

I don't know how to debounce it when it comes to multiple buttons.

Two quick points:

1) you may not need to debounce it: not all switches / buttons require debouncing. Some of the modern smd pushbuttons for example are surprisingly bounce-free. Play with your switch and see if you indeed need to debounce yours. 2) hardware debouncing is king: you will find that a simple rc network (and sometimes rrc network, depending on your switches) works remarkably well, and relieves the mcu of precious processing power + resources, especially when multiple buttons are debounced.

hart:

stojt3: so what you are saying that using debounce is not advisable and using interrupts is preferable in this situation? How do I use interrupts when I'm planning to use 20 button combinations?

I was suggesting that hardware debounce might be easier than trying to software debounce that many buttons. I wasn't suggesting that interrupts are preferable, just that they become difficult to use if you use software debounce.

Yes sir Hart but if I would to use hardware debounce, it would be a lot of work because i'm planning to use 20 buttons for different combinations that means I have to make 20 hardware debounce ckts. for the 20buttons (correct me if I am wrong, noobie here) . Then using software debounce where I only need to call a function to debounce those 20 buttons. hmmmm...

[quote author=Nick Gammon link=topic=139805.msg1051968#msg1051968 date=1356984081]

stojt3: what do you think?

Does it work? [/quote]

It successfully compiled but I haven't get to test it out yet because my groupmate has the Arduino working on another module, will keep you updated. Is it okay sir Nick if something is wrong when I do get to test it I can message you for your expert advice?

dhenry:

I don't know how to debounce it when it comes to multiple buttons.

Two quick points:

1) you may not need to debounce it: not all switches / buttons require debouncing. Some of the modern smd pushbuttons for example are surprisingly bounce-free. Play with your switch and see if you indeed need to debounce yours. 2) hardware debouncing is king: you will find that a simple rc network (and sometimes rrc network, depending on your switches) works remarkably well, and relieves the mcu of precious processing power + resources, especially when multiple buttons are debounced.

I have tried testing it out without the debounce, it worked but it was pretty inconsistent in producing a sound especially when I push a new button to perform a new button combination sometimes it produces a new sound but most of the time it doesn't because it couldn't read the latest button that I pressed. :( That's why I came into conclusion that I should use debounce, been watching Jeremy Blums video tutorials to learn and this is how I came up with the idea to use this technique to detect button pressed and released. Problem is I don't know how to debounce multiple buttons, I made a new code with the help of sir geoff (the one I posted lately, feel free to check if something is wrong with the code) but haven't tested it yet because my groupmate has our arduino. :D

Thank you guys for replying and trying to help me, happy new year to you all! :D

stojt3: Is it okay sir Nick if something is wrong when I do get to test it I can message you for your expert advice?

No it is not. Please confirm technical questions to the forum where many people will be able to offer advice.

And as a cultural thing "sir Nick" implies I have been knighted by the Queen, which I have not been. Please drop the "sir". I know you are trying to be polite, but it doesn't translate quite right.

A simple debounce would be to simply discard any transitions which occur within a short period of an earlier one. That is, if switch A is pressed, note the time. Then ignore any other presses within (say) 50 milliseconds. This eliminates the need to use delay().

because it couldn’t read the latest button that I pressed.

That sounds more like bad contact than bouncing.

dhenry:

because it couldn't read the latest button that I pressed.

That sounds more like bad contact than bouncing.

sometimes it does read, but most of the time it's inconsistent