Use A toggle button to control a 4 channel relays module sequentially

Hi everyone, I am working on the project but I am stuck with the code. The logic is to create a sequence to control the relay sequentially and the 5V DC relay can control the 4 channel solenoid valves. For example, In second 1, the relay 1 will go from HIGH to LOW, In second 2, the relay 2 will go from HIGH to LOW, In second 3, the relay 3will go from HIGH to LOW. Then, in second 4, the relay 1 will go from LOW to HIGH, until in second 6, when the relay 3 goes from LOW to HIGH. The sequence is done. Can anyone help me out of this? Really appreciate it, thank you.

The code.

// set pin numbers:
int relayPin1=7;
int relayPin2=6;
int relayPin3=5;
//const int relayPin4=4

int buttonPin = 2; //add button boolean for true false operation
int ledPin = 22;
//boolean on = false;
int buttonState = LOW;
int ledState = -1;
int State = -1;

unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 200;    // the debounce time; increase if the output flickers
unsigned long currentTime;

unsigned long relayTime_1 = 1000 ;
unsigned long relayTime_2 = 2000;
unsigned long relayTime_3 = 3000;
unsigned long relayTime_1_1 = 4000;
unsigned long relayTime_2_1 = 5000;
unsigned long relayTime_3_1 = 6000;

unsigned long previous_relayTime_1 = 0;
unsigned long previous_relayTime_2 = 0;
unsigned long previous_relayTime_3 = 0;

 // initialize the LED pin as an output:
void setup (){
  //Serial.begin(9600);
  pinMode(buttonPin,INPUT);
  pinMode(ledPin,OUTPUT);
  pinMode(relayPin1, OUTPUT);
  pinMode(relayPin2, OUTPUT);
  pinMode(relayPin3, OUTPUT);
  digitalWrite(relayPin1,HIGH);
  digitalWrite(relayPin2,HIGH);
  digitalWrite(relayPin3,HIGH);
  //pinMode(relayPin4, OUTPUT);
}

void loop(){
  //unsigned long currentTime = millis();
  //int Start = currentTime;
  buttonState = digitalRead(buttonPin); // read the state of the pushbutton value:
  //filter out any noise by setting a time buffer
  if ( (millis() - lastDebounceTime) > debounceDelay) {
    //if the button has been pressed, lets toggle the LED from "off to on" or "on to off"
    if ( (buttonState == HIGH) && (ledState < 0) ) {    
      digitalWrite(ledPin, HIGH); //turn LED on
      //digitalWrite(relayPin, HIGH);
      ledState = -ledState; //now the LED is on, we need to change the state
      State = -State;
      lastDebounceTime = millis(); //set the current time
  if ((ledState >0) && (State > 0)){
    currentTime = millis();
    if ((digitalRead(relayPin1) == HIGH) && (currentTime - previous_relayTime_1 >= relayTime_1)){
     digitalWrite(relayPin3,LOW);
     previous_relayTime_1 = millis();
    }
    if ((digitalRead(relayPin2) == HIGH) && (currentTime - previous_relayTime_2 >= relayTime_2)){
     digitalWrite(relayPin2,LOW);
     previous_relayTime_2 = millis();
    }
    if ((digitalRead(relayPin3) == HIGH) && (currentTime - previous_relayTime_3 >= relayTime_3)){
     digitalWrite(relayPin3,LOW);
     previous_relayTime_3 = millis();
    }
    if((digitalRead(relayPin1) == LOW) && (currentTime - previous_relayTime_1 >= relayTime_1_1)){
     digitalWrite(relayPin1,HIGH);
     previous_relayTime_1 = millis();
    }
    if((digitalRead(relayPin2) == LOW) && (currentTime - previous_relayTime_2 >= relayTime_2_1)){
     digitalWrite(relayPin2,LOW);
     previous_relayTime_2 = millis();
    }
    if((digitalRead(relayPin3) == LOW) && (currentTime - previous_relayTime_3 >= relayTime_3_1)){
     digitalWrite(relayPin3,HIGH);
     previous_relayTime_3 = millis();
    }
    if (millis() > previous_relayTime_3){
     State = -State;
    }
   }
  }

  else if ( (buttonState == HIGH) && (ledState > 0)){

  digitalWrite(ledPin, LOW); //turn LED off
  digitalWrite(relayPin1,HIGH);
  digitalWrite(relayPin2,HIGH);
  digitalWrite(relayPin3,HIGH);
  ledState = -ledState; //now the LED is off, we need to change the state
  lastDebounceTime = millis(); //set the current time
  State = -State;
  }
 }
}

