Control 2 Relays with 3 Buttons

Hello Folks,

After spending almost a half day thinking what should be the logic and trying couple of codes without sucess I decide to search for a support here for my case.

I need to control 2 relays with 3 buttons.
The tricky part of the logic is:

Initial state of the relays shall be OFF after power on.
ONLY Relay1 or Relay2 can be ON at the same time.
Double press of the button doesn't change the relay conditions

If Button1 is pressed Relay1 shall became ON
If Button2 is pressed Relay1 shall became OFF
If button3 is pressed Relay2 shall became ON
If Button2 is pressed Relay2 shall became OFF

So in summary Relay1 and Relay2 have separate buttons for ON and share one button for OFF.

In addition -> In most schematic decisions the Buttons are connected between Digital pins and ground. I have test couple of codes using this approach, but I observe spontaneously OFF and ON without button interuption. In couple of other sites I see approaches using Push up resistors, so the digital pin is not"flying" during off condition of the button. Can you recommend a reliable solution which have a stable opearation.

Thank you for support in advance!


pinMode(pinNumber, INPUT_PULLUP);

Wire it up with some LEDs to test it to see if you have your logic right.
If you want only one relay on at a time, you should just set the other relay to off when you turn one on. So pressing button 1 or 3 will turn on the respective relay and turn the other off.

Not sure if this works (too lazy to wire something up) but it should give you something to work with:

const byte pinSw1;              //pins for the switches
const byte pinSw2;
const byte pinSw3;

const byte pinRly1;             //pins controlling the relays
const byte pinRly2;

#define RLY_OFF     HIGH        //on/off states for the relays (change as needed to suit your wiring)
#define RLY_ON      LOW

    lstSw1,     //holds the "last" value of switch 1
    lstSw2,     //holds the "last" value of switch 2
    lstSw3;     //holds the "last" value of switch 3

void setup( void )
    //setup the switch inputs as "INPUT_PULLUP"; switch should ground pin
    //when closed
    pinMode( pinSw1, INPUT_PULLUP );
    pinMode( pinSw2, INPUT_PULLUP );
    pinMode( pinSw3, INPUT_PULLUP );    
    //setup the relay control pins and make sure they're off
    pinMode( pinRly1, OUTPUT );
    digitalWrite( pinRly1, RLY_OFF );
    pinMode( pinRly2, OUTPUT );
    digitalWrite( pinRly2, RLY_OFF );

    //establish the initial "last" state of the switches with a read in setup()
    lstSw1 = digitalRead( pinSw1 );
    lstSw2 = digitalRead( pinSw2 );
    lstSw3 = digitalRead( pinSw3 );

void loop( void )
    static unsigned long
        timeReadSw = 0;

    //update the switches every 50mS
    if( millis() - timeReadSw > 50 )
        timeReadSw = millis();

        //if switch 1 has transitioned high to low (become pressed) turn on relay 1
        //if relay is already on, this will have no effect (relay stays on)
        if( ReadSwitch( &pinSw1, &lstSw1 ) )
            digitalWrite( pinRly1, RLY_ON );

        //if switch 3 has transitioned high to low (become pressed) turn on relay 2
        //if relay is already on, this will have no effect (relay stays on)
        if( ReadSwitch( &pinSw3, &lstSw3 ) )
            digitalWrite( pinRly2, RLY_ON );

        //if switch 2 has transitioned high to low (become pressed) turn off both relays
        //if one is already off, this is a "don't care" operation
        if( ReadSwitch( &pinSw2, &lstSw1 ) )
            digitalWrite( pinRly1, RLY_OFF );
            digitalWrite( pinRly2, RLY_OFF );

//to save space, this one functions allows reading of all three switches
//we send pointers to the pin to read and the variable holding the last
//value of that switch from loop
bool ReadSwitch( byte *pin, byte *last )

    //read the pin pointed to by the parameter "pin"
    currSw = digitalRead( *pin );
    //if the read is different from the value stored in the variable pointed to by "last"...
    if( currSw != *last )
        //make last the new value
        *last = currSw;
        //if the reading is now low, a transition from high to low occurred meaning the
        //switch was closed. If that's the case, return true to loop, otherwise
        //return false (we ignore button releases.)
        if( currSw == LOW )
            return true;
            return false;