Delayed output without using the delay function

I'm working on a controller for my floor heating. Each room has his own thermostat ( on/off)
The controller has to control the magnetic valves, the boiler and the pump for the floor heating.
My sketch is working with the use of the delay() function.
Now I want to modify this sketch so that the program does not stops for the delay().
I've tried this based on the examples with millis(), but it doesn't work.
How can I solve this problem ?

CV_controller.ino (3.6 KB)

Please post your best effort at using millis() for timing, using code tags when you post it

In my experience the easiest way to tidy up the code and add the code tags is as follows

Start by tidying up your code by using Tools/Auto Format in the IDE to make it easier to read. Then use Edit/Copy for Forum and paste what was copied in a new reply. Code tags will have been added to the code to make it easy to read in the forum thus making it easier to provide help.

It is also helpful to post error messages in code tags as it makes it easier to scroll through them and copy them for examination

Hope this time it's better to read based on your advise.
Please find what I have tried with millis(), but doesn't work.`



int HRQ;                                      // vraag naar warmte
int PHRQ = 0;                                 //vorige vraag voor warmte
int NHRQ = 0;                                 //nadraaien pomp vloerverwarming
const unsigned long startvertraging = 10000;  // startvertraging voor boiler en pomp voor openlopen magneet ventielen
const unsigned long stopvertraging = 5000;    // stopvertraging voor pomp na stoppen boiler

unsigned long previousTime_start = 0;
unsigned long previousTime_stop = 0;

unsigned long startMillis = 0;
unsigned long currentMillis = 0;
int Tr1 = 0;
int Tr2 = 0;


void setup() {

  Serial.begin(9600);
  // put your setup code here, to run once:
  pinMode(22, INPUT);  // thermostaat LOGEERKAMER
  pinMode(24, INPUT);  // thermostaat KAMER COCO
  pinMode(26, INPUT);  // thermostaat KAMER BOBBI
  pinMode(28, INPUT);  // thermostaat BERGING
                       //pinMode(19, INPUT);
                       //pinMode(21, INPUT);
                       //pinMode(22, INPUT);
                       //pinMode(23, INPUT);

  pinMode(40, OUTPUT);  // relais logeerkamer ( 230V)
  pinMode(42, OUTPUT);  // relais kamer Coco ( 230V)
  pinMode(44, OUTPUT);  // relais kamer Bobbi ( 230V)
  pinMode(46, OUTPUT);  // relais kamer berging ( 230V)
  //pinMode(27, OUTPUT);// relais kamer res ( 230V)
  //pinMode(12, OUTPUT);// relais kamer res ( 230V)
  //pinMode(13, OUTPUT);// relais kamer res ( 230V)
  //pinMode(2, OUTPUT);// relais kamer res ( 230V)

  pinMode(48, OUTPUT);  // contact boiler (potentiaal vrij)
  pinMode(50, OUTPUT);  // pomp vloerverwarming ( 230V)
}

void loop() {

  Tr1 = digitalRead(22);
  Tr2 = digitalRead(24);
  digitalWrite(40, Tr1);
  digitalWrite(42, Tr2);


  if (((Tr1 == 1) || (Tr2 == 1)) && (PHRQ == 0)) {
    Serial.print(Tr1);
    Serial.print(Tr2);

    //unsigned long currentTime = millis();
    currentMillis = millis();


    if (currentMillis - previousTime_start <= startvertraging) {


      //delay (5000);
      PHRQ = 1;
      //Serial.print(PHRQ);

      //Serial.println( "   boiler start op");
      previousTime_start = currentMillis;
      PHRQ = 1;
      digitalWrite(48, 1);
      digitalWrite(49, 1);
    }
  }
  if (((Tr1 == 1) || (Tr2 == 1)) && (PHRQ == 1)) {
    Serial.print(Tr1);
    Serial.print(Tr2);
    Serial.print(PHRQ);

    Serial.println("   boiler draait al");
  }




  if (((Tr1 == 0) && (Tr2 == 0)) && (PHRQ == 1)) {
    digitalWrite(48, 0);
    Serial.println("   boiler uit");

    Serial.print(Tr1);

    delay(5000);
    PHRQ = 0;
    Serial.print(PHRQ);
    Serial.println("   pomp uit");
    digitalWrite(49, 0);
  }
  if ((Tr1 == 0 && Tr2 == 0) && (PHRQ == 0)) {
    Serial.print(Tr1);
    Serial.print(Tr2);
    Serial.print(PHRQ);
    Serial.println("   geen verwarming");
  }
}

