One Push Button Trigger 2 Pins

Hello,

Please anyone help me here... :frowning:

I'm trying to trigger 2 Pins Output in different act with single push button.

Here, I set the Pins:
Digital Pin 2 and 3 are OUTPUT
Digital Pin 4 is INPUT

I want the action like:

  • Button pressed for first time, Pin 2 HIGH; then wait for 1000 ms Pin 3 HIGH; then Pin 3 back to LOW in 1000 ms (while Pin 2 still HIGH continuously)

  • Button pressed for second time, Pin 2 LOW.

Thanks.

That sounds like a state machine to me. Combined with millis() timing they are a very powerful tool.

Try this and learn from it.

const byte LED1 = 2;
const byte LED2 = 3;
const byte button = 4;
unsigned long timeStarted;
byte state = 0;
byte currentButtonState;
byte previousButtonState = HIGH;

void setup()
{
  Serial.begin(115200);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(button, INPUT_PULLUP);
}

void loop()
{
  switch (state)  //only execute the code for the current state
  {
    case 0:    //waiting for first button press
      currentButtonState = digitalRead(button);
      if (currentButtonState == LOW && previousButtonState == HIGH)  //button has become pressed
      {
        digitalWrite(LED1, HIGH);
        timeStarted = millis();
        state = 1;
      }
      break;

    case 1:    //wait 1000ms with pin 2 HIGH then turn on LED2
      if (millis() - timeStarted >= 1000)
      {
        digitalWrite(LED2, HIGH);
        timeStarted = millis();
        state = 2;
      }
      break;

    case 2:    //wait 1000ms with both LEDs on then turn off LED2
      if (millis() - timeStarted >= 1000)
      {
        digitalWrite(LED2, LOW);
        state = 3;
      }
      break;

    case 3:    //wait for button to be pressed then turn off LED1 and go back to the start
      currentButtonState = digitalRead(button);
      if (currentButtonState == LOW && previousButtonState == HIGH)  //button has become pressed
      {
        digitalWrite(LED1, LOW);
        state = 0;
      }
      break;
  }
  previousButtonState = currentButtonState;
}

Thank you UKHeliBob,

I've tried it, but when I uploaded the sketch, the trigger on Pin 2 and 3 straight to HIGH (without pressing the button). The output is ok, Pin 2 HIGH; then wait for 1000 ms Pin 3 HIGH; then Pin 3 back to LOW in 1000 ms (while Pin 2 still HIGH continuously). When I pressed the button afterward, it seems loop back again, rather than Pin 2 get LOW.

I did some changes, I just swap around the HIGH and LOW on:

