Multiple buttons, both read as pressed twice when executing code, ezButton Library

I have general coding experience, mainly MatLab and Excel/VBA, so Arduino is a whole new ball game for me. I have narrowed it down to a coding error as the hardware works perfectly fine on a simple but not ideal code.

The general idea of the code is to have 2 buttons do two versions of something similar. In this case, the 1st button will run it 1 time, the 2nd button will run it multiple times. The code is doing everything as expected, except for the fact it will register 2 button presses when either button is pressed, executing the actions inside either buttons IF statement 2 times. I added the internal IF statements to the button.isPressed() IF statements, thinking it might fix it, but it still runs 2 times.

// -------------------- LIBRARIES --------------------------------------------------------------------------------------------------------------------------------------------------- //

#include <AccelStepper.h>                                                       // includes AccelStepper library
#include <ezButton.h>                                                           // includes ezButton library


// -------------------- CONSTANTS --------------------------------------------------------------------------------------------------------------------------------------------------- //

const int piece_Distance = 1670;                                                // distance stepper motor needs to run
const int pieces_1 = 1;                                                         // number of pieces to run for button 1
const int pieces_2 = 10;                                                        // number of pieces to run for button 2

const int button_Interval = 50;                                                 // number of millisecs between button readings

AccelStepper stepper;                                                           // create stepper object, Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5

const int button_Num = 2;                                                       // number of buttons used
const int button_1_Pin = 6;                                                     // defines pin number for button 1
const int button_2_Pin = 7;                                                     // defines pin number for button 2
ezButton buttonArray[] = {ezButton(button_1_Pin), ezButton(button_2_Pin)};      // creates button array for multiple buttons

const int relay_Pin  = 8;                                                       // create relay_Pin object that attaches to pin 8


// -------------------- VARIABLES --------------------------------------------------------------------------------------------------------------------------------------------------- //

int count_1 = 1;                                                                // creates count object to keep track of for pieces
int count_2 = 0;                                                                // creates count object to keep track of for pieces

int button_1 = 0;                                                               // creates button 1 variable for code run
int button_2 = 0;                                                               // creates button 2 variable for loop run

unsigned long stepper_Distance_1 = 0;                                           // set initial distance of stepper to 0 (max val of 4,294,967,295)
unsigned long stepper_Distance_2 = 0;                                           // set initial distance of stepper to 0 (max val of 4,294,967,295)


// -------------------- SETUP (RUNS ONCE AT BEGINNING OF PROGRAM) ------------------------------------------------------------------------------------------------------------------- //

void setup() 
{
  Serial.begin(9600);                                                           // sets data rate in bits per second for serial data transmission

  /*Stepper motor setup:*/
  stepper.setMaxSpeed(2500.0);                                                  // sets maximum drive speed for stepper motor in steps per second
  stepper.setAcceleration(5000.0);                                              // sets acceleration for stepper motor in steps per second^2 
  pinMode(relay_Pin, OUTPUT);                                                   // declare Relay as output

  for (byte i = 0; i < button_Num; i++)                                         // for loop to establish debounce for each button
  {
    buttonArray[i].setDebounceTime(100);                                        // set debounce time to 50 milliseconds
  }
}


// -------------------- LOOP (RUNS UNTIL POWERED OFF OR STOPPED) -------------------------------------------------------------------------------------------------------------------- //

void loop() 
{
  for (byte i = 0; i < button_Num; i++)
    buttonArray[i].loop();                                                      // MUST call the loop() function first

    if (buttonArray[0].isPressed()) 
    {      
      button_1 = 1;
      
      if (button_1 == 1)
      {
        Serial.println("The button 1 is pressed");
        
        Serial.println(count_1);
        
        /*Stepper motor control:*/
        delay(2000);                                                            // delay stepper motor start
        stepper_Distance_1 = stepper_Distance_1 + piece_Distance;               // calculate stepper motor position
        stepper.runToNewPosition(stepper_Distance_1);
        delay(1000);                                                            // delay to turn on LED/Relay
        digitalWrite (relay_Pin, HIGH);                                         // turn on relay high
        delay(500);                                                             // delay to switch to relay low
        digitalWrite (relay_Pin, LOW);                                          // turn on low relay (turn off) 
        
        button_1 = 0;
      }  
    }

    if (buttonArray[1].isPressed()) 
    {
      button_2 = 1;
      
      if (button_2 == 1)
      {
        Serial.println("The button 2 is pressed");
        for (count_2 = 1; count_2 < pieces_2 + 1; count_2++)
        {   
          Serial.println(count_2);     
          /*Stepper motor control:*/
          delay(2000);                                                            // delay stepper motor start
          stepper_Distance_2 = stepper_Distance_2 + piece_Distance;               // calculate stepper motor position
          stepper.runToNewPosition(stepper_Distance_2);
          delay(1000);                                                            // delay to turn on LED/Relay
          digitalWrite (relay_Pin, HIGH);                                         // turn on relay high
          delay(500);                                                             // delay to switch to relay low
          digitalWrite (relay_Pin, LOW);                                          // turn on low relay (turn off)
        }
        button_2 = 0;
      }
    }
}

When I press button 1, I get the following in my Serial Monitor:

The button 1 is pressed
1
The button 1 is pressed
1

When I press button 2, I get the following in my Serial Monitor:

The button 2 is pressed
1
2
3
4
5
6
7
8
9
10
The button 2 is pressed
1
2
3
4
5
6
7
8
9
10

Any help is appreciated. I can provide more details if necessary. Thanks.

you don't want to see only if the button IS pressed but you also need to remember you have taken that action into account and not trigger again until the button is released

there are better libraries than ezButton.h that will let you know the State but also have methods that return true only once (or trigger a callback once)

