Multifunctional Pushbutton?

Hello!

As stated in the subject matter, i have trouble with knowing how to have ONE pushbutton to do several things every time it is pressed.

Let's me use an example:

I have ONE pushbutton. First time it is pressed = action 1 happens, next time it is pressed = action 2 happens, etc.

Let's take my project:

I have an automatic drawer that i want to open and close. I have a H-bridge, which is used to run a 12V motor, which switches the direction, which opens and closes the drawer.

So let's get back to the example

Action 1 = Opens the drawer (runs motor, and stops at a given time, until next button press)

Action 2 = Closes the drawer (switches motor direction, and stops when drawer is closed)

I have an idea of this being in a loop, where you can state the amounts of button presses. For instance:

Int buttonPress = 0;

Then maybe have an if/else sentence, which controls the actions?

if (buttonPress==1) //Action 1

  • Then does something here

else (do nothing)

And so on.

Hope you understand what i am getting at here. If not, please let me know!

Have a look at the state change detection example. it shows how to count button presses. Combine that with the switch case structure or a series of if, else if, else statements to choose an action based in the button push count.

In this case i would probably use a switch case structure.

You have the right idea so all you need to do now is write some code that implements it.

One thing, it's important that you note when the button changes to being pressed and not just is pressed. By a bit of good luck the StateChangeDetection example in the IDE shows how to do that so it's very close to what you need except it only triggers something every 4th button push. So that should be a good starting point.

Give it a try. If you have problems post your code here and we can help you to get it working.

Steve

Hello again!

I have taken a look at your suggestions and i have come up with this code:

//Konstanter
const int enA = 10;
const int in1 = 9;
const int in2 = 8;
const int buttonPin = 2;
//Variable
int buttonState = 0;
int buttonPushCounter = 0;
int lastButtonState = 0;

void setup() {
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(enA, OUTPUT);
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
}




void loop(){
buttonState = digitalRead(buttonPin);

if(buttonState != lastButtonState) {
  if(buttonState==HIGH) {
    buttonPushCounter++;
    Serial.println("tændt");
    Serial.print("Antal tryk på knap: ");
    Serial.println(buttonPushCounter);
  } else {
    Serial.println("slukket");
  }
  delay(50);
}
lastButtonState = buttonState;

if(buttonPushCounter == 1){
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);
  analogWrite(enA, 255);
  delay(2000);
  digitalWrite(in1,LOW);
  digitalWrite(in2,LOW);
  if(buttonPushCounter == 2){
    digitalWrite(in1,LOW);
    digitalWrite(in2,HIGH);
    analogWrite(enA,255);
    delay(2000);
    digitalWrite(in1,LOW);
    digitalWrite(in2,LOW);
  }
  buttonPushCounter = 0;
}
  

}

I have tried using the Statechange detection example as a stepping stone, which helped me out, but i am having some issues.

The button is connected to the arduino as shown in the StateChange detection example and my connections look like this:

So when i power this up the button goes from off to on and back again many times, without me even pressing the button. Any idea why?

And also, does my code seem right for my project purpose? I ain’t a arduino Wiz, so i am not sure.

Thank you! :slight_smile:

The button is connected to the arduino as shown in the StateChange detection example

Check your circuit carefully against the description in the SCD example

The circuit: - pushbutton attached to pin 2 from +5V - 10 kilohm resistor attached to pin 2 from ground

Pin 2 should be held LOW (GND) via the 10K resistor until the button is pressed which should connect pin 2 to 5V (HIGH)

Your circuit as drawn holds pin 2 at 5V all the time

Hello again!

Thanks for your suggestion, i have got it to work now with the button.

So the button acts as intended. I am still having trouble with the code as shown earlier, regarding my project. Where it is supposed to be pressed once = action 1 happens, press again =action 2 happens and then reset back to 0.

I am not sure if this code implements this idea, or if i have done something wrong, because it does not seem to work, when i connect it as shown in the schematic. (Even after fixing the button issue) :)

The first thing to correct is that you have got the

    if (buttonPushCounter == 2)

inside the

  if (buttonPushCounter == 1)

code block. This problem would be easier to see if you Auto Formatted your code in the IDE

Alright. I've corrected it, by putting and } after the first if statement, and just before the second if statement.

But i still can't seem to get it to work. Have tried another code with switch case, but seems not to have done anything. The motor runs, when i upload the original code, but the button does not respond. The motor just runs in intervals of a few seconds, then turns off, and then turns on and does the same thing.

