millis() problem

The code below is a very cut down version of a sketch I'm working on which is working as it stands, but it needs more doing to it.

It concerns a refrigeration compressor (Relay_5 on Pin 9) which is controlled by a Thermostat (Pin 2, normally open, closed for compressor operation).

I need to arrange millis() delays so that the compressor avoids a hot starts, under the following circumstances:

1: When the compressor switches OFF after a period of operation, it mustn't be allowed to start again until a period of 5 minutes (300000 milliseconds) has passed, to allow the pressure to dissipate.

2: If there is a short power cut of a few seconds for example, the compressor may have been operating at the time, so on reset of the Arduino, there should be a 5 minute delay before the compressor is allowed to start.

I know there are numerous millis() examples on the internet, and I've studied most of them over Christmas but I'm not much further forward. It's a very difficult concept for a novice to get to grips with, not least because in my case the time count must start at the switch off of the compressor, rather than the start of the Arduino (at least in situation 1).

This sketch doesn't include my attempts to put together a delay as despite many evenings of study, I haven't been able to put together anything that compiles, let alone works.

So could someone spell out please, in baby steps suitable for a novice, how to implement the two delays needed to stop the compressor from starting when there may be too much pressure for a safe start? Thanks.

const int RELAY_ON = 0;
const int RELAY_OFF = 1;

const int RELAY_5 = 9;  // Digital I/O pin number 9 - Relay 5 - Compressor

const int Programmable_Thermostat = 2;  // Digital I/O pin 2 - closed for heat demand

void setup()         /****** SETUP: RUNS ONCE ******/
{
  // Initialize Pins so relays are inactive at reset
  digitalWrite(RELAY_5, RELAY_OFF);  // Initialize Relay Pins so relays are inactive at reset

  // THEN set pins as outputs
  pinMode(RELAY_5, OUTPUT);  // set Relay Pin as output

  pinMode(2, INPUT_PULLUP); // enable internal pullup resistor on Pin 2 - Programmable Thermostat


}          //--(end setup )---


void loop() {  /****** LOOP: RUNS CONSTANTLY ******/
  if (digitalRead(Programmable_Thermostat) == LOW)
  {
    digitalWrite(RELAY_5, RELAY_ON);  // set Compressor ON

  }    else   {
    digitalWrite(RELAY_5, RELAY_OFF);  // set Compressor OFF

  }
}


//--(end main loop )---



//*********( THE END )***********

Here's how you might do a POR delay. You should be able to use the concepts to implement the other timing you want...

#define POR_DELAY   300000L

uint8_t
    bFlags;
#define POR_FLAG    0b00000001
    
unsigned long
    ulPORDelayTimer;

void setup() 
{
  // put your setup code here, to run once:
  ulPORDelayTimer = millis();
  bFlags = 0;
}

void loop() 
{
  // put your main code here, to run repeatedly:
  if( !(bFlags & POR_FLAG) )
  {
    if( (millis() - ulPORDelayTimer) >= POR_DELAY )
        bFlags |= POR_FLAG;
  }
  else
  {
    //use additional flags and timer/millis to check for
    //off-on timing etc
    if (digitalRead(Programmable_Thermostat) == LOW)
     digitalWrite(RELAY_5, RELAY_ON);  // set Compressor ON
    else
        digitalWrite(RELAY_5, RELAY_OFF);  // set Compressor OFF
 
  }//else

}//loop

SpikeUK2564:
2: If there is a short power cut of a few seconds for example, the compressor may have been operating at the time, so on reset of the Arduino, there should be a 5 minute delay before the compressor is allowed to start.

So the Arduino is also subject to the power outage, correct? The solution to this is to write the compressor state to EEPROM. EEPROM is non-volatile so it will maintain the data you wrote after a power outage. In setup(), you will read the EEPROM and determine whether the delay is necessary depending on the value. You can get information on the EEPROM library here:

Some boards (e.g. MKR, Zero) don't have EEPROM but you will usually be able to find a library that provides the same functionality using the flash memory.

