Help with code: Delay function blocking code.

Hello to everyone.

After few days of fighting with this got here to get some advice.

I'm working on control panel to control relays and display actual function.

All main idea of control panel is to trigger relay for specific time which is adjustable by variable resistor, then to trigger other relay for same time after delay , all may look like this :

Start button > time delay variable 5s -5min>relay1 on for 0,2-2s> time delay variable 5s -5min>relay2 on for 0,2-2s> time delay variable 5s -5min>relay3 on for 0,2-2s> etc

Code which i build dose it all but have to much delay to stop cycle or re adjust time, simply delay function blocking it all.

Thought about using mills function but don't understand that yet.

Hope someone will be able to help me with it.

Thanks

#include <Wire.h>
#include <LiquidCrystal_I2C.h> // spec crystal

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); //LCD ADRESS



const int rel1Pin =  2;
const int rel2Pin =  3;
const int rel3Pin =  4;
const int rel4Pin =  5;        
const int rel5Pin =  6;
const int rel6Pin =  7;
const int motorPin = 8;
const int cycPin =  9;
const int buzPin =  13;

unsigned long time;


void setup(){

Serial.begin(9600);

 pinMode(10, INPUT);

  pinMode(11, INPUT_PULLUP); // start button
  
  pinMode(12, INPUT_PULLUP);  //stop button

  lcd.begin(20,4);
  lcd.setCursor(2,0);
  lcd.print("System Start Up");

  pinMode(ledPin, OUTPUT);
  pinMode(rel1Pin, OUTPUT);
  pinMode(rel2Pin, OUTPUT);
  pinMode(rel3Pin, OUTPUT);
  pinMode(rel4Pin, OUTPUT);
  pinMode(rel5Pin, OUTPUT);
  pinMode(rel6Pin, OUTPUT);
  pinMode(motorPin, OUTPUT);
  pinMode(cycPin, OUTPUT);
  pinMode(buzPin, OUTPUT);

digitalWrite(rel1Pin, HIGH);
digitalWrite(rel2Pin, HIGH);
digitalWrite(rel3Pin, HIGH);
digitalWrite(rel4Pin, HIGH);          //all off
digitalWrite(rel5Pin, HIGH);
digitalWrite(rel6Pin, HIGH);
digitalWrite(motorPin, HIGH);
digitalWrite(cycPin, HIGH);
digitalWrite(buzPin, HIGH);
delay(1000);

 lcd.setCursor(8,1);
  lcd.print("Test");

digitalWrite(rel1Pin, LOW);
delay(10);
digitalWrite(rel1Pin, HIGH);
delay(500);
digitalWrite(rel2Pin, LOW);
delay(10);
digitalWrite(rel2Pin, HIGH);
delay(500);
digitalWrite(rel3Pin, LOW);
delay(10);
digitalWrite(rel3Pin, HIGH);
delay(500);
digitalWrite(rel4Pin, LOW);
delay(10);
digitalWrite(rel4Pin, HIGH);
delay(500);
digitalWrite(rel5Pin, LOW);
delay(10);
digitalWrite(rel5Pin, HIGH);
delay(500);
digitalWrite(rel6Pin, LOW);
delay(10);
digitalWrite(rel6Pin, HIGH);
delay(1000);

 lcd.setCursor(6,2);
  lcd.print("Complete");
delay(2000);

lcd.setCursor(0,0);
 lcd.print("                                                                                ");

 lcd.setCursor(1,0);
  lcd.print(" System ON");
  lcd.setCursor(1,1);
  lcd.print("Pulse Time ");
  lcd.setCursor(1,2);
  lcd.print("Daley Time");
  lcd.setCursor(1,3);
  lcd.print("Motor Temp");




}
void loop() {




 int sensorVal3 = digitalRead(11);
  
  Serial.println(sensorVal3);


 int sensorVal4 = digitalRead(12);
 
  Serial.println(sensorVal4);

  

  

  int sensorReading = analogRead(A0);
  // map 
  int delayTime1 = map(sensorReading, 0, 100, 200, 1000);
 
  
 int sensorReading1 = analogRead(A1);
  // map  
  int delayTime2 = map(sensorReading1, 0, 1023, 100, 1000);

  
    // read the input on analog pin 0:
  int sensorValue1 = analogRead(A0);
  // print out the value 
  lcd.setCursor(12,2);
lcd.print(sensorValue1);
  delay(1);        // delay in between reads for stability

  // read the input on analog pin 1:
  int sensorValue2 = analogRead(A1);
  // print out the value
   lcd.setCursor(12,1);
lcd.print(sensorValue2);
  delay(1);        // delay in between reads for stability






    if(sensorVal3 == LOW){  // HOLD UP ON FUNCTION TO WORK IN LOOP
digitalWrite(buzPin, LOW);
delay(500);
digitalWrite(buzPin, HIGH);
delay(100);
digitalWrite(buzPin, LOW);
delay(20);
digitalWrite(buzPin, HIGH);
delay(100);
digitalWrite(motorPin, LOW); 
digitalWrite(cycPin, LOW);
 lcd.setCursor(0,0);
 lcd.print("                                                                                ");
delay(50);
 lcd.setCursor(1,0);
  lcd.print("ON");
  lcd.setCursor(1,1);
  lcd.print("Pulse Time ");
  lcd.setCursor(1,2);
  lcd.print("Daley Time");
  lcd.setCursor(1,3);
  lcd.print("Motor Temp");
   

 
  digitalWrite(rel1Pin, LOW);
  delay(delayTime2);
 
  digitalWrite(rel1Pin, HIGH);
  delay(delayTime1);

  digitalWrite(rel2Pin, LOW);
  delay(delayTime2);
 
  digitalWrite(rel2Pin, HIGH);
  delay(delayTime1);

 digitalWrite(rel3Pin, LOW);
  delay(delayTime2);
 
  digitalWrite(rel3Pin, HIGH);
  delay(delayTime1);

  digitalWrite(rel4Pin, LOW);
  delay(delayTime2);
 
  digitalWrite(rel4Pin, HIGH);
  delay(delayTime1);

   digitalWrite(rel5Pin, LOW);
  delay(delayTime2);
 
  digitalWrite(rel5Pin, HIGH);
  delay(delayTime1);

  digitalWrite(rel6Pin, LOW);
  delay(delayTime2);
 
  digitalWrite(rel6Pin, HIGH);
  delay(delayTime1);
  }
 



    if(sensorVal4 == LOW){   // SWICH   off

digitalWrite(buzPin, LOW);
delay(200);
digitalWrite(buzPin, HIGH);
delay(100);
digitalWrite(buzPin, LOW);
delay(20);
digitalWrite(buzPin, HIGH);
delay(100);
     digitalWrite(motorPin, HIGH);  

digitalWrite(cycPin, HIGH);

    lcd.setCursor(0,0);
 lcd.print("                                                                                ");
delay(5);
 lcd.setCursor(1,0);
  lcd.print(" OFF");
  lcd.setCursor(1,1);
  lcd.print("Pulse Time ");
  lcd.setCursor(1,2);
  lcd.print("Daley Time");
  lcd.setCursor(1,3);
  lcd.print("Motor Temp");

}




if(digitalRead(10) == LOW){ // start button
  
 lcd.setCursor(1,0);
  lcd.print("ON");
  lcd.setCursor(1,1);
  lcd.print("Pulse Time ");
  lcd.setCursor(1,2);
  lcd.print("Daley Time");
  lcd.setCursor(1,3);
  lcd.print("Motor Temp");
   
  digitalWrite(rel1Pin, LOW);
  delay(delayTime2);
 
  digitalWrite(rel1Pin, HIGH);
  delay(delayTime1);

  digitalWrite(rel2Pin, LOW);
  delay(delayTime2);
 
  digitalWrite(rel2Pin, HIGH);
  delay(delayTime1);

 digitalWrite(rel3Pin, LOW);
  delay(delayTime2);
 
  digitalWrite(rel3Pin, HIGH);
  delay(delayTime1);

  digitalWrite(rel4Pin, LOW);
  delay(delayTime2);
 
  digitalWrite(rel4Pin, HIGH);
  delay(delayTime1);

   digitalWrite(rel5Pin, LOW);
  delay(delayTime2);
 
  digitalWrite(rel5Pin, HIGH);
  delay(delayTime1);

  digitalWrite(rel6Pin, LOW);
  delay(delayTime2);
 
  digitalWrite(rel6Pin, HIGH);
  delay(delayTime1);
  }
  }