When i take a look at the serial monitor, it says that the buttonpress = 1, and then (without me touching the button) says buttonpress = 1 again (seems like it's running the first if-statement over and over again, without gaining a count, which should activate the second if-statement

I am sooo confused, haha :cold_sweat:

EDIT:

So it seems that the button works (sometimes)

When i press the button, which would be buttonPushCounter == 1, then the motor spins one way(which is fine), but after like 2 seconds it stops for a very small time, and keeps going the same direction until other input is given (which i not what i had in mind doing)

When i press the button again, which would be buttonPushCounter ==2, then the motor spins the other way (as intended), and does the same thing as stated just above. (not intended)

When i press a third time, the motor stops, since buttonPushCounter ==3, which does not have any statements, but what i want is when buttonPushCounter ==2 happens, then the next push on the button should bring it back to buttonPushCounter ==1 (which i tried to do with buttonPushCounter = 0; in the end of the loop)

Any ideas?

When you make changes to your code, please post the latest version so that we can keep up.

The code that corresponds with the recent description:

//Konstanter
const int enA = 10;
const int in1 = 9;
const int in2 = 8;
const int buttonPin = 2;
//Variable
int buttonState = 0;
int buttonPushCounter = 0;
int lastButtonState = 0;

void setup() {
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(enA, OUTPUT);
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
}




void loop() {
  buttonState = digitalRead(buttonPin);

  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      buttonPushCounter++;
      Serial.println("tændt");
      Serial.print("Antal tryk pÃ¥ knap: ");
      Serial.println(buttonPushCounter);
    } else {
      Serial.println("slukket");
    }
    delay(50);
  }
  lastButtonState = buttonState;

  if (buttonPushCounter == 1) {
    digitalWrite(in1, HIGH);
    digitalWrite(in2, LOW);
    analogWrite(enA, 255);
    delay(2000);
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
  }
  if (buttonPushCounter == 2) {
    digitalWrite(in1, LOW);
    digitalWrite(in2, HIGH);
    analogWrite(enA, 255);
    delay(2000);
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
  }
buttonPushCounter != 0;
}

Okay. I found a solution.

So what i thought needed to be small adjustments to my code seemed to be true after all.

The only thing i had to do to solve my problem was to move the 2 if statements that contained my actions, up so they would be between the first if statement and just before the first "else" statement. This solved my problem with the motor running indefinitely until another action was given.

The code before was:

//Konstanter
const int enA = 10;
const int in1 = 9;
const int in2 = 8;
const int buttonPin = 2;
//Variable
int buttonState = 0;
int buttonPushCounter = 0;
int lastButtonState = 0;

void setup() {
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(enA, OUTPUT);
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
}




void loop() {
  buttonState = digitalRead(buttonPin);

  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      buttonPushCounter++;
      Serial.println("tændt");
      Serial.print("Antal tryk pÃ¥ knap: ");
      Serial.println(buttonPushCounter);
    } else {
      Serial.println("slukket");
    }
    delay(50);
  }
  lastButtonState = buttonState;

  if (buttonPushCounter == 1) {
    digitalWrite(in1, HIGH);
    digitalWrite(in2, LOW);
    analogWrite(enA, 255);
    delay(2000);
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
  }
  if (buttonPushCounter == 2) {
    digitalWrite(in1, LOW);
    digitalWrite(in2, HIGH);
    analogWrite(enA, 255);
    delay(2000);
    digitalWrite(in1, LOW);
    digitalWrite(in2, LOW);
  }
buttonPushCounter != 0;
}

And the code now is:

//Konstanter
const int enA = 10;
const int in1 = 9;
const int in2 = 8;
const int buttonPin = 2;
//Variable
int buttonState = 0;
int buttonPushCounter = 0;
int lastButtonState = 0;

void setup() {
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(enA, OUTPUT);
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
}




void loop() {
  buttonState = digitalRead(buttonPin);

  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      buttonPushCounter++;
      Serial.println("tændt");
      Serial.print("Antal tryk på knap: ");
      Serial.println(buttonPushCounter);

      if (buttonPushCounter == 1) {
        digitalWrite(in1, HIGH);
        digitalWrite(in2, LOW);
        analogWrite(enA, 255);
        delay(2000);
        digitalWrite(in1, LOW);
        digitalWrite(in2, LOW);
      }
      if (buttonPushCounter >=2) {
        digitalWrite(in1, LOW);
        digitalWrite(in2, HIGH);
        analogWrite(enA, 255);
        delay(2000);
        digitalWrite(in1, LOW);
        digitalWrite(in2, LOW);
        buttonPushCounter = 0;
      }
    } else {
      Serial.println("slukket");
    }
    delay(50);
  }
  lastButtonState = buttonState;

delay(10);
}

