0

noob here

So what I am trying to do is output a different number depending on the number of button presses e.g. for 1 button press it should output 1 and so forth. After that I only really want the outputs for 1 to 4 presses. I am using these inputs for a game. Right now, it does work and counts up until 4 and then resets back to 0. The problem that I am having is it continues after 1 click to 2 clicks; what I want it to do is count 1 click when its clicked once, twice when its clicked twice etc. I am trying to use a debouncing code to distinguish between single tap, double tap, triple tap etc @VE7JRO kindly provided a great solution to this problem, albeit it was for one button. I am trying to adjust the code to accommodate 2 separate buttons (on separate pins), but it is giving me an error.

This is the code:

#include <Bounce2.h>

// Connect both buttons in series with one connection
// to GND and the other to a digital pin.
const int buttonPin1 = 2;
const int buttonPin2 = 3;

class Button
{
  private:

    int m_buttonPin1;
    int m_buttonPin2;
    int m_counter;
    unsigned long m_buttonPressTimeout;
    unsigned long m_previousMillis;

  public:

    Button(int button):
      m_buttonPin1(buttonPin1),
      m_buttonPin2(buttonPin2),
      m_counter(0),
      m_buttonPressTimeout(1500), // Button press timeout 500 ms.
      m_previousMillis(0){}



    void Update()
    {
      int valA = digitalRead(button1); // read button stateint 
      int  valB = digitalRead(button2); // read button state
       if (valA == LOW &&valB == LOW)
       { 
      if(m_counter > 0 && millis() - m_previousMillis >= m_buttonPressTimeout)
      {
        Serial.print("Count from Update() just before it's re-set to 0 = ");
        Serial.println(GetCounter());
        m_counter = 0;
      }
    }

    void IncrementCounter(){
      m_counter++;
      if(m_counter > 4){m_counter = 4;}
      if(m_counter == 1){
        m_previousMillis = millis();
      }
    }

    byte GetCounter(){
      return m_counter;
    }

};

Bounce button1Debouncer = Bounce();
Bounce button2Debouncer = Bounce();
Button MyButton(buttonPin1);
Button MyButton(buttonPin2);

void setup(){

  Serial.begin(9600);

  pinMode(buttonPin1, INPUT_PULLUP);
  button1Debouncer.attach(buttonPin);
  button1Debouncer.interval(5);
  pinMode(buttonPin2, INPUT_PULLUP);
  button2Debouncer.attach(buttonPin);
  button2Debouncer.interval(5);

}

void loop(){

  // Call the Update function as fast as possible.
  MyButton.Update();

  // Button pressed.
  if(button1Debouncer.update() && button2Debouncer.update())
  {
    if(button1Debouncer.fell() && button2Debouncer.fell()){
      MyButton.IncrementCounter();
      Serial.print("Count from Button Debouncer = ");
      Serial.println(MyButton.GetCounter());
    }
  }

}
}

The error is: "'buttonPin1' is not a type", I do not understand this error as it didn't give that error for when a single button was used.

  • You write that you want it for a game. So probably you do not want count the presses but just see which button was pressed right? Do not call "digitalRead" many times if you want be fast. A better solution would be to read 7 pins with a single call with PIND, so you read pin 0 to 7 (advanced). Or, when I analyze your code, you just want to be notified of changes, you can use interrupts. – Adriano Nov 15 at 10:15
  • @Adriano I actually do want the number of presses. I think I should make it a little clearer: Fair point...I never really explained it So, I have a player that needs to jump onto different platforms to collect coins and in each level the platform and coin numbers differ and because I am using the input device as a clicking distraction so in each level the amount of clicks needed to make the character move, changes So in one level you need to press the buttons twice, thrice in the next level etc – user19964 Nov 15 at 12:44
  • I don't understand the problem you are trying to solve. How many separate buttons do you have? Is each button on a separate pin, or do you have a matrix of buttons? Can the user press more than one button at a time, and you want to detect how many are pressed at the same time? Let's call that numberOfButtonsPressed. Then are you also looking for the user to single-tap, double-tap, triple-tap, etc, some number of buttons? So you both have the number of buttons being pressed, and the number of times they are pressed? – Duncan C Nov 17 at 21:39
  • You will need to handle "slop" in the input, where the user presses the different buttons at slightly different times. If they are trying to press 4 buttons, you might detect first one, then 2, then 3, then 4 buttons pressed. And because of bounce, you might see some of those button inputs switch rapidly between not-pressed and pressed for a few milliseconds before settling down. – Duncan C Nov 17 at 21:42
  • You might try 20-50 mS. If you don't detect any change in button state for that long, you can consider the button state as stable and take a reading. – Duncan C Nov 17 at 21:43
