3 buttons, 3 relays, 3 pumps, how to work in parallel without delay?

Hello this is my project
3 PushButtons
3 Realys
3 Pumps
Every button is connected to the Relay and the relay starts the Pump
When I push the button1 Relay1 is ON and Pump1 is ON after delay time of 4 sec. Pump 1 is OFF

Because I use delay during this 4 sec. my other Buttons 2,3 (Pumps2, 3) are not functional. When the delay finish then my other Buttons/Pumps are functional.
I need to make them to be functional whenever I press the button (during delay)

I know that this is because I use delay (everything is on hold) but I don't know how to make this to work without delay ...because in my real project I need the pump to work maybe 2min. and during this 2min. other pumps are not functional but I need them to be.

Probably I will need to use "currentMillis - previousMillis >= OnTime" but I dont know how... please can someone help me
Project Link


#define buttonP1 5  //Button1
#define buttonP2 6  //Button2
#define buttonP3 7  //Button3

#define relayR1 9     // Pump1
#define relayR2 10    //Pump2
#define relayR3 11    //Pump3


void setup() {
   Serial.begin(9600);
  // put your setup code here, to run once:
    // Activating the digital pins pull up resistors
  pinMode(buttonP1, INPUT_PULLUP);
  pinMode(buttonP2, INPUT_PULLUP);
   pinMode(buttonP3, INPUT_PULLUP);
  
  pinMode(relayR1, OUTPUT);
  pinMode(relayR2, OUTPUT);
  pinMode(relayR3, OUTPUT);
}

void loop() {
 
// if button is pressed
   //Pump1 ON
 if (digitalRead(buttonP1) == LOW) {
  delay(500);
    digitalWrite(relayR1, HIGH);
    Serial.print("P1 ON: ");
    delay(4000);
    //Pump1 Off
    digitalWrite(relayR1, LOW);
    Serial.println("P1 OFF");
  }
   else if (digitalRead(buttonP2) == LOW) {
    digitalWrite(relayR2, HIGH);
    Serial.print("P2 ON: ");
    delay(4000);

    digitalWrite(relayR2, LOW);
    Serial.println("P2 OFF");
}
   else if (digitalRead(buttonP3) == LOW) {
    digitalWrite(relayR3, HIGH);
    Serial.print("P3 ON: ");
    delay(4000);

    digitalWrite(relayR3, LOW);
    Serial.println("P3 OFF");
}
}

Welcome to the forum

See Using millis() for timing. A beginners guide, Several things at the same time and the BlinkWithoutDelay example in the IDE

look this over
besides using millis() is also uses arrays
you should be able to add values to the array for the other 2 relays



const byte    PinBut     [] = { 5 };
const byte    PinRelay   [] = { 9};
unsigned long MsecPeriod [] = { 4000 };
const char   *label      [] = { "P1" };

const int Nrelay            = sizeof(PinRelay);
unsigned long msecRelay  [Nrelay];
bool          tmr        [Nrelay];


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

    for (int n = 0; n < Nrelay; n++)  {
        pinMode      (PinBut   [n], INPUT_PULLUP);
        pinMode      (PinRelay [n], OUTPUT);
        digitalWrite (PinRelay [n], LOW);      // off
    }
}

// -----------------------------------------------------------------------------
void loop() {
    unsigned long msec = millis ();

    for (int n = 0; n < Nrelay; n++)  {
        if (tmr [n] && msec - msecRelay [n] >= MsecPeriod [n])  {
            tmr [n] = false;
            digitalWrite (PinRelay [n], LOW);      // off
            Serial.print (label [n]);
            Serial.println (" off");
        }

        if (! tmr [n] && (LOW == digitalRead (PinBut [n])))  {
            digitalWrite (PinRelay [n], HIGH);      // on
            tmr       [n] = true;
            msecRelay [n] = msec;
            Serial.print (label [n]);
            Serial.println (" on");
        }
    }
}

thank you but this is very hard code for me... Im a begginer :slight_smile:

here is What I did so far... and Button1 is working... but I need to correct other buttons to do the same... fill free to give me sugestions


#define buttonP1 5  //Button1
#define buttonP2 6  //Button2
#define buttonP3 7  //Button3

#define relayR1 9     // Pump1
#define relayR2 10    //Pump2
#define relayR3 11    //Pump3

unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 4000;  //the value is a number of milliseconds

void setup() {
   Serial.begin(9600);
  // put your setup code here, to run once:
    // Activating the digital pins pull up resistors
  pinMode(buttonP1, INPUT_PULLUP);
  pinMode(buttonP2, INPUT_PULLUP);
   pinMode(buttonP3, INPUT_PULLUP);
  
  pinMode(relayR1, OUTPUT);
  pinMode(relayR2, OUTPUT);
  pinMode(relayR3, OUTPUT);
  startMillis = millis();  //initial start time
}