Thanks for all your suggestions. Has helped me alot. I will not think twice about asking here again. You were all very helpful. I might need you again sometime ;)

And actually, i have one more cry for help (I am sorry, haha)

Since we have the button working as intended and the coding working as intended. Now i want several buttons, which can work in parallel, which - no matter which one you press or if you press them simultaneously - will activate the same action as i had worked on earlier.

The idea is to create a pressure plate type of thing, which has 4 buttons (one in each corner) in which i would 3D print a plate, which could press down on the buttons. So that means that it does not matter if you press 1, 2, 3 or 4 buttons at the same time, the same action would still occur otherwise.

How would i start this, how would these buttons be connected, as well as how would the coding look, if i were to have several buttons for the same action?

Software solution : put the button pin numbers in an array and iterate through it reading the state of the current pin. When you find one pressed take action

Hardware solution : wire the buttons in parallel

Hello again.

I have taken all your suggestions and help.

The project is almost done, but i am in need om some assistance again.

In the project i also want 2 buttons, which will work as a limit switch for the motor. (For context, our motor runs on a rack & pinion setup). So when the motor hits one of the buttons it stops and can again start when i press the pressure plate, but the thing is that it matters which way the motor runs AFTER i press the pressure plate after the motor has been stopped by one of the limit switches.

Because if the motor runs the wrong direction when the pressure plate is pressed, then that means it would just stop the motor in the same place again. So if you look at a line, which has the two limit switches in each end. The motor runs to the left, and hits the left limit switch, and it stops. When the plate is pressed, the motor should then go right, so it would not again hit the left switch.

Hope you understand what i am getting at here.

The code as of now, is as follows:

//Konstanter
const int enA = 10;
const int in1 = 9;
const int in2 = 8;
const int buttonPin = 2;
const int endestoppin = 3;
//Variable
int buttonState = 0;
int buttonPushCounter = 0;
int lastButtonState = 0;
int endestopState = 0;
int endestopCounter = 0;
int lastEndestopState = 0;

void setup() {
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(enA, OUTPUT);
  pinMode(buttonPin, INPUT);
  pinMode(endestopPIn, INPUT);
  Serial.begin(9600);
}




void loop() {
  buttonState = digitalRead(buttonPin);

  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      buttonPushCounter++;
      Serial.println("tændt");
      Serial.print("Antal tryk på knap: ");
      Serial.println(buttonPushCounter);

      if (buttonPushCounter == 1) {
        digitalWrite(in1, HIGH);
        digitalWrite(in2, LOW);
        analogWrite(enA, 255);
        if(endestop == HIGH); {
        digitalWrite(in1, LOW);
        digitalWrite(in2, LOW);
      }
      if (buttonPushCounter >=2) {
        digitalWrite(in1, LOW);
        digitalWrite(in2, HIGH);
        analogWrite(enA, 255);
        delay(2000);
        digitalWrite(in1, LOW);
        digitalWrite(in2, LOW);
        buttonPushCounter = 0;
      }
    } else {
      Serial.println("slukket");
    }
    delay(50);
  }
  lastButtonState = buttonState;

delay(10);

}

the thing is that it matters which way the motor runs AFTER i press the pressure plate after the motor has been stopped by one of the limit switches.

You know which way it was running when it triggered the limit switch. If you don't then you should do. So reverse the direction when the pressure plate is pressed to move away from the limit switch.

Are you intending to use only one input to detect reaching either limit ? If so then I foresee problems because when you move after stopping at the limit switch it will still be in the pressed position and will cause the motor to stop again.

I have not yet to build it into the drawer yet. So it could go either way, but i if i got to be honest, i pretty much know which way the motor runs when it hits the limit switches

UKHeliBob: Are you intending to use only one input to detect reaching either limit ? If so then I foresee problems because when you move after stopping at the limit switch it will still be in the pressed position and will cause the motor to stop again.

Im intending on using two different limit switches, one on each side. Which has two different inputs. And to your forseen problem, i have thought of this. My idea was to just make it move just a tiny bit, so the button is unpressed upon stopping. Maybe you have a better solution for this?

Im intending on using two different limit switches, one on each side. Which has two different inputs. And to your forseen problem, i have thought of this. My idea was to just make it move just a tiny bit, so the button is unpressed upon stopping. Maybe you have a better solution for this?

If you are going to use 2 independent limit switches there is no problem

start of loop()
  drawer moving from out to in
    if inner limit switch becomes pressed 
      stop the motor
    end if

  drawer moving from in to out
    if outer limit switch becomes pressed
      stop the motor
    end if

  if pressure plate becomes pressed
    if inner limit switch is currently pressed
      start motor moving outwards
    end if
    else if outer limit switch is currently pressed
      start the motor moving inwards
    end if
  end if