0

If it’s possible to connect the 2 buttons in series, then this sketch may give you the desired results.

#include <Bounce2.h>

// Connect both buttons in series with one connection
// to GND and the other to a digital pin.
const byte buttonPin = 2;

class Button{

  private:

    byte m_buttonPin;
    byte m_counter;
    unsigned long m_buttonPressTimeout;
    unsigned long m_previousMillis;

  public:

    Button(byte buttonPin):
      m_buttonPin(buttonPin),
      m_counter(0),
      m_buttonPressTimeout(500), // Button press timeout 500 ms.
      m_previousMillis(0){}

    void Update(){
      if(m_counter > 0 && millis() - m_previousMillis >= m_buttonPressTimeout){
        Serial.print("Count from Update() just before it's re-set to 0 = ");
        Serial.println(GetCounter());
        m_counter = 0;
      }
    }

    void IncrementCounter(){
      m_counter++;
      if(m_counter > 4){m_counter = 4;}
      if(m_counter == 1){
        m_previousMillis = millis();
      }
    }

    byte GetCounter(){
      return m_counter;
    }

};

Bounce buttonDebouncer = Bounce();
Button MyButton(buttonPin);

void setup(){

  Serial.begin(9600);

  pinMode(buttonPin, INPUT_PULLUP);
  buttonDebouncer.attach(buttonPin);
  buttonDebouncer.interval(5);

}

void loop(){

  // Call the Update function as fast as possible.
  MyButton.Update();

  // Button pressed.
  if(buttonDebouncer.update()){
    if(buttonDebouncer.fell()){
      MyButton.IncrementCounter();
      Serial.print("Count from Button Debouncer = ");
      Serial.println(MyButton.GetCounter());
    }
  }

}

EDIT

Based on your last update to the question:

I am trying to adjust the code to accommodate 2 separate buttons (on separate pins), but it is giving me an error.

I have updated the sketch to use 2 buttons on separate digital pins.

#include <Bounce2.h>

// Connect each button with one connection
// to GND and the other to a digital pin.
const byte buttonPin = 2;
const byte buttonPin2 = 3;

class Button{

  private:

    byte m_buttonPin;
    byte m_counter = 0;
    unsigned long m_buttonPressTimeout;
    unsigned long m_previousMillis;

  public:

    Button(byte buttonPin):
      m_buttonPin(buttonPin),
      m_counter(0),
      m_buttonPressTimeout(750), // Button press timeout in ms.
      m_previousMillis(0){}

    void Update(){
      if(m_counter > 0 && millis() - m_previousMillis >= m_buttonPressTimeout){
        Serial.print("Count from Update() just before it's reset to 0 = ");
        Serial.println(GetCounter());
        m_counter = 0;
      }
    }

    void IncrementCounter(){
      m_counter++;
      if(m_counter > 4){m_counter = 4;}
      if(m_counter == 1){
        m_previousMillis = millis();
      }
    }

    friend void IncrementCounter(Button&);

    void IncrementCounter(Button&){
      IncrementCounter();
    }

    byte GetCounter(){
      return m_counter;
    }

};

Bounce buttonOneDebouncer = Bounce();
Bounce buttonTwoDebouncer = Bounce();
Button ButtonOne(buttonPin);
Button ButtonTwo(buttonPin2);

void setup(){
  Serial.begin(9600);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(buttonPin2, INPUT_PULLUP);
  buttonOneDebouncer.attach(buttonPin);
  buttonTwoDebouncer.attach(buttonPin2);
  buttonOneDebouncer.interval(25);
  buttonTwoDebouncer.interval(25);
}

void loop(){

  // Call the Update function as fast as possible.
  ButtonOne.Update();
  ButtonTwo.Update();

  // Button one pressed.
  if(buttonOneDebouncer.update()){
    if(buttonOneDebouncer.fell()){
      if(digitalRead(buttonPin2) == 0){
        ButtonOne.IncrementCounter();
      }
    }
  }

  // Button two pressed.
  if(buttonTwoDebouncer.update()){
    if(buttonTwoDebouncer.fell()){
      if(digitalRead(buttonPin) == 0){
        ButtonOne.IncrementCounter(ButtonTwo);
      }
    }
  }

}
  • thank you, I will try this. Does this use an external library? @VE7JRO – user19964 Nov 19 at 18:51
  • Yes, the Bounce2 library. It's available in the IDE library manager. – VE7JRO Nov 19 at 18:54
  • Ah okay, I will try this out thank you @VE7JRO – user19964 Nov 19 at 18:58
  • Thank you; it works rather well...now just have to figure out how to connect two separate buttons on two separate pins @VE7JRO – user19964 Nov 20 at 0:01
  • @user19964 - It's easy to add another button. Define another variable such as buttonPin2, then do something like this Bounce buttonDebouncer2 = Bounce(); and this Button MyButton2(buttonPin2);. A bit of copy / pasting should get 2 buttons working quickly. The most difficult part will be to change the logic in the loop() to work with two buttons. – VE7JRO Nov 20 at 0:25