"if (currentButtonState == LOW && previousButtonState == HIGH) //button has become pressed
{"

become :

"if (currentButtonState == HIGH && previousButtonState == LOW) //button has become pressed
{"

to stop the OUTPUT straight to HIGH.

Then, I added "delay(10);" at the end before "previousButtonState = currentButtonState;" to avoid the bouncing when pressing the button.

Thank you so much for the help. I learn more step again... :slight_smile:

How have you got the button wired ?
You will note that in my code I use

pinMode(button, INPUT_PULLUP);

which activates the built in pullup resistor on the pin so we always know that it is HIGH when not pressed and not at some uncertain voltage that the program might regard as LOW or HIGH. When using the internal pullup resistor the circuit should be wired to take the pin LOW when pressed.

Some things to take note of.
When reading the button state it is not good enough to know that the button IS pressed because it may be held down through all of the states so the code checks for the button to BECOME pressed. That way it does not matter if the button remains pressed, the program will not respond until it is pressed again.

Note the comment about how switch/case allows only the code relevant to the current state to run and how the state is updated to make another part of the code run. You can check for multiple actions and exit to different states if you want. The state numbers do not have to proceed linearly.

Using millis() for timing allows the loop() function to run even when timing an event, unlike the delay() function. You could, for instance, flash another LED and still have the program respond to button presses at any time.

Yes Sorry.. I didn't set the button wire as in "pullup resistor", because I wanted it trigger by +5V instead. However, after I swap the "HIGH" to "LOW" and add "delay", it work so fine as what I wanted. Thank you so much.

Then I play a bit more of it. I put more buttons but the output still 2 pins. I was thinking if I can make different output action by selecting each button. I set 6 button input. The result was fine and it worked, even though the sketch is too long. I don't know how to compact it become simple sketch. So, I just add multiple process with different action on each. You may look at below...
by the way, how to make a page for source like you did?

anyway, I just copy it to here then... sorry if it make long text..

const byte in1 = 2;
const byte in2 = 3;
const byte in3 = 4;
const byte in4 = 5;
const byte in5 = 6;
const byte in6 = 7;
const byte outE1 = 8;
const byte outE2 = 9;
const int led = 10;

unsigned long timeStarted;
byte state1 = 0;
byte currentButtonState1;
byte previousButtonState1 = HIGH;

byte state2 = 0;
byte currentButtonState2;
byte previousButtonState2 = HIGH;

byte state3 = 0;
byte currentButtonState3;
byte previousButtonState3 = HIGH;

byte state4 = 0;
byte currentButtonState4;
byte previousButtonState4 = HIGH;

byte state5 = 0;
byte currentButtonState5;
byte previousButtonState5 = HIGH;

byte state6 = 0;
byte currentButtonState6;
byte previousButtonState6 = HIGH;

//For LED Standby Pin 10
int ledMODE0 = 1;
//For LED Blinking Pin 10
int ledMODE1 = 0;
int ledState = HIGH;
long previousMillis = 0;
long interval = 100;

void setup()
{
Serial.begin(115200);
pinMode(outE1, OUTPUT);
pinMode(outE2, OUTPUT);
pinMode(led, OUTPUT);
pinMode(in1, INPUT);
pinMode(in2, INPUT);
pinMode(in3, INPUT);
pinMode(in4, INPUT);
pinMode(in5, INPUT);
pinMode(in6, INPUT);
}

void loop()
{
//------------------Switch Select 1 - START
switch (state1) //only execute the code for the current state 1
{
case 0: //waiting for first button press
currentButtonState1 = digitalRead(in1);
if (currentButtonState1 == HIGH && previousButtonState1 == LOW) //button1 has become pressed
{
digitalWrite(outE1, HIGH);
ledMODE1 = 1;
timeStarted = millis();
state1 = 1;
}
break;

case 1: //wait 1000ms to Turn OFF
if (millis() - timeStarted >= 300)
{
digitalWrite(outE1, LOW);
timeStarted = millis();
state1 = 2;
}
break;

case 2: //wait 1000ms to Turn OFF
if (millis() - timeStarted >= 200)
{
digitalWrite(outE1, HIGH);
timeStarted = millis();
state1 = 3;
}
break;

case 3: //wait 1000ms to Turn OFF
if (millis() - timeStarted >= 500)
{
digitalWrite(outE1, LOW);
ledMODE1 = 0;
timeStarted = millis();
state1 = 0;
}
break;
}
delay(20);
previousButtonState1 = currentButtonState1;
//--------------------------------------------//----------------------------------------------

//------------------Switch Select 2 - START---------------------------------------------------
switch (state2) //only execute the code for the current state 2
{
case 0: //waiting for first button press
currentButtonState2 = digitalRead(in2);
if (currentButtonState2 == HIGH && previousButtonState2 == LOW) //button2 has become pressed
{
digitalWrite(outE1, HIGH);
ledMODE1 = 1;
timeStarted = millis();
state2 = 1;
}
break;

case 1: //wait 1500ms to Turn OFF
if (millis() - timeStarted >= 1500)
{
digitalWrite(outE1, LOW);
ledMODE1 = 0;
timeStarted = millis();
state2 = 0;
}
break;
}
delay(20);
previousButtonState2 = currentButtonState2;
//--------------------------------------------//----------------------------------------------

//------------------Switch Select 3 - START---------------------------------------------------
switch (state3) //only execute the code for the current state 3
{
case 0: //waiting for first button3 press
currentButtonState3 = digitalRead(in3);
if (currentButtonState3 == HIGH && previousButtonState3 == LOW) //button3 has become pressed
{
digitalWrite(outE1, HIGH);
ledMODE1 = 1;
timeStarted = millis();
state3 = 1;
}
break;

case 1: //wait 2000ms to Turn OFF
if (millis() - timeStarted >= 2000)
{
digitalWrite(outE1, LOW);
ledMODE1 = 0;
timeStarted = millis();
state3 = 0;
}
break;
}
delay(20);
previousButtonState3 = currentButtonState3;
//--------------------------------------------//----------------------------------------------

//------------------Switch Select 4 - START---------------------------------------------------
switch (state4) //only execute the code for the current state 4
{
case 0: //waiting for first button4 press
currentButtonState4 = digitalRead(in4);
if (currentButtonState4 == HIGH && previousButtonState4 == LOW) //button4 has become pressed
{
digitalWrite(outE1, HIGH);
ledMODE1 = 1;
timeStarted = millis();
state4 = 1;
}
break;

case 1: //wait 2500ms to Turn OFF
if (millis() - timeStarted >= 2500)
{
digitalWrite(outE1, LOW);
ledMODE1 = 0;
timeStarted = millis();
state4 = 0;
}
break;
}
delay(20);
previousButtonState4 = currentButtonState4;
//--------------------------------------------//----------------------------------------------

//------------------Switch Select 5 - START---------------------------------------------------
switch (state5) //only execute the code for the current state 5
{
case 0: //waiting for first button5 press to Turn ON
currentButtonState5 = digitalRead(in5);
if (currentButtonState5 == HIGH && previousButtonState5 == LOW) //button5 has become pressed
{
digitalWrite(outE1, HIGH);
ledMODE1 = 1;
timeStarted = millis();
state5 = 1;
}
break;

case 1: //waiting for first button5 press to Turn OFF
currentButtonState5 = digitalRead(in5);
if (currentButtonState5 == HIGH && previousButtonState5 == LOW) //button5 has become pressed
{
digitalWrite(outE1, LOW);
ledMODE1 = 0;
timeStarted = millis();
state5 = 0;
}
break;
}
delay(20);
previousButtonState5 = currentButtonState5;
//--------------------------------------------//----------------------------------------------

//------------------Switch Select 6 - START---------------------------------------------------
switch (state6) //only execute the code for the current state 6
{
case 0: //waiting for first button6 press
currentButtonState6 = digitalRead(in6);
if (currentButtonState6 == HIGH && previousButtonState6 == LOW) //button6 has become pressed
{
digitalWrite(outE1, HIGH);
ledMODE1 = 1;
timeStarted = millis();
state6 = 1;
}
break;

case 1: //wait 1000ms with pin 2 HIGH then turn on out2
if (millis() - timeStarted >= 1000)
{
digitalWrite(outE2, HIGH);
timeStarted = millis();
state6 = 2;
}
break;

case 2: //wait 1000ms with both outs on then turn off out2
if (millis() - timeStarted >= 1000)
{
digitalWrite(outE2, LOW);
state6 = 3;
}
break;

case 3: //wait for button to be pressed then turn off out1 and go back to the start
currentButtonState6 = digitalRead(in6);
if (currentButtonState6 == HIGH && previousButtonState6 == LOW) //button6 has become pressed
{
digitalWrite(outE1, LOW);
ledMODE1 = 0;
state6 = 0;
}
break;
}
delay(20);
previousButtonState6 = currentButtonState6;
//--------------------------------------------//----------------------------------------------

//LED Indicator Status------------------------------------------------------------------------
// StandBy LED ON
if(ledMODE0 == 1)
{
digitalWrite(led, HIGH);
}

// Blinking LED State Led Pin 10
unsigned long currentMillis = millis();
if(ledMODE1 == 1)
{
if(currentMillis - previousMillis > interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;

// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
digitalWrite(led, ledState);
}
}
}

Any idea?

Thanks.

how to make a page for source like you did?

That's the easy bit. Paste in the code, select it then click the seventh icon from the right above the smileys in the editor.

As to making your code smaller, I notice that you have many variables where the name only differs from others by the numerical suffix. That usually means that you could hold the state of the variables in arrays and access them using the array index. Use the value of the loop variable in a for loop as the array index and you only need one set of code to process them all.

Even as it stands you have many repeated lines of code which you could turn into functions and call with parameters to allow them to use the variables relevant to the current situation.

There are few things you can do to make your code "compact".

It may look strange at first, but...

  1. if(condition)
    evaluates the condition as true of false, hence
    if(button == HIGH) or
    if(button) are equivalent

  2. if( previous == HIGH && current == LOW )
    can be replaced with
    if(previous exclusive OR current) - true only when previous HIGH and current LOW or previous LOW and current HIGH

  3. Replace "common" code using function, same as digitalWrite(led, ledState); does for you. I prefer to start "internally", inside out.

For example you can replace this simple code with function :

// StandBy LED ON
if(ledMODE0 == 1)
{
digitalWrite(led, HIGH);
}

int TurnLED( int LEDxState, int LEDxPin, boolean bOnOff) )
{
if(LEDxState) // check LED state
{
digitalWrite(LEDxPin,bOnOff); // set / reset LED
}
retrun LEDxState;
}

The key is to write code comments and function description and its parameters description

// TurnLED check the LED state and sets / reset LED
// input parameters LEDxState current state of LED
// LEDxPin LED I/O pin number
// bOnOff false turn LED off, true turn LED on
// output returns current state of LED

Good luck.

PS Before some " guru" complains - the above function example is not logically all together - just an example!

@UKHeliBob, thanks for the simple bit.. I want to try it, :smiley:

//  StandBy LED ON
 if(ledMODE0 == 1)
 {
   digitalWrite(led, HIGH);
 }

Ahh.. yesss I can do it now.. great..

I don't have programming background. I just learned from books and search on web to make something I like with Arduino. That's way, about the code, yes I just use the name only differs from others by the numerical suffix.

Anyway, about what you're saying,

Use the value of the loop variable in a for loop as the array index and you only need one set of code to process them all.

I don't really understand about it. Is there any examples? :smiley:

Thanks once again.


@Vaclav, Thanks for the example.. It worth to try.. :slight_smile:

Here is an example using arrays to control 2 LED sequences using arrays based on my original code

const byte ledPinA[] = {2, 8};
const byte ledPinB[] = {3, 9};
const byte buttonPin[] = {4, 10};
unsigned long timeStarted[2];
byte state[] = {0, 0};
byte currentButtonState[2];
byte previousButtonState[] = {HIGH, HIGH};
unsigned long waitA[] = {1000, 1500};
unsigned long waitB[] = {1000, 2000};
byte numberOfSequences = sizeof(state) / sizeof(state[0]);

void setup()
{
  Serial.begin(115200);
  for (int x = 0; x < numberOfSequences; x++)
  {
    pinMode(ledPinA[x], OUTPUT);
    pinMode(ledPinB[x], OUTPUT);
    pinMode(buttonPin[x], INPUT_PULLUP);
  }
}

void loop()
{
  for (int index = 0; index < numberOfSequences; index++)
  {
    switch (state[index])  //only execute the code for the current state
    {
      case 0:    //waiting for first button press
        currentButtonState[index] = digitalRead(buttonPin[index]);
        if (currentButtonState[index] == LOW && previousButtonState[index] == HIGH)  //button has become pressed
        {
          digitalWrite(ledPinA[index], HIGH);
          timeStarted[index] = millis();
          state[index] = 1;
        }
        break;

      case 1:    //wait 1000ms with pin 2 HIGH then turn on LED2
        if (millis() - timeStarted[index] >= waitA[index])
        {
          digitalWrite(ledPinB[index], HIGH);
          timeStarted[index] = millis();
          state[index] = 2;
        }
        break;

      case 2:    //wait 1000ms with both LEDs on then turn off LED2
        if (millis() - timeStarted[index] >= waitB[index])
        {
          digitalWrite(ledPinB[index], LOW);
          state[index] = 3;
        }
        break;

      case 3:    //wait for button to be pressed then turn off LED1 and go back to the start
        currentButtonState[index] = digitalRead(buttonPin[index]);
        if (currentButtonState[index] == LOW && previousButtonState[index] == HIGH)  //button has become pressed
        {
          digitalWrite(ledPinA[index], LOW);
          state[index] = 0;
        }
        break;
    }
    previousButtonState[index] = currentButtonState[index];
  }
}

Its major flaw is that it uses the same LED/button sequences, only the timing is changed. This too could be overcome overcome by putting the state to move to from the current one in array then each sequence would not need to be the same and each sequence would not need to use the same states in the same order.

Great.. Thank you so much.. Now I have more knowledge for this case.

I have another issues with ethernet shield project. Can I share it here or I have to make new subject for it?

It would be better to start a new thread so that the title is relevant to the problem.

Alright then.. Thanks.