end of loop()

Note that none of the code must be blocking so no delay()s, for instance

Hello.

Thanks for your suggestion.

I do have one problem though. Since i can't use delay, that means my motor runs indefinitely, but i was thinking about using millis() instead. I have researched, but i still have no clue how i would implement it into my own code.

I have used the BlinkWithoutDelay example as a stepping stone, but i am still in doubts. I have tried to implement it, aswell as the two switches.

Problems i have after implementing the two limit switches and trying to implement millis:

  1. Motor runs indefinitely (probably because i have not implemented millis() correctly)
  2. When "buttonPushCounter" = 1, then action1 does not happen anymore. It only detects action2, so only when "buttonPushCounter" = 2.

I might have other issues, but not what i know of.

Code is:

//Konstanter
const int enA = 10;
const int in1 = 9;
const int in2 = 8;
const int buttonPin = 2;
const int endestopPin1 = 3;
const int endestopPin2 = 4;
//Variable
int buttonState = 0;
int buttonPushCounter = 0;
int lastButtonState = 0;

//endestop 1
int endestopState1 = 0;
int lastEndestopState1 = 0;

//Endestop 2
int endestopState2 = 0;
int lastEndestopState2 = 0;

//Delay til motor
unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 2000;


void setup() {
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(enA, OUTPUT);
  pinMode(buttonPin, INPUT);
  pinMode(endestopPin1, INPUT);
  pinMode(endestopPin2, INPUT);
  Serial.begin(9600);
  startMillis = millis();
}




void loop() {
  currentMillis = millis();
  buttonState = digitalRead(buttonPin);
  endestopState1 = digitalRead(endestopPin1);
  endestopState2 = digitalRead(endestopPin2);


  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      buttonPushCounter++;
      Serial.println("tændt");
      Serial.print("Antal tryk på knap: ");
      Serial.println(buttonPushCounter);

      if (buttonPushCounter == 1) {
        digitalWrite(in1, HIGH);
        digitalWrite(in2, LOW);
        analogWrite(enA, 255);
        if (currentMillis - startMillis >= period)
        {
          digitalWrite(in1, LOW);
          digitalWrite(in2, LOW);
          startMillis = currentMillis;
        }
      }
      if (buttonPushCounter == 2) {
        digitalWrite(in1, LOW);
        digitalWrite(in2, HIGH);
        analogWrite(enA, 255);
        if (currentMillis - startMillis >= period)
        {
          digitalWrite(in1, LOW);
          digitalWrite(in2, LOW);
          buttonPushCounter = 0;
          startMillis = currentMillis;
        }
      } else {
        Serial.println("slukket");
      }


    }
    lastButtonState = buttonState;




    if (endestopState1 != lastEndestopState1) {
      if (endestopState1 == HIGH) {
        Serial.println("endestop1 til");
        digitalWrite(in1, LOW);
        digitalWrite(in2, LOW);
      }
    }
    if (endestopState2 != lastEndestopState2) {
      if (endestopState2 == HIGH) {
        Serial.println("endestop2 til");
        digitalWrite(in1, LOW);
        digitalWrite(in2, LOW);
      }
    }
    if (buttonState == HIGH) {
      if (endestopState1 == HIGH) {
        digitalWrite(in1, HIGH);
        digitalWrite(in2, LOW);
      }
      else if (endestopState2 == HIGH) {
        digitalWrite(in1, LOW);
        digitalWrite(in2, HIGH);





      }
    }
  }
}

Compare my pseudo code with your actual code.

Mine is in 3 independent sections (it could be in 2), whereas yours is just about all of your code is inside the test for buttonState being HIGH. It would be easier to see that problem if you Auto Formatted the code in the IDE and put each { and } alone on a line

Your code would be easier to understand if you added some comments or even better put code in well named functions.

For instance, what does

       digitalWrite(in1, LOW);
        digitalWrite(in2, HIGH);
        analogWrite(enA, 255);

do ? If it were in a function named (perhaps) drawerIn() then it would be more obvious. The same goes for the other motor control commands

Your variable names are also anonymous. Why endestopPin1 and endestopState1 when you could use innerStopPin and innerStopState, for instance (could be outer, I can't tell) ? As it is I can't tell from your code what each input does.

On the subject of inputs, how are they wired ? Do you have pulldown resistors in place to keep them at a know state when not activated ? If not then consider using INPUT_PULLUP in pinMode() to activate the built in pullup resistors and change the program logic and wiring to match so that LOW means pressed