2

You SHOULD pay attention to the following issues:

1. Floating input problem:

Symptom: the reading value from the input pin is not matched with the button's pressing state.

Cause: input pin is NOT used pull-up or pull-down resistor.

Solution: Use pull-up or pull-down resistor. See Arduino Button (with pull-up/pull-down)

2. Chattering phenomenon

It should be considered in only some application that needs to detect exactly number of the pressing.

Symptom: Button is pressed one, but Arduino code detects several times.

Cause: Due to mechanical and physical issues, the state of the button (or switch) is quickly toggled between LOW and HIGH several times

Solution: Debounce. See Arduino Button Debounce

  • 1
    Thank you for the tips. I Have a pull up resistor on both my buttons and I had implemented a debounce code in this code. I am getting pretty much the same thing as before @Rozona Zoro – user19964 Nov 12 at 0:02
1

It is likely you are experiencing problems associated with button contact bounce. This is where the processor is so fast that it "sees" the button make several contacts when the user only intends for 1 contact to be seen by the program. Consider using this button de-bounce library instead of reading the state of the buttons directly in the sketch.

The code for the above debounce Arduino library is hosted here at github.com. In general, people using github.com will have an "example" folder along with the source code and documentation folders. The debounce Arduino library example folder is here. There are about half a dozen Arduino sketch examples including this 2 button example which might be used as the starting point for the project in the question.

There may be a logic problem in the code when interpreting the number of button presses into "a", "b", "c" & "d". The modulo operator "%" is used. And in the first test, the number of button presses % 1 is tested. If the result is zero the test is true. As any number % 1 has no remainder this test will always be zero and therefor always true. As all other tests are nested inside "else" statements none of the other tests will be executed. Instead consider using a switch / case statement where the code switches on the number of button presses and the case statements are "case 1:", case 2:", "case 3:" & "default:". It is good coding practice to always have a "default:" case in a switch statement. Here we use "default:" instead of "case 4:". After using the value representing the number of button presses, always remember to clear this value before the next iteration. Remember, any "global" values (values defined outside a function) will retain their values between calls to that function. Any "local" value (values defined inside a function) will not retain their values and need to be initialize each time they are used.

  • are there any examples showing how to implement this library...I have it imported to my project but am not sure how to implement it @st2000 – user19964 Nov 12 at 13:52
  • I'll add where to find examples in my answer. Also, I appreciate you editing your question to make it better. I added text to your question to make it clear more information was added and what that information is showing. – st2000 Nov 12 at 14:49
  • yes, I see that you've edited my question: thank you...it reads much better now. Yes, those examples would be much appreciated @st2000 – user19964 Nov 13 at 14:01
  • @st2000just thought to mention that the counter is working now, but it isn't working exactly how I would like it to. – user19964 Nov 14 at 0:27
  • You are using the Modulo "%" operator. I do not think that is what you want. For instance, you can divide any integer by 1 and not get a remainder. So 1 % 1 is 0, 2 % 1 is 0 anything % 1 is 0. That statement is always true and nothing below it will execute. You will always print out "a". Do you want me to alter my answer again? – st2000 Nov 14 at 4:04
1

Your updated code has lots of problems. To do button debouncing, try something like this:

//Adjust debounceTime as desired. Shorter times will make fore faster button 
//response, but make the debouncing less effective. 50 is 1/20th of a second. 
#define debounceTime 50

unsigned long nextButtonCheckTime = 0;
bool buttonAState = false;
bool buttonBState = false;


void loop() {
  //Only check the buttons if the debounce time has passed
  if (millis() > nextButtonCheckTime) 
    bool newButtonAState = digitalRead(buttonAPin) == LOW;
    bool newButtonBState = digitalRead(buttonBPin) == LOW;
    //If one or both buttons have changed state
    if  (buttonAState != newButtonAState || buttonBState != newButtonBState)) {
      nextButtonCheckTime = millis() + debounceTime;
      buttonAState = newButtonAState;
      buttonBState = newButtonBState;
      //Handle change of button state
    }
  }
}

That is pseudocode. It almost certainly contains syntax errors. You should use it as a guide, and rewrite it to suit your needs. Do not say "I copied your code into my sketch and it won't compile."

  • Thank you; this does help as a guideline indeed. I will use it accordingly @DuncanC – user19964 Nov 19 at 0:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.