You also need to handle the situation where the compressor had recently stopped before the short power outage. The most simple solution is to wait the 5 minutes before writing to EEPROM that the compressor is in the "safe to turn on" state. The downside to this approach is that if the compressor had been off for 4 minutes, then a power outage occurred, on restart the code would delay an additional 5 minutes, resulting in a longer than necessary delay. If that's an issue, you could periodically write the time since the compressor was turned off to EEPROM. You do need to be aware that the EEPROM is only rated for a certain number of writes (100000 in the case of the AVR boards like Uno, Mega, Leonardo, etc.). If your sketch is constantly writing to EEPROM, you will wear it out very quickly. So you would need to determine an appropriate frequency to write.

None of the above considers the length of the power outage. If the power was out for longer than 5 minutes, then no delay is necessary. If that's an issue, you could connect a battery powered RTC module to your Arduino, which you can query for the actual time at restart and compare that to the last timestamp data in the EEPROM.

I have a similar issue with a DIY oxygen concentrator system. It has a mechanical unloader valve on the pressure switch. So if there is a power outage while the compressor is running, the compressor is pressurized and it can't start once the power comes back on. I've been meaning to replace the mechanical unloader with a normally open solenoid valve, but I haven't gotten my hands on a solenoid rated for that pressure yet.

SpikeUK2564:
I need to arrange millis() delays so that the compressor avoids a hot starts, under the following circumstances:

1: When the compressor switches OFF after a period of operation, it mustn't be allowed to start again until a period of 5 minutes (300000 milliseconds) has passed, to allow the pressure to dissipate.

2: If there is a short power cut of a few seconds for example, the compressor may have been operating at the time, so on reset of the Arduino, there should be a 5 minute delay before the compressor is allowed to start.

If a simple solution is acceptable then it could be made very simple.

For {2} just put a 5 minute delay() in setup() to ensure that, no matter what, there cannot be a too hasty start when the Arduino restarts.

For {1} then something like this pseudo code should work

if (motorPermittedToStart == true) {
   // code to make motor start
}
if (time for motor to stop) {
   // code to stop motor
  motorPermittedToStart = false;
  motorStoppedTime = millis()
}
if (millis() - motorStoppedTime >= 5minutes) {
   motorPermittedToStart = true;
}

...R

Thanks for the replies. I'm trying to get to grips with Blackfin's solution to start with. I have inserted, I hope correctly, Blackfin's code into my full sketch - which maybe I should have posted to begin with.

The idea of my sketch briefly is that the compressor comes on in response to the Programmable Thermostat closing, calling for heat. If the Defrost Stat goes open, the Defrost Valve activates. If the High Pressure Stat goes open, the control lines to the Compressor Relay, and the Defrost Valve Relay go open, effectively disabling them.

It is important that the Compressor doesn't try to start within 5 minutes of having previously shut down.

I can't pretend to begin to understand Blackfin's code, but it does seem to work in the event of my Situation 2, which is a good thing as it is my intention to avoid a delay() as I intend to control the fans on Relays 1 to 4 in due course so I don't want the UNO going to sleep for 5 minutes.

I'm not sure how to adapt the code to my Situation 1.

I also don't understand how Blackfin's code knows it is controlling Relay_5 on Pin 9, and not the other relays.

I have reduced the delay time to 5 seconds, which is more sensible for testing.

If someone could help me with my understanding of this code, maybe by inserting comments in my sketch, I would be most grateful. Thanks.

// constants don't change
const int RELAY_ON = 0;
const int RELAY_OFF = 1;

const int RELAY_1 = 5;  // Digital I/O pin number 5 - Relay 1 - Not used
const int RELAY_2 = 6;  // Digital I/O pin number 6 - Relay 2 - Not used
const int RELAY_3 = 7;  // Digital I/O pin number 7 - Relay 3 - Not used
const int RELAY_4 = 8;  // Digital I/O pin number 8 - Relay 4 - Not used
const int RELAY_5 = 9;  // Digital I/O pin number 9 - Relay 5 - Compressor
const int RELAY_6 = 10;  // Digital I/O pin number 10 - Relay 6 - Defrost Valve
const int RELAY_7 = 11;  // Digital I/O pin number 11 - Relay 7 - Compressor Relay control line
const int RELAY_8 = 12;  // Digital I/O pin number 12 - Relay 8 - Defrost Valve Relay control line

const int Programmable_Thermostat = 2;  // Digital I/O pin 2 - closed for heat demand
const int Frost_Stat = 3;               // Digital I/O pin 3 - normally closed, open for defrost mode
const int High_Pressure_Stat = 4;       // Digital I/O pin 4 - normally closed, open to stop compressor and defrost valve