(Code tags added by moderator)

Hello
Do you have a start button for the sequence, too?

Hi,
Welcome to the forum.

Please read the post at the start of any forum , entitled "How to use this Forum".
OR
https://forum.arduino.cc/index.php?topic=712198.0
Then look down to "code problems" about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

3 channel or 4 channel of relays?

If all your button does is start the process, you do not need the debounce bit of code.
All you need to do is sense the button change state and act.

How have you got your button wired?

If from 5V to input pin, then you need a 10K resistor between the input pin and gnd to pull the input pin to a LOW when the button is open.

If from Gnd to input pin, then you need a 10K resistor between the input pin and 5V to pull the input pin to a HIGH when the button is open.

Can you please post a circuit diagram.

Have you been able to activate any of the relays.

I think this is the sequence you are explaining.

Do you need a sequence reset button to intialise the relays after the sequence?

Tom.. :grinning: :+1: :coffee: :australia:

Hi, Ys, I tried to use a toggle button to start the program, when it is pressed, the led lights up and the relay starts working sequentially. However, I can run the toggle button, the the relay doesn't work

Thank you Tom.
I use the 4 channel of relays but I only use 3 channels, spare channel for other usage,
I only need one button to start the program, but I want it to be a toggle button. The button works fine when I pressed it once on/off, But when I want the relay starts working sequentially after the button is pressed (HIGH), it doesn't work at all. Also, when I pressed the button again (LOW), the relay won't go back to HIGH state.

I am sorry that I don't know how to draw a circuit diagram like I don't know which specific components should I find in the circuit diagram software. For example, I use the 4 module relays, but some software just have different forms of relay and doesn't include the transistors resistors.
I can briefly draw one and I hope I can get some feedback and correction.

The sequence is:
1.Button pressed to start, led lights up
2. 0 s-1 s : nothing happened
3. 1s: relay1 is triggered from LOW to HIGH
4. 2s: relay2 is triggered from LOW to HIGH
5. 3s: relay 3 is triggered from LOW to HIGH and relay 1 is triggered from HIGH to LOW
6. 4s: relay 2 is triggered from HIGH to LOW
7. 5s : relay 3 is triggered from HIGH to LOW
8. Repeat steps 3-7 until the button is pressed again
9. when button is pressed, led goes off and all relays are reset and all the relay becomes LOW.

Hello
What do think about the timing provided by TomGeorge?

Hi, this is the time line I want to build.
Capture2

Hello
I´m confused :thinking:
That timing will not match to your start post.

Sorry for the mismatch, I am still a beginner of these diagrams, but if the sequence below follows, what would be the diagram and the code? Thank you. and sorry for my bad bad english
The sequence is:
1.Button pressed to start, led lights up
2. 0 s-1 s : nothing happened
3. 1s: relay1 is triggered from LOW to HIGH
4. 2s: relay2 is triggered from LOW to HIGH
5. 3s: relay 3 is triggered from LOW to HIGH and relay 1 is triggered from HIGH to LOW
6. 4s: relay 2 is triggered from HIGH to LOW
7. 5s : relay 3 is triggered from HIGH to LOW
8. Repeat steps 3-7 until the button is pressed again
9. when button is pressed, led goes off and all relays are reset and all the relay becomes LOW.

Hi,
So you need each of your relays ON for 2s and OFF for 3s, and each relay delayed by 1s.
Like this.

First press starts the sequence and a second press stops the sequence.
2s ON and 3s OFF is that correct?

Tom.. :grinning: :+1: :coffee: :australia:

Hi,
So to start all you need to do is detect an input from LOW to HIGH to SET a variable that runs the sequence.
Then detect an input from LOW to HIGH to RESET that variable and stop the sequence and turn all relays OFF, ready for another press.

Tom... :grinning: :+1: :coffee: :australia:

1 Like

How precisely do you need it to be at that one second mark? Is a simple delay(1000) close enough, even with a few processing cycles? I can think of two ways to do this. My initial thought is to use modular division to reset a sort of "count," but as I went through that in my head it became more complicated than I anticipated. A much easier implementation would be something like:

/*
 * put in all your normal code for relay pins, check if button is pressed, etc
 * and be sure to put your relay pins in an array, to make the next bit of code easier
 * and put your first delay(1000) with the code that checks for if the button is pressed to also make this easier
 */
for(int count = 0; count < 3; count++){
  digitalWrite(relayPin[count], HIGH);
  if(count!=2)
    delay(1000); //Skip last count so relay 1 and relay 3 toggle nearly simultaneously
}
for(int count = 0; count < 3; count++){
  digitalWrite(relayPin[count], LOW);
  delay(1000); //Don't skip this if you want them all off for one second
}

You may need to add, remove, or otherwise modify the delay() calls to fit your needs exactly, but this code should do what you want and it's pretty simple. However, this will have to complete a cycle before you can stop it with the button press. If you want to stop it with the button press, you'd want to add at the start of each for loop code to check for the button press, and probably use an interrupt just to be sure it'll read your button press, then you're only ever 1 second away from stopping (or you could the whole kill code in an interrupt, but that's not always wise).

1 Like

Hi,
@likethesandwich your code would probably do the job, however because you use delays you would not be able to monitor the stop command all the time.

A "blink without delay" approach may be needed.

Tom... :grinning: :+1: :coffee: :australia:

A global bool of buttonOn, check it at the start of the first for loop, and attach an interrupt that changes buttonOn and sets the three relays to LOW. Since only the first for loop would be affected (won't hurt to write "LOW" a second time to the pins), that would accomplish the end goal. It might not be the cleanest and fastest approach, but I would imagine it's fast enough, and it's not terrible. The interrupt only need to write 3 pins to low and change a bool value, shouldn't take too long. Could be even faster using PORT manipulation, extremely fast.

I am wondering how can I put the code of "millis()" that is used to control the button and "delay()" that is used to control the sequence of relays together. I tried once but the relays didn't work at all.
If I want to stop the button whenever I want and reset the relay at the meanwhile, how can I utilize the code of millis() instead of delay()? Thank you all

Hi,
You do not use delay at all, when you put say delay(500), you make the code STOP for 1/2s.
The controller is suspended, it does not read or control I/O while a delay is working.

Tom... :grinning: :+1: :coffee: :australia:

You'll need something against which to check millis(). Essentially you'll need two global variables, a "count" and a "previousMillis" So when the button is pushed, previousMillis = millis(), then check if millis() - previousMillis > 1000 and then do stuff (if yes), and up the count. While the count is < 3, make the pins high, then when the count is > 2 make the pins low (although this exact method will not turn relay 1 off at the same time as relay 3 goes on, so you'll have to do some code to make that work).

Hello and good morning
I think the IDE example "BLINKWITHOUTDELAY" is the mother of all timer function in all variantes. In my sketches I´m using the b.m. eventTimer() function to handle time events. The function parameter contains the address to a struct{} storing all needed data.

enum {NoEvent, Event};
bool eventTimer(TIMER &button) {
  return ((millis() - button.timeStamp >= button.duration) ? Event : NoEvent);
}

Hi, I changed the coding and successfully run the sequence and expected outcome. But when I add another button to control the opposite sequence, it doesn't work. Can I use 2 cases for two separate loops? Here is the code.

#include <Relay.h>

const int pinLed = 49;
const int pinButton = 2;
const int pinLed2 = 43;
const int pinButton2 = 3;
const int pinRelay1 = 7;
const int pinRelay2 = 6;
const int pinRelay3 = 5;

int isRunning = -1;
int directions = 1; // 1 is forwards; -1 is backwards

int buttonState = LOW;
int lastButtonState = LOW;
int buttonState2 = LOW;
int lastButtonState2 = LOW;
unsigned long buttonDebounceTime = 0;
unsigned long buttonDebounceTime2 = 0;
const unsigned long buttonDebounceDelay = 50;

int ledState = LOW;
int ledState2 = LOW;

Relay relay1(pinRelay1, false);
Relay relay2(pinRelay2, false);
Relay relay3(pinRelay3, false);
int relay1State = HIGH;
int relay2State = HIGH;
int relay3State = HIGH;
int relaySequenceIndex = 0;
unsigned long relayDebounceTime = 0;
unsigned long relayDebounceTime2 = 0;
const unsigned long relayInterval = 1300;

void setup() {
// put your setup code here, to run once:
pinMode(pinButton, INPUT);
pinMode(pinButton2, INPUT);
pinMode(pinLed, OUTPUT);
pinMode(pinLed2, OUTPUT);
relay1.begin();
relay2.begin();
relay3.begin();

digitalWrite(pinLed, LOW);
digitalWrite(pinLed2, LOW);

relay1.turnOn();
relay2.turnOn();
relay3.turnOn();
}

void loop() {
// put your main code here, to run repeatedly:
buttonforward();
buttonbackward();
}

void buttonforward(){
int buttonReading = digitalRead(pinButton);

if (buttonReading != lastButtonState) {
buttonDebounceTime = millis();
}

if (millis() - buttonDebounceTime > buttonDebounceDelay) {
if (buttonReading != buttonState) {
buttonState = buttonReading;

  if (buttonState == HIGH) {
    isRunning = -1 * isRunning;
    directions = 1 * directions;
  }
}

}

if (isRunning > 0 && directions == 1) {
if (ledState == LOW) {
ledState = HIGH;
digitalWrite(pinLed, HIGH);
}

if (millis() - relayDebounceTime >= relayInterval) {
  if (direction == 1) { // forwards
      switch (relaySequenceIndex) {
      case 0:
        relay1State = LOW;
        relay1.turnOff();
        break;
      case 1:
        relay2State = LOW;
        relay2.turnOff();
        // break;
      case 2:
        relay3State = LOW;
        relay3.turnOff();
        break;
      case 3:
        relay1State = HIGH;
        relay1.turnOn();
        break;
      case 4:
        relay2State = HIGH;
        relay2.turnOn();
        break;
      case 5:
        relay3State = HIGH;
        relay3.turnOn();
        break;
    }
  }
}

relaySequenceIndex = (relaySequenceIndex + 1) % 6;
  relayDebounceTime = millis();

}else {
if (ledState == HIGH) {
ledState = LOW;
digitalWrite(pinLed, LOW);
}
if (relay1State == LOW) {
relay1State = HIGH;
relay1.turnOn();
}
if (relay2State == LOW) {
relay2State = HIGH;
relay2.turnOn();
}
if (relay3State == LOW) {
relay3State = HIGH;
relay3.turnOn();
}
}

lastButtonState = buttonReading;
}

void buttonbackward(){
int buttonReading2 = digitalRead(pinButton2);

if (buttonReading2 != lastButtonState2){
buttonDebounceTime2 = millis();

}

if (millis() - buttonDebounceTime2 > buttonDebounceDelay){
if (buttonReading2 != buttonState2){
buttonState2 = buttonReading2;

  if (buttonState2 == HIGH){
    isRunning = 1 * isRunning;
    directions = -1 *directions;
  }
}

}

if (isRunning > 0 && direction == -1) {
if (ledState2 == LOW) {
ledState2 = HIGH;
digitalWrite(pinLed2, HIGH);
}

if (millis() - relayDebounceTime2 >= relayInterval) {
  if (directions == -1){
      switch (relaySequenceIndex) {
      case 0:
        relay3State = LOW;
        relay3.turnOff();
        break;
      case 1:
        relay2State = LOW;
        relay2.turnOff();
        break;
      case 2:
        relay1State = LOW;
        relay1.turnOff();
        break;
      case 3:
        relay3State = HIGH;
        relay3.turnOn();
        break;
      case 4:
        relay2State = HIGH;
        relay2.turnOn();
        break;
      case 5:
        relay1State = HIGH;
        relay1.turnOn();
        break;
    }
  }
}

relaySequenceIndex = (relaySequenceIndex + 1) % 6;
  relayDebounceTime2 = millis();
}

else {
if (ledState2 == HIGH){
ledState2 = LOW;
digitalWrite(pinLed2, LOW);
}
if (relay1State == LOW) {
relay1State = HIGH;
relay1.turnOn();
}
if (relay2State == LOW) {
relay2State = HIGH;
relay2.turnOn();
}
if (relay3State == LOW) {
relay3State = HIGH;
relay3.turnOn();
}
}

lastButtonState2 = buttonReading2;
}

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