one button 3 relay sequencer

hi everyone. i super new to arduino
im trying to build a one dry contact button that when you push it once it will fire relay 1 for 2 sec
then when you push the button again it will fore relay 2 for 2 sec
then when you hit the button again it will fire relay 3 for 2 sec
and when you hit the button again it will go back to relay 1
then rinse and repeat forever.
i would love some code help on this
thanks

For now, replace the relays with LED and resistors to see what happens. Have you tried the example programs?

Paul

You can do this with varying degrees of “sophistication”. The simplest (and least sophisticated) is to use the often maligned delay() between digitalWrite()s to high and low for on and off. (Your relays may be the ones that need a low for on and high for off, though.)

So you use a while() to sit and do nothing while waiting for a switch press, then do the on for relay A, delay and off. Copy and paste that code editing as required for the pin for relay B and C.

The Arduino loop() will take care of getting back to relay A after relay C.

I have written such code if you want it. (Will only post if you ask, in case you would rather press on by yourself.)

It’s simple and ugly, but does the trick.

elvon. help with code would be super helpful thank you.

Get comfortable with the first five sketches in IDE/file/examples/digital. After you've got debouncing and INPUT_PULLUP down add state change detection to toggle the onboard LED. Then increment a count variable. That'll get you most of the way there.

Also, don't miss doing several things at the same time.

i would love some code help on this

The way this forum works is that you try something, and if you run into difficulties, post the code (using code tags) and explain the problem.

See "How to use this forum" for the details.

You can also post on the "Gigs and Collaborations" section, but be prepared to pay for the help.

jremington:
The way this forum works is that you try something, and if you run into difficulties, post the code (using code tags) and explain the problem.

That's not strictly true. It's actually a common practice from what I see, for people to post turnkey code with no previous input from the op. It's anyone's prerogative to do that.

I have offered the op my code (although I didn't post it until he or she asked) and here it is.

There's a huge catch with this code, and that is it relies on you (@op) having told us the complete picture. It's simple unsophisticated code which is completely blocking. It blocks while waiting for the switch press. I blocks during the delays. So if there's anything else supposed to be happening (like maybe waiting for the press of a different button, or the blinking of a led to show the sketch is running) that cannot readily be added to this sktech.

One part needs explanation. You will see these lines:

pinMode(switchPin, INPUT_PULLUP); //wire switch from pin to ground

As the comment says, wire the switch from the pin to ground. The internal pullup resistor will hold the pin high; a press will take it low. That might seem back to front, but is a very common way to do things.

And this:

while(digitalRead(switchPin)){} //wait for press

This says while the switchPin is high (that is, not pressed, as just explained) do nothing. (Note the {} with nothing inside.) Then if the pin becomes low, ie pressed, exit the while and go to the next line.

This simple approach doesn't need debouncing; the 2 second delay is basically a long debounce. Soon as the pin goes low, the while is exited, and the pin isn't checked again until 2s has passed. If the switch bounces for 2s it's time to stomp on it.

Here's the code. If @op you want it to be made more sophisticated, you will need to come to terms with all the things in post #4.

//very very ugly code for forum thread 599195
// totally blocking :(

byte relayA = 14; //tested with leds
byte relayB = 15;
byte relayC = 16;
byte switchPin = 4; //wire switch from pin to ground

void setup()
{
  pinMode(relayA, OUTPUT);
  pinMode(relayB, OUTPUT);
  pinMode(relayC, OUTPUT);
  pinMode(switchPin, INPUT_PULLUP); //wire switch from pin to ground

  //turn off L13
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

} //setup

void loop()
{
while(digitalRead(switchPin)){} //wait for press
digitalWrite(relayA, HIGH); //assumes high is on; your relays may be low on, high off
delay(2000); 
digitalWrite(relayA, LOW); //assumes low is off

while(digitalRead(switchPin)){} //wait for press
digitalWrite(relayB, HIGH);
delay(2000);
digitalWrite(relayB, LOW);

while(digitalRead(switchPin)){} //wait for press
digitalWrite(relayC, HIGH);
delay(2000); 
digitalWrite(relayC, LOW);
} //loop

There is nothing intrinsically wrong with code that blocks, provided the user is aware that adding functionality later is likely to be tricky, and may well require a change of mindset to non-blocking code.

If @op in the back of your mind you anticipate needing to do more things in your sketch, I would urge that you not become too attached to doing it this way and rather:

dougp:
... don't miss doing several things at the same time.

It's actually a common practice from what I see, for people to post turnkey code with no previous input from the op.

Yes, sometimes that happens, and as you will find those contributions very often go ignored.

New forum members should not be encouraged to expect ready made solutions to their problems.

thank for the starter code. it really helps me . i have done almost zero code in my life so far and im just trying to come up with something better than what i was using before. and i think this little arduino is the key.
thanks again for the code and you input. i hope to learn a lot from this forum

What you put into it, you will get out of it.

superspencedog:
thank for the starter code. it really helps me .

You're welcome, but take heed of what I said about that sketch.

It's not readily scaleable; if you want you sketch to get much more sophisticated your coding will need sophistication as well, as in #4 above. In fact you should probably aim for that kind of coding anyway.

Elvon’s code is a great place to start but I agree with him: don’t get too used to the get-out-of-jail-free “delay()” card. Used for more than a few mS at a time it can really screw up other things you might want to do.

This is an example of a non-blocking method of timing. “Proof” is given by the blinking LED, showing the micro is able to timing quick blinks of the LED while the timing of relays goes on the back ground.

Kind of neat about this code is that it allows you to turn on the 2nd and 3rd LEDs while the first is still on and they will all dutifully shut off after their 2-sec period.

It’s more complicated for sure than the blocking example but the techniques used pay dividends when your projects become more complex.

//very very ugly code for forum thread 599195
// that doesn't use blocking

#define RELAY_CLOSE     LOW
#define RELAY_OPEN      HIGH

byte relayA = 14;       //tested with leds
byte relayB = 15;
byte relayC = 16;
byte switchPin = 4;     //wire switch from pin to ground

//create an array we use to easily select which relay we want to drive
const byte grRelays[] =
    {
        relayA,
        relayB,
        relayC    
    };

//these two arrays hold the information for the relays
//  - on or off (relayState)
//  - the system millis() count when the relay was turned on
bool 
    grrelayState[3];
unsigned long
    grtimeRelay[3];

//lastSwitch is used to know when a switch was depressed (vs "is" depressed)
byte
    lastSwitch;

//index is used to keep track of which relay we're working with each 
//press of the button
byte
    Index;
        
void setup()
{
    //use the array to set up...
    for( int i=0; i<3; i++ )
    {
        //...the pin outputs to be in the "open" state...
        digitalWrite( grRelays[i], RELAY_OPEN );
        //...set the pins to be outputs...
        pinMode( grRelays[i], OUTPUT );
        //and initialize the state and time arrays
        grrelayState[i] = false;
        grtimeRelay[i] = 0;
        
    }//for

    //start with relay '0'
    Index = 0;

    //set up the switch input as pull-up
    pinMode(switchPin, INPUT_PULLUP);       //wire switch from pin to ground
    //read the switch now to set the "lastSwitch" variable
    lastSwitch = digitalRead( switchPin );
    
    //set up the built-in LED'
    //part of this demo is to blink the LED while the other stuff is 
    //going on to demonstrate doing multiple things at once
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, LOW);
    
} //setup