`

Useless phrase. Please describe what you expected to happen and what happened instead.

Note that the if statement in the following will always be true:

    currentMillis = millis();
    if (currentMillis - previousTime_start <= startvertraging) {


      //delay (5000);
      PHRQ = 1;
      //Serial.print(PHRQ);

      //Serial.println( "   boiler start op");
      previousTime_start = currentMillis;

If you ask for help, please change to using meaningful names for variable, etc. People usually can't follow someone elses acronyms and abbreviations. No need for short names.

Hello guyc1

My recommendation from practice:

Define an object with the I/Os, time control once and use this multiple times for each room.

As already mentioned, do not use any magic abbreviations or numbers. The comments in the sketch use great designations that can be used as variable names.

p.s. Arrays and structs are your friends.

that's my problem that I cannot solve. I try to find something to creat a delay similar with the example 'blink without delay'

@paulpaulson apply this to your explanation.

For a beginner your "explanation"

is a many letters using acronym, that hides away a lot of knowledge which requires to learn dozens of hours about medium advanced programming techniques!

@guyc1
here is a video-tutorial that explains how non-blocking timing based on millis() works

alternatively you could read this tutorial

@guyc1

If you do a very careul comparing of your line

 if (currentMillis - previousTime_start <= startvertraging) {

with this one

 if (currentMillis - previousTime_start >= startvertraging) {

what tiny little difference do you discover?

For whom is that advice? It is not clear.

can you describe what your code does?

why not just use the thermostate input to control the heat? why do you need a delay?

may be hellpful to see the code that works with delay

  • noticed that your code uses pin 49 instead 50 for the pump

looks like you just want to delay turning off the pump after turning off the boiler

look this over
tested on my hardware.
you need to modify it for your pins.

const byte PinThermo [] = { A1, A2, A3 };
const byte PinRelay  [] = {  9, 10, 11 };
const int  Nrelay       = sizeof(PinRelay);

const byte PinBoiler    =   13;
const byte PinPump      =   12;

enum { Off = HIGH, On = LOW };

const unsigned long MsecPumpDelay = 2000;
      unsigned long msec0;

char s [90];

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

    int cnt = 0;
    for (int n = 0; n < Nrelay; n++)  {
        if (On == digitalRead (PinThermo [n]))  {
            msec0 = msec;
            cnt++;

            if (Off == digitalRead (PinRelay [n]))  {
                digitalWrite (PinRelay [n],  On);
                digitalWrite (PinBoiler,     On);
                digitalWrite (PinPump,       On);

                sprintf (s, " cnt %d, room %d On", cnt, n);
                Serial.println (s);
            }
        }
        else
            if (On == digitalRead (PinRelay [n]))  {
                digitalWrite (PinRelay [n],  Off);

                sprintf (s, " cnt %d, room %d Off", cnt, n);
                Serial.println (s);
            }
    }

    if (0 == cnt)  {
        if (On == digitalRead (PinBoiler))  {
            digitalWrite (PinBoiler, Off);
            Serial.println (" Boiler Off");
        }

        if (On == digitalRead (PinPump) && msec - msec0 >= MsecPumpDelay)  {
            digitalWrite (PinPump, Off);
            Serial.println (" Pump Off");
        }
    }

    delay (100);        // deals with switch bounce
}

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

    for (int n = 0; n < Nrelay; n++)  {
        digitalWrite (PinRelay [n],  Off);
        pinMode      (PinRelay [n],  OUTPUT);
        pinMode      (PinThermo [n], INPUT_PULLUP);
    }

    digitalWrite (PinBoiler,  Off);
    digitalWrite (PinPump,    Off);
    pinMode      (PinBoiler,  OUTPUT);
    pinMode      (PinPump,    OUTPUT);
}

First of all my excuses for my late answer, but I was away the whole day and had no time to read my emails and to play with arduino.

I want to do 2 things :

  1. Starting from the position that there is no heat demand ( all thermostats open contact), when the first thermostat ask heat, his magnetic valve has to open. Because the opening time for this type of valves is 2 minutes, the controller has to wait 2 minutes befor the boiler and the pump is started.

  2. When their is no heat demand anymore, the boiler must be stopped and to send the heat stil present in the boiler, has to be in service for 1 minute after the last thermostat is off.

The original sketch I made with the delay() function is working well, but the arduino has to handle also alarms later on. For that reason it should be fine to replace the delay() function with a routine based on millis().

See picture in attachment.

Guy

(attachments)

sequence.pdf (24.2 KB)

look this over

output - note times

19:18:32.198 ->  cnt 1, room 0 On
19:18:34.215 ->  Boiler/Pump On
19:18:36.095 ->  cnt 2, room 2 On
19:18:37.877 ->  cnt 0, room 0 Off
19:19:01.117 ->  cnt 0, room 2 Off
19:19:01.117 ->  Boiler Off
19:19:02.108 ->  Pump Off
const byte PinThermo [] = { A1, A2, A3 };
const byte PinRelay  [] = {  9, 10, 11 };
const int  Nrelay       = sizeof(PinRelay);

const byte PinBoiler    =   13;
const byte PinPump      =   12;

enum { Off = HIGH, On = LOW };

const unsigned long MsecPumpOnDelay  = 2000;
const unsigned long MsecPumpOffDelay = 1000;
      unsigned long msec0;

char s [90];

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

    int cnt = 0;
    for (int n = 0; n < Nrelay; n++)  {
        if (On == digitalRead (PinThermo [n]))  {
            cnt++;

            if (Off == digitalRead (PinRelay [n]))  {
                digitalWrite (PinRelay [n],  On);
                msec0 = msec;       // maybe used to delay turning on boiler

                sprintf (s, " cnt %d, room %d On", cnt, n);
                Serial.println (s);
            }
        }
        else
            if (On == digitalRead (PinRelay [n]))  {
                digitalWrite (PinRelay [n],  Off);

                sprintf (s, " cnt %d, room %d Off", cnt, n);
                Serial.println (s);
            }
    }

    // turn off boiler and delay turning off pump
    if (0 == cnt)  {
        if (On == digitalRead (PinBoiler))  {
            digitalWrite (PinBoiler, Off);
            msec0 = msec;
            Serial.println (" Boiler Off");
        }

        if (On == digitalRead (PinPump) && msec - msec0 >= MsecPumpOffDelay)  {
            digitalWrite (PinPump, Off);
            Serial.println (" Pump Off");
        }
    }
    // delay turning on boiler and pump
    else if (Off == digitalRead (PinPump) && msec - msec0 >= MsecPumpOnDelay) {
        digitalWrite (PinBoiler, On);
        digitalWrite (PinPump,   On);
        Serial.println (" Boiler/Pump On");
    }

    delay (100);        // deals with switch bounce
}

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

    for (int n = 0; n < Nrelay; n++)  {
        digitalWrite (PinRelay [n],  Off);
        pinMode      (PinRelay [n],  OUTPUT);
        pinMode      (PinThermo [n], INPUT_PULLUP);
    }

    digitalWrite (PinBoiler,  Off);
    digitalWrite (PinPump,    Off);
    pinMode      (PinBoiler,  OUTPUT);
    pinMode      (PinPump,    OUTPUT);
}

And there is at least one cut&dry technique to replace delay() with timer(s).

Once that is done, adding alarm(s) and a status blinker as separate independent tasks is no big deal as long as they do not block execution either.

How can I thank you.
Based on your first sketch, I was trying to program the boiler and pump delay. but then I saw your latest version. This is it.
Anyway, I learned a lot. :grinning_face:

You need to be careful using this. sizeof gives you the size of the array, not the number of elements in it. It only works in your sketch because you are using it on an array of 1-byte elements. If you change the type of the array (or copy-and-paste it to use with a different array), it might not work. The general way to get the number of elements in an array like this is to take the sizeof the full array and divide it by the sizeof one element of the array.

sizeof(array) / sizeof(array[0])

This will always work no matter what type the array is. You can even define a preprocessor macro function to do this for you

#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
const int  Nrelay       = ARRAY_SIZE(PinRelay);

A handy little function to tuck away in your library folder:

ArraySize.h:

#ifndef ARRAY_SIZE
#define ARRAY_SIZE

template <class T, size_t n>
size_t arraySize(T const (&)[n]) {
  return n;
}

#endif

Use:

#include "ArraySize.h"

uint8_t array1[] {1, 2, 3, 4, 5};
uint32_t  array2[] {1, 2, 3, 4, 5, 6};

const size_t size1 {arraySize(array1)};
const size_t size2 {arraySize(array2)};

void setup() {
  Serial.begin(115200);
  delay(1000);

  Serial.print("array1 has ");
  Serial.print(size1);
  Serial.println(" elements");

  Serial.begin(115200);
  Serial.print("array2 has ");
  Serial.print(size2);
  Serial.println(" elements");
}

void loop() {
}

i am

When you define the array, make a const variable = # of elements.

It is best on Arduino to never use dynamic allocation.