void loop() {
 currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
// if button is pressed
   //Pump1 ON
 if (digitalRead(buttonP1) == LOW) {
     digitalWrite(relayR1, HIGH);
    Serial.print("P1 ON: ");
  delay(500);
 }
  if (currentMillis - startMillis >= period) {  //test whether the period has elapsed
 
       digitalWrite(relayR1, LOW);
    Serial.println("P1 OFF");  //if so, change the state of the LED.  Uses a neat trick to change the state
    startMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.
  Serial.println(startMillis); 
  }


   else if (digitalRead(buttonP2) == LOW) {
    digitalWrite(relayR2, HIGH);
    Serial.print("P2 ON: ");
   delay(500);
   }
if (currentMillis - startMillis >= period) {  //test whether the period has elapsed
 
    digitalWrite(relayR2, LOW);
    Serial.println("P2 OFF");
    startMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.
}
   else if (digitalRead(buttonP3) == LOW) {
    digitalWrite(relayR3, HIGH);
    Serial.print("P3 ON: ");
    delay(500);
   }
if (currentMillis - startMillis >= period) {  //test whether the period has elapsed
    digitalWrite(relayR3, LOW);
    Serial.println("P3 OFF");
    startMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.
}
}

perhaps what you're trying to do isn't as simple as you think

above you turned the relay on

  • what is the purpose of the delay?
  • what enable the timer code below to turn off the relay
  • where is the timestamp capturing when the relay was turned on?

arrays are a very basic programming concept that allow an index to refer to a value that is needed multiple times, for example, your button and relay pins.

the following code not only works for one button/relay but as many as are described with value in the arrays

at the top of the code all the variables are captured in arrays. Some arrays have initialized values such as the button and relay pinss, the amount of delay in MsecPeriod and the label array hold a text string descibing the relay

but two other arrays are needed, msecRelay[] holds the timestamp of when the relay was captured and tmr [] indicates whether the timer is enabled

additional values can initialize, for example

const byte    PinBut     [] = { 5, 6, 7 };

the size of the array, the # of pins can be figured out by the processor using sizeof() which returns the # of bytes in the array

the code in the for loop checks if the button is pressed, that it's value is LOW AND if the timer is already active -- ! tmr [n].

if the relay needs to be set, it's turned on, the tmr flag set true and the current time, msec capture in msecRelay [].

a print indiates which relay is turned on

the timer is enabled when tmr [n] is true. When it's enabled, if the time since the relay was turned on and a timestatamp capture exceeds the delay period, MsecPeriod

the timer is disable, false, the relay turned off and there is a print indicating which relay is being turned off


i hope the description helps you understand what is needed to use millis(). Presumably seeing it in code is easier that reading about how to do it

This may be simpler to understand

if ((digitalRead(buttonP1) == LOW) && (R1state == OFF))
{
   	digitalWrite(relayR1, HIGH);
   	Serial.print("R1 ON: ");
   	R1state = ON;
   	R1start_time = millis();  
}

if (((millis() - R1start_time) >= period) && (R1state == ON))
{
   digitalWrite(relayR1, LOW);
   R1state = OFF;
}



won't this code be repeatedly invoked once it expires?

Yes
It's an easy fix.
Thanks

Maybe it's alittle bit more simple with a library. This is an example of the MobaTools library. It does nearly exactly the same as you wish, but with (only 2) leds:

#include <MobaTools.h>
/* Demo: non blocking timers without delay()
 *  In principle, the 'MoToTimer' works like a kitchen timer.
 *  You wind it up to a certain time and then it runs back to 0. 
 *  Unlike the kitchen alarm clock, however, it does not ring.
 *  You have to check cyclically to see if the time has expired. But that fits
 *  perfectly with the principle of the 'loop', i.e. a cyclical query in an endless loop.
 *  Function calls:
 *  MoToTimer.setTime( long Laufzeit );  sets the time in ms
 *  bool = MoToTimer.running();       == true as long as the time is still running, 
 *  bool = MoToTimer.expired();         This call returns true only once if the time has expired
 *                                      succeding calls will return 'false' again.
 *  
 *  In this demo, 2 leds are switched on with one button each for different times.
 *  At each expiry of the time, a message is output once on the serial monitor.
 *  The buttons must be connected between the pin and Gnd
*/

const byte led1P =  5;
const byte led2P =  6;

const byte button1Pin = A0;
const byte button2Pin = A1;


MoToTimer timer1;
MoToTimer timer2;

void setup() {
  Serial.begin(115200);
  while (!Serial);  // only needed for Arduino Micro/Leonardo
  pinMode(led1P, OUTPUT);
  pinMode(led2P, OUTPUT);
  pinMode(button1Pin, INPUT_PULLUP );
  pinMode(button2Pin, INPUT_PULLUP );
}