void loop()
{
    //instead of having everything in loop, break the basic functions out into their
    //own routines
    ReadSwitch();
    TimeRelay();

    BlinkTheLED();
    
}//loop

void BlinkTheLED( void )
{
    //this just turns the built-in LED on and off at ~300mS intervals
    //static variables mean they don't go away when the function ends;
    //next time in, the variables are still there and have their old values
    //very useful for keeping track of, say, whether the LED is on or off
    static bool
        stateLED = false;
    static unsigned long
        timeLED = 0;
    unsigned long
        timeNow;

    //check the difference between the millis count now and what it was when we changed
    //state. If it's less than 300mS, just leave...
    timeNow = millis();
    if( (timeNow - timeLED) <  300 )
        return;
    //it's been 300mS or more so make the millis time now the "old time" and toggle the LED state
    timeLED = timeNow;

    //not the shortest code syntax to do this but clear;
    //if the LED is off now, turn it on and vice-versa
    if( stateLED == false )
    {
        stateLED = true;
        digitalWrite( LED_BUILTIN, HIGH );
    
    }//if
    else
    {
        stateLED = false;
        digitalWrite( LED_BUILTIN, LOW );
        
    }//else
    
}//BlinkTheLED

void ReadSwitch( void )
{
    byte
        swRead;
    static unsigned long
        timeSwitch = 0;

    //read the switch every 50mS
    if( millis() - timeSwitch < 50 )
        return;
    timeSwitch = millis();

    swRead = digitalRead( switchPin );
    //if the current read does not equal the last read, something changed...
    if( swRead != lastSwitch )
    {
        //make this the new "last"...
        lastSwitch = swRead;
        //did we read low? If so, it means the switch went from high last time to low this time
        //meaning it was pressed
        if( swRead == LOW )
        {
            //turn on the next relay indicated by Index
            digitalWrite( grRelays[Index], RELAY_CLOSE );
            //set its state to "true"
            grrelayState[Index] = true;
            //and grab the millis count when we closed it
            grtimeRelay[Index] = millis();

            //now we can bump the index; when we run out of LEDs go back to zero
            Index++;
            if( Index == 3 )
                Index = 0;
            
        }//if
        
    }//if
    
}//ReadSwitch

void TimeRelay( void )
{
    //check all three relays
    for( int i=0; i<3; i++ )
    {
        //is this one on?
        if( grrelayState[i] == true )
        {
            //...yes; is it time to turn it off?
            if( (millis() - grtimeRelay[i]) >= 2000 )
            {
                //yes; turn it off and clear the flag
                digitalWrite( grRelays[i], RELAY_OPEN );
                grrelayState[i] = false;
                
            }//if
            
        }//if
        
    }//if

}//TimeRelay

blackfin i also like your code it will keep from cycling if the input is just help down, but i dont want relay 2 and 3 to fire until the previous relay is has timed out.
i am running large automatic doors in a house and if i were to fire all the relays at once it would confuse the door control.
but blakfins code and elvons code is far superior to anything i have been able to write. but thats how you learn and thank you two again.