Well, guess what? Time to learn - see the link below for help with mills and your program - yes I had to go through it several times slowly - but it is the secret

Demonstration code for several things at the same time

Take a look at Using millis() for timing. A beginners guide

Thank you for directing me route, definitely learned a lot as it has been few days now.

Unfortunately I still have problem on how to time other part of Sequence

i'm Trying to Trigger one relay after another.

Hope you will be able to help

Thanks

 if (digitalRead(10) == LOW) {

    if (currentMillis - previousMillis >= 50000) {
      previousMillis = currentMillis;
      digitalWrite(rel1Pin, LOW);
      if (digitalRead(rel1 == LOW) {
      if (currentMillis - previousMillis == 50000) {
          previousMillis = currentMillis;
          digitalWrite(rel2Pin, LOW);
          delay(200);
          digitalWrite(rel2Pin, HIGH);
        }
      }
      delay(200);
      digitalWrite(rel1Pin, HIGH);
    }
  }

Just to clarify please: there are two different times, it seems. A "long" time between each relay (5s to 5m) and "short" time during which each relay is active (0.2 to 2s).

So are there 2 potentiometers that set those 2 times independently, and they must be adjustable on the fly?

(You mention "variable resistor" but I think you mean a pot. But seems to me you need 2, 1 for each interval?)

edit: I forgot about the button ;). Does the button start a new single cycle with timings for that cycle? And then nothing happens until the button is pressed again, and new times (if pots changed) take effect?