void loop() {
  // -------- switching the first led ------------------
  if ( !digitalRead(button1Pin) && !timer1.running() ) {
    Serial.println("start first timer");
    // Switch led on and start timer
    timer1.setTime( 2000 );
    digitalWrite( led1P, HIGH );
  }
  if ( timer1.expired() ) {
    Serial.println("first timer expired");
    digitalWrite( led1P, LOW );
  }
  // -------- switching the second led ------------------
  if ( !digitalRead(button2Pin) && !timer2.running() ) {
    // Switch led on and start timer
    Serial.println("start second timer");
    timer2.setTime( 1500 );
    digitalWrite( led2P, HIGH );
  }
  if ( timer2.expired() ) {
    Serial.println("second timer expired");
    digitalWrite( led2P, LOW );
  }
  
}

of course it is, but shouldn't it be explained ??

Well let's see what @tanjamaya1 says.

Thank you guys for your effort... I really appreciate it... for me this code is understandable and I'll try it...

I try this as well... just to ask you here I should declare
R1state, R2state etc
R1start_time, R2start_time etc?

Yes,
I left the details for you to do, otherwise you won't learn anything.
You also need to define ON and OFF.

LOL!

Yes. I was going to de-arrayize @gcjr's sketch and give it some 21st century style adjustments just to present the essential logic steps w/o the complexity of arrays and industrial certified programming.

   if the button is pressed turn on the relay and start a timer

   if (when!)the timer expires turn off the relay

where "start a timer" means make note of what time it is ("capture a timestamp") which is just putting the value of millis() into an appropriate variable and

expiring means checking to see if that time had receded into the past, that is to say the elapsed time is greater then the time the relay shoukd be on.

We often skip making that explicit, viz:

   unsigned long elapsedTime = now - whenWeStarted;
   if (elapsedTime > 4000) digitalWrite(theRelayPin, OFF);

which assumes a now that is the current value of millis() and OFF defined

# define OFF  HIGH

to accommodate a module that might want LOW to be OFF.

I'd have to look closer than I dare to be sure, but it looks like the relay will be on for a time after the switch is not being pressed anymore; a slightly more sophisticated approach to the button handling would start that time immediately the switch becomes prsssed. I have not read @MicroBahner's solution yet, I am betting it does that.

BTW and FWIW, @MicroBahner's stuff in it somewhere has a perfectly wonderful button handler thing, just a shoutout here to say thx and well done, too well hidden.

a7

This was the easiest solution for me... thank you @MicroBahner
here is the final code

#include <MobaTools.h>
#define buttonP1 5  //Button1
#define buttonP2 6  //Button2
#define buttonP3 7  //Button3

#define relayR1 9     // Pump1
#define relayR2 10    //Pump2
#define relayR3 11    //Pump3

MoToTimer timer1;
MoToTimer timer2;
MoToTimer timer3;

void setup() {
   Serial.begin(9600);
  // put your setup code here, to run once:
    // Activating the digital pins pull up resistors
  pinMode(buttonP1, INPUT_PULLUP);
  pinMode(buttonP2, INPUT_PULLUP);
   pinMode(buttonP3, INPUT_PULLUP);
  
  pinMode(relayR1, OUTPUT);
  pinMode(relayR2, OUTPUT);
  pinMode(relayR3, OUTPUT);
}

void loop() {

  // -------- switching the first Pump ------------------
  if ( (digitalRead(buttonP1) == LOW) && !timer1.running() ) {
    Serial.println("start timer 1");
    // Switch Realy on and start timer
    timer1.setTime( 4000 );
     digitalWrite(relayR1, HIGH);
    }
  if ( timer1.expired() ) {
    Serial.println(" timer 1 expired");
     digitalWrite(relayR1, LOW);
  }
  // -------- switching the second Pump ------------------
  if ( (digitalRead(buttonP2) == LOW) && !timer2.running() ) {
    // Switch Realy on and start timer
    Serial.println("start timer 2");
    timer2.setTime( 4000 );
     digitalWrite(relayR2, HIGH);
  }
  if ( timer2.expired() ) {
    Serial.println(" timer 2 expired");
      digitalWrite(relayR2, LOW);
  }
  // -------- switching the third Pump ------------------
  if ( (digitalRead(buttonP3) == LOW) && !timer3.running() ) {
    // Switch Realy on and start timer
    Serial.println("start timer 3");
    timer3.setTime( 4000 );
     digitalWrite(relayR3, HIGH);
  }
  if ( timer3.expired() ) {
    Serial.println(" timer 3 expired");
      digitalWrite(relayR3, LOW);
  }
  
}