Pushbutton (run - stop - reverse - stop)

Hi all, I need help on a project whereby curtain of my house's sun roof should be opened and closed using a pushbutton. I already have built and installed the mechanical stuff. It works just fine. I need to use Arduino to control that as follows: 1- Pushbutton is momentarily pressed, LED attached to pin 4 goes HIGH, preferably for some time, say 30Sec. 2- Pushbutton is pressed again, LED4 goes LOW. 3- Pushbutton is pressed again, another LED attached to pin5 (NOT 4) goes HIGH, preferably for about 30Sec. (this step for reversing the motor) 4- Pushbutton is pressed again, LED5 goes LOW. That will help me controlling the motor as: RUN – STOP – REVERSE – STOP. My main difficulty is with the 3rd step where pressing the pushbutton should not turn the LED attached to pin 4 on again. Instead, LED5 attached to pin 5 should turn on to reverse the motor.

Any help would be appreciated!

There are two parts to your problem. First is detecting when the button is pressed. Second is deciding on what to do when the button is pressed.

Which one do you need help with?

If it's the second part, that's pretty simple. You just need to count the button presses, and do something based on the count: if(buttonPressed) { count++; }

switch(count%4) { case 0: // Do something - turn on pin 4 break; case 1: // Do something - turn off pin 4 break; case 2: // Do something - turn on pin 5 break; case 3: // Do something - turn off pin 5 break; }

Add delays (or, better yet, use millis() and record when the last action occurred) as required.

So you can already toggle the motor on and off with the button?

If so, it's a simple thing to add a reverse mode.

The way I would do it (the option you would choose may differ, I don't know how your code works) is to have a boolean variable to store the direction of the motor. click If direction == true, go forward; direction = true Else go backward; direction = false click Stop

So every time the motor should be turned on, it checks whether last time it went forward or back, then moves accordingly and toggles the direction variable.

There may be better solutions depending on your code, though. [edit]Whopops! Someone beat me.

PS shouldn't the line that increments counter be changed to: counter = (counter++)%4 I feel like that would be better so that the variable isn't always increasing.[/edit]

Thank you guys for your response! Yes, Pauls. The second part relating to counting presses is what I have a difficulty with. The code I am trying to modify is one of the examples provided by Arduino. I am not good enough at doing such a modification to match my needs. So, your help would be much appreciated!

Sciguy, It's more practical for me to use two Rlys for controlling the motor's direction.

Here is the code I need to modify:

int inPin = 7; // the number of the input pin
int outPin1 = 13; // the number of the output1 pin
int outPin2 = 12; // the number of the output2 pin
int state1 = LOW; // the current state of the output1 pin
int state2 = LOW; // the current state of the output2 pin
int reading; // the current reading from the input pin
int previous = LOW; // the previous reading from the input pin
// the follow variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long time = 0; // the last time the output pin was toggled
long debounce = 100; // the debounce time, increase if the output flickers
void setup()
{
pinMode(inPin, INPUT);
pinMode(outPin1, OUTPUT);
pinMode(outPin2, OUTPUT);
}
void loop()
{
reading = digitalRead(inPin);
// if the input just went from LOW and HIGH and we've waited long enough
// to ignore any noise on the circuit, toggle the output pin and remember
// the time
if (reading == HIGH && previous == LOW && millis() - time > debounce) {
if (state1 == HIGH)
state1 = LOW;
else
state1 = HIGH;
time = millis();
}
digitalWrite(outPin1, state1);
previous = reading;
}

thanks a lot!

In that code, you are toggling the output pin every time a button is pressed. Add a global variable:

int pressCount = 0;

Then, where you call the digitalWrite function, add:

pressCount++;

Your code, with proper indenting and some optimization will end up looking like this:

void loop()
{
  reading = digitalRead(inPin);
  if (reading == HIGH &&
      previous == LOW &&
      millis() - time > debounce)
  {
    state1 = !state1; // Toggle the state
    pressCount++;
    time = millis();

    switch(pressCount%4)
    {
      case 0:
        // Turn on 1st pin
        break;
      case 1:
        // Turn off 1st pin
        break;
      case 2:
        // Turn on 2nd pin
        break;
      case 3:
        // Turn off 2nd pin
        break;
    }
  }
  previous = reading;

  digitalWrite(outPin1, state1);
}

... run - stop - reverse - stop ... . Any help would be appreciated!

It's simple - you need an "E" unit from a Lionel train.

Don

Thank you guys for your help! Thx PaulS for the code, it works very well!!! This is gonna be very helpful to me in many projects I work on. However, it would be even better if I can set a time for each LED, say 30sec, so that it turns off after that time even if pushbutton is not pressed. And if pushbutton is pressed during that time, the LED should also turn off. I tried (delay) but it did not work because Arduino doesn't response during the delay, which means I can't turn the LED off unless the set time passes.

int inPin = 7; // the number of the input pin
int outPin1 = 13; // the number of the output1 pin
int outPin2 = 12; // the number of the output2 pin
int state1; // the current state of the output1 pin
int reading; // the current reading from the input pin
int previous = LOW; // the previous reading from the input pin
long time = 0; // the last time the output pin was toggled
long debounce = 200; // the debounce time, increase if the output flickers
int pressCount = 1; 
void setup()
{
pinMode(inPin, INPUT);
pinMode(outPin1, OUTPUT);
pinMode(outPin2, OUTPUT);
}
void loop()
{
reading = digitalRead(inPin);
if (reading == HIGH && previous == LOW && millis() - time > debounce) 
{
state1 = !state1; // Toggle the state
pressCount++;
time = millis();

switch(pressCount%4)
 {
      case 0:
digitalWrite(outPin1, HIGH);        // Turn on 1st pin
        break;
      case 1:
digitalWrite(outPin1, LOW);        // Turn off 1st pin
        break;
      case 2:
digitalWrite(outPin2, HIGH);        // Turn on 2nd pin
        break;
      case 3:
digitalWrite(outPin2, LOW);        // Turn off 2nd pin
        break;
    }
  }
  previous = reading;
  }

The switch statement is executed every time there is a button press, but reading the button press happens every pass through loop.

What you could do is add a global boolean variable, buttonPressed, initially set to false:

boolean buttonPressed = false;

Then, set button pressed to true when the button is pressed, where the state = !state; statement is now. The state variable is no longer used, is it?

Then move the switch statement. It is currently in the block that tests if a button is pressed. After that block, create another if block:

if(buttonPressed)
{
   // switch statement goes here
   buttonPressed = !buttonPressed;
}

After doing this, the code should act exactly like it does today, but now we are set up to change it. What we want to do is simulate a button press after 30 seconds, unless a real one was received. To do that, you need to record when the pin last changed state (using a global variable, setting it in the if(buttonPressed) block.

On each pass through loop, check if now minus then is greater than some value (you mentioned 30 seconds). If it is, set buttonPressed to true. On the next pass through loop, buttonPressed will be true, even though no physical button press occurred. You'll probably only want to simulate a button press while a motor is running. You probably don't want to exit a stopped state automatically.

I'll leave it to you to try to implement this. If you have questions or difficulties, come on back. Your money will be cheerfully refunded.