Thanks for your reply.

Yes there are 2 different times adjustable on 2 potentiometers, one for each time and they are adjustable on the fly.

I managed to get most of the code to do what I want it to do just got stuck on how to put timing on next relay and how to loop it.

I didn't described it very well so will try again :

This is just part of the code I got stuck on :

  // when button start is pressed one main relay is on in this situation holding up function 
// when main relay is on we reading value of it with pin(10)


 if (digitalRead(10) == LOW) {    // confirmation of main relay on                

    if (currentMillis - previousMillis >= 50000) {  // first delay (50000) ; time in here is just an example in 
                                                                         here, it will be variable in the end 

      previousMillis = currentMillis;                     // get time
      digitalWrite(rel1Pin, LOW);                         //in here rel1 is on, up to here is all good 
      if (digitalRead(rel1 == LOW) {                    //   I thought that it will trigger rel2   but its not, I believe 
                                                                       that there is not much time to count to 5s   when rel1 is on  
      if (currentMillis - previousMillis == 50000) { //time for rel2 again example timing 
          previousMillis = currentMillis;                   // get time 
          digitalWrite(rel2Pin, LOW);                       //in here rel2 should be on and its not
          delay(200);                                             //deley, again time is just an example will be varible (small 
                                                                        delay like that is not blocking code for me )
          digitalWrite(rel2Pin, HIGH);                      // rel2 off
        }
      }
      delay(200);                                                 //rel1 off delay  working all good 
      digitalWrite(rel1Pin, HIGH);                          // rel1 off working all good 
    }
  }

// so all that should be in repeating loop until stop button is pressed and shuts off main relay so pin(10)reading is high

hycek:
Hello to everyone.

After few days of fighting with this got here to get some advice.

I'm working on control panel to control relays and display actual function.

All main idea of control panel is to trigger relay for specific time which is adjustable by variable resistor, then to trigger other relay for same time after delay , all may look like this :

Start button > time delay variable 5s -5min>relay1 on for 0,2-2s> time delay variable 5s -5min>relay2 on for 0,2-2s> time delay variable 5s -5min>relay3 on for 0,2-2s> etc

Code which i build dose it all but have to much delay to stop cycle or re adjust time, simply delay function blocking it all.

To time multiple events, you can setup one timer and in the ISR count each counter variable. When it hits zero, reload it's value and trigger the appropriate relay.

For example, setup a timer running at 1000 Hz. Setting a counter to 1000 will take exactly one second to count to zero. Then, trigger the relay and reload the counter. Another counter may be loaded with 2000, giving you a 2 second operation.

Since all this happens in the same ISR, all counts count down to zero, trigger their respective relays and get reloaded.

If you don't understand this, let me know and I'll try to provide you with a simple example that you can expand on.

I'm bowing out in favour of krupski: not going to cloud the issue if s/he's taking the OP on an isr adventure...

How about a pre-emptive "don't do serial I/O in interrupt context", for when the debugging starts?

krupski:
For example, setup a timer running at 1000 Hz. Setting a counter to 1000 will take exactly one second to count to zero. Then, trigger the relay and reload the counter. Another counter may be loaded with 2000, giving you a 2 second operation.

Would not that be "millis()"?

Would not that be "millis()"?

Much too simple otherwise I would have suggested it myself.

Oh, wait a minute, I did that in reply #2

I know I said this:

12Stepper:
I'm bowing out in favour of krupski

... but wth, here's some code.

It's not exactly what you want, in part because I don't fully understand the requirement (edit.. What's cycpin? What's stop supposed to do? Is the timing supposed to change mid-cycle? (I made mine constant for a cycle, changes at the start of a new one)). I also can't find any pots (how can that be?) so my timings are just from random numbers of 100-500ms for on, and 1-2s between.

I also didn't use an lcd; mine is currently in the washing machine. Run it with the monitor open.

The below is a simple state machine: it starts idle, and switches to cycling when the start button is pressed. In cycling, if we have a newRelay, it captures the start time, turns the current relay on, and sets newRelay false (else it will continually reset that time.) Then it delay()-lessly checks for when the on time has expired, and turns the relay off. Then it delay()-lessly checks for when the on time plus between time has expired, and increments to the next relay. If all the relays are done, it goes back to idle.