#define POR_DELAY   5000L               // POR = Power-On-Relay Delay ??

uint8_t                                 // The same as a byte?
bFlags;
#define POR_FLAG    0b00000001          // ??

unsigned long
ulPORDelayTimer;                        // ??

void setup()         /****** SETUP: RUNS ONCE ******/
{
  {
    // Initialize Pins so relays are inactive at reset
    digitalWrite(RELAY_1, RELAY_OFF);  // Initialize Relay Pins so relays are inactive at reset
    digitalWrite(RELAY_2, RELAY_OFF);  // Initialize Relay Pins so relays are inactive at reset
    digitalWrite(RELAY_3, RELAY_OFF);  // Initialize Relay Pins so relays are inactive at reset
    digitalWrite(RELAY_4, RELAY_OFF);  // Initialize Relay Pins so relays are inactive at reset
    digitalWrite(RELAY_5, RELAY_OFF);  // Initialize Relay Pins so relays are inactive at reset
    digitalWrite(RELAY_6, RELAY_OFF);  // Initialize Relay Pins so relays are inactive at reset
    digitalWrite(RELAY_7, RELAY_OFF);  // Initialize Relay Pins so relays are inactive at reset
    digitalWrite(RELAY_8, RELAY_OFF);  // Initialize Relay Pins so relays are inactive at reset

    // THEN set pins as outputs
    pinMode(RELAY_1, OUTPUT);  // set Relay Pin as output
    pinMode(RELAY_2, OUTPUT);  // set Relay Pin as output
    pinMode(RELAY_3, OUTPUT);  // set Relay Pin as output
    pinMode(RELAY_4, OUTPUT);  // set Relay Pin as output
    pinMode(RELAY_5, OUTPUT);  // set Relay Pin as output
    pinMode(RELAY_6, OUTPUT);  // set Relay Pin as output
    pinMode(RELAY_7, OUTPUT);  // set Relay Pin as output
    pinMode(RELAY_8, OUTPUT);  // set Relay Pin as output

    pinMode(2, INPUT_PULLUP); // enable internal pullup resistor on Pin 2 - Programmable Thermostat
    pinMode(3, INPUT_PULLUP); // enable internal pullup resistor on Pin 3 - Defrost Stat
    pinMode(4, INPUT_PULLUP); // enable internal pullup resistor on Pin 4 - High Pressure Stat


    ulPORDelayTimer = millis();
    bFlags = 0;
  }


}          //--(end setup )---


void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{
  if ( !(bFlags & POR_FLAG) )
  {
    if ( (millis() - ulPORDelayTimer) >= POR_DELAY )
      bFlags |= POR_FLAG;
  }
  else
  {

    if (digitalRead(Programmable_Thermostat) == LOW)
    {
      digitalWrite(RELAY_5, RELAY_ON);  // set Compressor ON
    }    else   {
      digitalWrite(RELAY_5, RELAY_OFF);  // set Compressor OFF
    }

    if (digitalRead(Frost_Stat) == HIGH)
    {
      digitalWrite(RELAY_6, RELAY_ON);  // set Defrost Valve ON
    } else   {
      digitalWrite(RELAY_6, RELAY_OFF);  // set Defrost Valve OFF
    }

    if (digitalRead(High_Pressure_Stat) == HIGH)
    {
      digitalWrite(RELAY_7, RELAY_ON);  // Compressor Relay control line OPEN - Disabled
    } else   {
      digitalWrite(RELAY_7, RELAY_OFF);  // Compressor Relay control line CLOSED
    }

    if (digitalRead(High_Pressure_Stat) == HIGH)
    {
      digitalWrite(RELAY_8, RELAY_ON);  // Defrost Valve Relay control line OPEN - Disabled
    } else   {
      digitalWrite(RELAY_8, RELAY_OFF);  // Defrost Valve Relay control line CLOSED
    }
  }

}


//--(end main loop )---



//*********( THE END )***********

The way the code is constructed none of the relays should operate until the POR_DELAY (now 5-seconds in your code, not 5-minutes.)

The if-else statement at the beginning of loop() basically waits until the timeout, then sets the bit in the flag. On the next pass, the flag is set so the "else" code executes.

If you need the delay to affect only specific relay(s), you'll need to change the code a bit. Not a difficult change.