Go Down

Topic: New to arduino here. How do I debounce multiple buttons? (Read 4 times) previous topic - next topic

stojt3

Dec 30, 2012, 07:00 am Last Edit: Dec 30, 2012, 07:30 am by stojt3 Reason: 1
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:
Code: [Select]


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



strykeroz

Hi

There are lots of ways to do most things, but here's a way that I often use to software debounce multiple buttons.  
Code: [Select]

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
"There is no problem so bad you can't make it worse"
- retired astronaut Chris Hadfield

stojt3

#3
Dec 30, 2012, 11:38 am Last Edit: Dec 30, 2012, 11:41 am by stojt3 Reason: 1
Hi thanks for your reply kind sir.
Here is my updated code.
Code: [Select]

#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..

Code: [Select]

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..


Code: [Select]

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!

strykeroz

#4
Dec 30, 2012, 11:46 am Last Edit: Dec 31, 2012, 01:12 am by strykeroz Reason: 1

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:
Code: [Select]
4*(diebounce[2]))
Sorry 'bout the typo.  Should be debounce(2) of course.

Code: [Select]

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.

Code: [Select]

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
"There is no problem so bad you can't make it worse"
- retired astronaut Chris Hadfield

stojt3

Quote

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.
Code: [Select]

#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!

stojt3

Quote
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.

hart

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

stojt3

Sir Geoff, when I compiled it has an error with this line of code
Code: [Select]

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?

Nick Gammon

Code: [Select]

  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:

Code: [Select]

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.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

stojt3

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.

Code: [Select]

#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?

stojt3

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?

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?


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. 

Nick Gammon

Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

dhenry

Quote
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.

Go Up