Relay pins are in an array. (edit: so they are numbered 0-5 not 1-6 :wink: )

L13 bwods the whole time to prove there's no blocking.

Check the line marked <<<<<<<<< and comment it in or out depending on your relay logic: I was using leds to ground as a test, high is on for me.

//  https://forum.arduino.cc/index.php?topic=649992

//to use RELAY_ON or RELAY_OFF in digitalWrite(), instead of HIGH or LOW
//(un-)comment the next line depending on the relay's logic 
//#define weHaveAnActiveLowRelay //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#ifdef weHaveAnActiveLowRelay
#define RELAY_ON LOW   // most relay modules use this *active low* logic
#define RELAY_OFF HIGH
#else
#define RELAY_ON HIGH   // for testing with an *active high* relay or led
#define RELAY_OFF LOW
#endif

//  there is a bwod on led13 to prove no blocking
unsigned long previousBlink;
int blinkInterval = 500;
bool blinkState;

//states
enum {ST_idle, ST_cycling} currentState = ST_idle;

//pins
const byte start = 11;
const byte relays[] = {2, 3, 4, 5, 6, 7};
const byte numberOfRelays = sizeof(relays) / sizeof(relays[0]);

//timing
int relayOnTime;
int betweenRelayTime;
// values will be set by pots, but here by random
unsigned long relayWentOnAt;
bool newRelay = false;
byte currentRelay;


void setup()
{
  // initialize serial communication:
  Serial.begin(9600);
  Serial.println("setup() ... ");
  Serial.println("6 relays with timers");
  Serial.print("Compiler: ");
  Serial.print(__VERSION__);
  Serial.print(", Arduino IDE: ");
  Serial.println(ARDUINO);
  Serial.print("Created: ");
  Serial.print(__TIME__);
  Serial.print(", ");
  Serial.println(__DATE__);
  Serial.println(__FILE__);

  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(start, INPUT_PULLUP);

  Serial.print("Initialising "); Serial.print(numberOfRelays); Serial.println(" relays/pins:");
  for (byte i = 0; i < numberOfRelays; i++)
  {
    Serial.print(i); Serial.print("/"); Serial.print(relays[i]); Serial.print(" ");
    digitalWrite(relays[i], RELAY_OFF);
    pinMode(relays[i], OUTPUT);
  }
  randomSeed(analogRead(0));
  Serial.println(" ");
  Serial.println("setup() done");
  Serial.println(" ");
  Serial.println("Entering idle state: press Start...");
}//setup

void loop()
{
  proofOfLife();
  manageRelays();
} //loop

void proofOfLife()
{
  if (millis() - previousBlink >= blinkInterval)
  {
    previousBlink = millis();
    blinkState = !blinkState;
    digitalWrite(LED_BUILTIN, blinkState);
  }
}

void manageRelays()
{
  switch (currentState)
  {
    case ST_idle:
      if (!digitalRead(start))
      {
        relayOnTime = random(100, 501); //will be a mapped pot in real life
        betweenRelayTime = random(1000, 2001);  //will be a mapped pot in real life
        Serial.print("On time: "); Serial.print(relayOnTime); Serial.print(", between relay time: "); Serial.println(betweenRelayTime);
        currentState = ST_cycling;
        currentRelay = 0;
        newRelay = true;
      }
      break;

    case ST_cycling:
      
      if (newRelay)
      {
        relayWentOnAt = millis();
        digitalWrite(relays[currentRelay], RELAY_ON);
        Serial.print("Relay "); Serial.print(currentRelay); Serial.print(" on at "); Serial.println(relayWentOnAt);
        newRelay = false;
      }

      if (millis() - relayWentOnAt >= relayOnTime)
      {
        digitalWrite(relays[currentRelay], RELAY_OFF);
      }

      if (millis() - relayWentOnAt >= relayOnTime + betweenRelayTime)
      {
        currentRelay++;
        newRelay = true;
      }

      if (currentRelay == numberOfRelays)
      {
        currentState = ST_idle;
        Serial.println("Returning to idle state: press Start...");
      }
      break;


  }//switch
}//manageRelays

Think of your goal as a timeline,bumped along by a button or period of seconds.

The approach to resolve this is a state-machine for each of the ‘states’ the outputs can be in...
Using millis(), you can test whether to ove forward, or wait for user input.

It sounds hard, but is quite logical. the same as you would approach it as a thinking person.

Thinking as a person is what gets you into the delay() mess. "Press a button and it does X for 2 seconds" is a very simple instruction but writing it for a dumb computer to follow is much more difficult.

Even just in the first 3 words are multiple issues with debouncing and making your program responsive enough.

I think you need to think like a computer. It doesn't see button presses and 2 seconds is like 2 weeks. It sees button-is-currently-down and it sees milliseconds like long-running tasks.