Multiple tasks one single button

Hello, community. I am trying to run a program in Arduino so one single button can make a led and a dc motor run for five seconds when clicked once. And then run for 10 seconds when clicked two times. And finally, to have it run indefinitely as long as it is been hold down.
The problem I have is that the led and motor will run for five seconds when I press the button once, but if I push it two times it will run for ten seconds, which is fine, but it doesn't respond correctly just because I pushed two times, it will do 5 seconds, and the 10 seconds, and then 5 seconds, and then 10 seconds, and so on. It won't respond to the command of two clicks 10 seconds, or 1 click, 5 second.

int buttonPin = 2;      // button connected to digital pin 2
int ledPin = 0;         // LED connected to digital pin 0
int motorPin = 1;       // motor connected to digital pin 1
int buttonState = 0;    // variable to store button state
int buttonPresses = 0;  // variable to store number of button presses

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(motorPin, OUTPUT);
}

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

  if (buttonState == HIGH) {
    buttonPresses++;
    delay(200);  // debouncing delay to avoid multiple counts for one button press
  }

  // if button pressed once, run LED and motor for 5 seconds
  if (buttonPresses == 1) {
    digitalWrite(ledPin, HIGH);
    digitalWrite(motorPin, HIGH);
    delay(5000);
    digitalWrite(ledPin, LOW);
    digitalWrite(motorPin, LOW);
  }

  // if button pressed twice, run LED and motor for 10 seconds
  if (buttonPresses == 2) {
    digitalWrite(ledPin, HIGH);
    digitalWrite(motorPin, HIGH);
    delay(10000);
    digitalWrite(ledPin, LOW);
    digitalWrite(motorPin, LOW);
    buttonPresses = 0;  // reset buttonPresses after second press
  }
}

This is not a very reliable way to debounce and count button presses, because it starts the delay() the instant the button is pressed, and does not sample the button while delay() is being executed.

  if (buttonState == HIGH) {
    buttonPresses++;
    delay(200);  // debouncing delay to avoid multiple counts for one button press
  }

There are button libraries and tutorials that discuss techniques for more control over counting, distinguishing short and long press, etc. Search phrase something like "arduino button library".

Take a look at the Arduino State Change Detection example to learn how to detect when a button "becomes pressed", and act accordingly. Files>Examples>02.Digital>StateChangeDetection

Thanks for the advice. I'll look for some more info regarding this specific function.

delay() is evil, makes you sit and spin..
look at blink without delay sample.
need to have some counters, intervals and use millis().

Another suggestion: drop the motor and use just the LED for testing button strategies.

Okay, that sounds like a good approach.

consider (not so simple handling button being held down)

#define MyHW
#ifdef MyHW
int buttonPin = A1;
int ledPin    = 13;
int motorPin  = 12;

#else
int buttonPin = 2;      // button connected to digital pin 2
int ledPin = 0;         // LED connected to digital pin 0
int motorPin = 1;       // motor connected to digital pin 1
#endif

byte butLst;

enum { ST_Idle, ST_5sec, ST_10sec };
int  state;

unsigned long msecPeriod;
unsigned long msecLst;

enum { Off = HIGH, On = LOW };

// -----------------------------------------------------------------------------
void setLedMotor (
    byte  onOff )
{
    digitalWrite (ledPin,   onOff);
    digitalWrite (motorPin, onOff);
}

// -----------------------------------------------------------------------------
void loop ()
{
    unsigned long msec = millis ();
    if (msecPeriod && msec - msecLst >= msecPeriod)  {
        state = ST_Idle;
        msecPeriod = 0;
        setLedMotor (Off);
        Serial.println ("timout");
    }

    byte but = digitalRead (buttonPin);
    if (butLst != but)  {
        butLst = but;
        delay (20);     // debounce

        if (LOW == but) {
            switch (state)  {
            case ST_Idle:
                state = ST_5sec;
                setLedMotor (On);
                msecLst    = msec;
                msecPeriod = 5000;
                Serial.print ("5sec  ");
                break;

            case ST_5sec:
                msecPeriod = 10000;
                Serial.print ("10sec ");
                break;
            }

            Serial.println (msecPeriod);
        }
        else {                  // release from being held down
            if (ST_Idle == state)
                setLedMotor (Off);
        }
    }

    if (LOW == but)
        setLedMotor (On);
}

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

    pinMode (buttonPin, INPUT_PULLUP);   // button between pin/gnd
    butLst = digitalRead (buttonPin);

    pinMode (ledPin,   OUTPUT);
    pinMode (motorPin, OUTPUT);

    setLedMotor (Off);
}

Thanks, I'll give it a try.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.