I'd suggest to look at @bricoleau library (but in French) or the OneButton library from Matthias Hertel.

its doesn't need to be that complicated

consider

#define Button  A1
#define LED     10

enum { Off = HIGH, On = LOW };

void
setup ()
{
    Serial.begin (9600);

    pinMode (Button, INPUT_PULLUP);

    digitalWrite (LED, Off);
    pinMode (LED,    OUTPUT);
}

void
loop ()
{
    static byte butState = Off;
           byte but      = digitalRead (Button);

    if (butState != but)  {
        butState = but;

        if (On == but)  {
            digitalWrite (LED, ! digitalRead (LED));

            const char *s = digitalRead (LED) ? "Off" : "On";
            Serial.println (s);
        }

        delay (10);     // debounce
    }
}

Isn't that essentially what my internal IF statements are doing when I set button_1 = 1 and then running the code when that value equals 1. It then immediately sets it to equal zero after that code is ran. This means that the button is somehow registering a press twice, even though it's getting debounced, as it would have to physically set the button_1 to 1 again to run the code.

what prevents isPressed() from returning true multiple times if the button state hasn't changed (i.e. hasn't been released yet)?

No... you force the flag to 1 all the time

if (buttonArray[0].isPressed()) 
    {      
     button_1 = 1; // <==== SEE HERE
      
      if (button_1 == 1) // <== SO THIS IS ALWAYS TRUE
      {

I guess that is technically true but that isn't the current issue. The button is being pressed once, and I have increased debounce before posting this to make sure its not registering a second press from my input.

It is forced to one only if the button is pressed, correct?

isn't it redundant to set a variable to a value and then immediately testing if the variable is that value?

i don't think the code is doing what you think

Hi,
You need to detect the button BEING pressed, that is GOING from LOW TO HIGH to set your buttonpressed variable.
Not the button staying pressed.
When you have accomplished the event that buttonpress being set has caused, you reset it and wait for another LOW to HIGH transition.

Tom... :smiley: :+1: :coffee: :australia:

This also causes the button to register 2 times. Those IF and setting equal to 1 were a possible way to address the issue but like I said, that obviously didn't work...lol.

// -------------------- LOOP (RUNS UNTIL POWERED OFF OR STOPPED) -------------------------------------------------------------------------------------------------------------------- //

void loop() 
{
  for (byte i = 0; i < button_Num; i++)
    buttonArray[i].loop();                                                      // MUST call the loop() function first

    if (buttonArray[0].isPressed()) 
    {      
        Serial.println("The button 1 is pressed");
        
        Serial.println(count_1);
        
        /*Stepper motor control:*/
        delay(2000);                                                            // delay stepper motor start
        stepper_Distance_1 = stepper_Distance_1 + piece_Distance;               // calculate stepper motor position
        stepper.runToNewPosition(stepper_Distance_1);
        delay(1000);                                                            // delay to turn on LED/Relay
        digitalWrite (relay_Pin, HIGH);                                         // turn on relay high
        delay(500);                                                             // delay to switch to relay low
        digitalWrite (relay_Pin, LOW);                                          // turn on low relay (turn off) 
    }

    if (buttonArray[1].isPressed()) 
    {
        Serial.println("The button 2 is pressed");
        for (count_2 = 1; count_2 < pieces_2 + 1; count_2++)
        {   
          Serial.println(count_2);     
          /*Stepper motor control:*/
          delay(2000);                                                            // delay stepper motor start
          stepper_Distance_2 = stepper_Distance_2 + piece_Distance;               // calculate stepper motor position
          stepper.runToNewPosition(stepper_Distance_2);
          delay(1000);                                                            // delay to turn on LED/Relay
          digitalWrite (relay_Pin, HIGH);                                         // turn on relay high
          delay(500);                                                             // delay to switch to relay low
          digitalWrite (relay_Pin, LOW);                                          // turn on low relay (turn off)
      }
    }
}

i think ezBUtton has a flaw

bool ezButton::isPressed(void) {
	if(previousSteadyState == HIGH && lastSteadyState == LOW)
		return true;
	else
		return false;
}
1 Like

Hi,
Have you looked at and tried this library;

Tom.... :smiley: :+1: :coffee: :australia:

1 Like

"pressed" typically means going from Off to On, not being On.

Hmmm...is there a simple solution you would recommend to fix the flaw in the ezButton? Or is it a much major flaw that would require a switch to a different library or something?

I guess I'm not sure exactly what the flaw is you are seeing. Thanks.

when isPressed() is true, perform your action if the flag is not set and set it.

when isPressed is not true, clear the flag

but this is just putting bandages on bad code

I have not looked at or tried this library, I am fairly new to this and I was striking out on google so decided to come to the experts. I will look at this and see if it could be a possible retrofit into my existing code. Thanks.

why?

depends on your definition of "pressed". does it mean the button is being depressed and held or that there is a change in state, a single event from what it was.

if you simply want to indicate the current state (is it being pressed?), why would you need the lastSteadyState.

Here is another approach, may help? May just be adding more headache.

#include <mechButton.h>

mechButton  button1(2);    // Set up button one on pin 2 <- serving suggestion
mechButton  button2(4);    // Set up button one on pin 4 <- serving suggestion


void setup(void) {

   button1.setCallback(btn1Clicked);
   button2.setCallback(btn2Clicked);
}


void btn1Clicked(void) {

   if (!button1.trueFalse()) {
      //Run it once
   }
}

void btn2Clicked(void) {

   if (!button2.trueFalse()) {
      //Run it multiple times
   }
}

void loop() { 
   idle();      // You will need to call idle in your loop for your button stuff to work.
 }

(I) think it does a good job of sorting out the button issues for you. If you would like to try this you will need to instal LC_baseTools from the IDE library manager to compile it.

Good luck!

-jim lee