Using Millis to Turn On/Off Relay for a set interval

Hi there!

First off I'm a beginner so please cut me a little bit of slack. I'm building an air compressor controller as an exercise to teach me a bit about programming. No worries, I have multiple safety redundancies. A necessity of the controller is to activate a solenoid valve which acts as an unloader for a set period of time after the compressor reaches its set point and has turned off. Additionally the solenoid will be activated again for a set period when the compressor turns on.

The issue that I'm having is that the the unloader valve will not stay on or off for the set period. Rather it will flash on or off once per the set interval. So, for example, the solenoid turns off for like a millisecond every 15 seconds when it's in the psi <= Start condition rather than turning on for 15 seconds then turning off. I feel like I'm really close to figuring this out but am obviously missing something.

I've been searching for ages for a similar problem that someone else has had but cannot find a thread that fits the problem precisely. I've considered using a while loop for the start and stop conditions but I'm not sure whether this would solve the issue either? Any hints that anyone could provide would be greatly appreciated!! Thanks very much in advance!

#include <Wire.h> //allows communication over i2c devices
#include <EEPROM.h> //Electronically erasable programmable memory library
#include <LiquidCrystal_I2C.h> //allows interfacing with LCD screens
  LiquidCrystal_I2C lcd(0x27, 16, 2); //sets the LCD I2C communication address; format(address, columns, rows)
#include <Bounce2.h> //Button debouncing library
  Bounce debouncer = Bounce(); //instantiates a bounce object

//Inputs
int pressureInput = A7; //sets the analog input pin for the pressure transducer
int RedEnd = 10; //sets address of end loop button on Nano digital pins

//Digital Outputs
int ConcRelay1 = 2; //sets address of concentrator1 relay on digital pins found on Nano
int ConcRelay2 = 3; //sets address of concentrator2 relay on digital pins found on Nano
int CompRelay3 = 4; //sets address of compressor relay on digital pins found on Nano
int ValveRelay4 = 5; //sets address of unloader valve relay on digital pins found on Nano


//Start and stop pressure values
const int Start = 40; //concentrators and compressor start at 40 PSI
const int Stop = 85; //concentrators and compressor stop at 85 PSI

// this is the EEPROM section
int eeAddress1 = 10;                // this sets the eeAddress1 tag and sets the address to 10, eeprom
int eeAddress2 = 20;                // this sets the eeAddress2 tag and sets the address to 20, eeprom

//Debounce section
int buttonState;                    // this set the tag "buttonState", to the current button state from the input pin
int lastButtonState = HIGH;          // this set the tag "lastButtonState", to the previous button state from the input pin
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 100;  // the debounce time; increase if the output flickers

// this is the "Clock"
unsigned long previousTime = 0;            // this sets the tag "previousTime", that will store the last time "delay" that was updated (unnecessary?)
unsigned long psiStopTime;               // time the PSI reached the stop point
unsigned long psiStartTime;             // time the PSI reached the start point
const long solenoidInterval = 30000;  // sets the interval time for solenoid to be open (30s)
const long warmInterval = 15000;     // sets time interval for concentrators to be on with valve open prior to compressor start

void setup() //setup routine, runs once when system turned on or reset
{
  //  this section assigns the inputs and outputs
 
 // inputs
  pinMode(RedEnd,INPUT_PULLUP);              // End loop button
    debouncer.attach(RedEnd);                // Attach the debouncer to REDEND with INPUT_PULLUP mode
    debouncer.interval(debounceDelay);   // interval in ms

 // outputs
  pinMode(ConcRelay1, OUTPUT);            // concentrator1 relay
   digitalWrite(ConcRelay1, LOW);        // initially sets output tag "ConcRelay1" low
  pinMode(ConcRelay2, OUTPUT);          // concentrator2 relay
   digitalWrite(ConcRelay2, LOW);       // initially sets output tag "ConcRelay2" low
  pinMode(CompRelay3, OUTPUT);            // comperssor relay
   digitalWrite(CompRelay3, LOW);         // initially sets output tag "CompRelay3" low
  pinMode(ValveRelay4, OUTPUT);         // unloader valve relay
   digitalWrite(ValveRelay4, LOW);      // initially sets output tag "ValveRelay4" low 
  
  // Retrieves the setpoints from the arduino eeprom so the unit can start up after a power fail
  EEPROM.get(eeAddress1, Start);         // retrieves the start psi from eeprom
  EEPROM.get(eeAddress2, Stop);          // retrieves the stop psi from eeprom
  
  //  Starts up the different libraries
  Serial.begin(9600); // start the serial monitor at 9600 baud
  lcd.init();         // start the lcd library
  lcd.backlight();    // turn on the lcd backlight
  lcd.clear();        // clear the cld screen
  Wire.begin();       // start the I2C library

  //Start up messge
  lcd.setCursor(2,0); //sets cursor to column 2, row 0
  lcd.print("Hello There!"); //prints label
  lcd.setCursor(0,1); //sets cursor to column 0, row 1
  lcd.print("Starting in 3sec");
  delay(3000);
  lcd.clear();
}

void loop() //loop routine runs over and over again forever
{

  // this section monitors the live psi and turns the compressor and concentrators on or off based off setpoints
  int psi = analogRead(7); // this reads the analog input(A7) and scales it
  psi = map(psi, 102, 922, 0, 150);             // this maps the raw analog input value to the converted PSI value         
  if (psi >= Stop ){digitalWrite (ConcRelay1 ,  LOW);}         // if psi is greater than stop setpoint turn off concentrator1
  if (psi >= Stop ){digitalWrite (ConcRelay2 ,  LOW);}         // if psi is greater than stop setpoint turn off concentrator2
  if (psi >= Stop ){digitalWrite (CompRelay3 ,  LOW);}         // if psi is greater than stop setpoint turn off compressor

   // this section keeps track of the millis counts (this is the "clock!")
  // millis is running in the background so any program delays wont effect the timing
  unsigned long currentMillis = millis(); // updates and holds a copy of the SecondMillis
  if (psi >= Stop ){
  {digitalWrite (ValveRelay4 , HIGH);}        // if psi is greater than stop setpoint turn on solenoid valve
  psiStopTime = currentMillis; // sets the time the stop point was reached to current time
  }
  if ((unsigned long)(currentMillis - psiStopTime) >= solenoidInterval){digitalWrite (ValveRelay4 , LOW);} //cuts power to solenoid after solenoidInterval time  

  if (psi<=Start){
 {digitalWrite (ConcRelay1 , HIGH);} // if psi is less than start setpoint turn on concentrator1
 {digitalWrite (ConcRelay2 , HIGH);} // if psi is less than start setpoint turn on concentrator2
 {digitalWrite (ValveRelay4 , HIGH);} // if psi is less than than start setpoint turn on solenoid valve
 psiStartTime = currentMillis; 
  }
 if ((unsigned long)(currentMillis - psiStartTime) >= warmInterval){ // allows concentrators to warm up prior to starting compressor, O2 purged through valve
 {digitalWrite (ValveRelay4 , LOW);}   //cuts power to solenoid after warmInterval time 
 {digitalWrite (CompRelay3 , HIGH);}         // if psi is less than start setpoint turn on compressor after warmInterval
 }
  
  // This section prints the PSI value caluculated from transducer to the LCD screeen
  Serial.print(psi, 1); //prints value from previous line to serial
  Serial.println("psi"); //prints label to serial
  lcd.setCursor(0,0); //sets cursor to column 0, row 0
  lcd.print("Current= "); //prints label
  lcd.setCursor(10,0); //sets cursor to column 10, row 0
  lcd.print(psi); //prints pressure value to lcd screen
  lcd.setCursor(12,0); //sets cursor to column 12, row 0
  lcd.print("PSI"); //prints label after value
  lcd.print("   "); //to clear the display after large values or negatives

  lcd.setCursor(0,1); //sets cursor to column 0, row 1
  lcd.print ("Min=40 ; Max=85"); //prints Start and Stop pressure values



// Update the Bounce instance :
  debouncer.update();

   // this section defines function of RedEnd button 
  if(digitalRead(RedEnd)== LOW){
    {digitalWrite (ConcRelay1 ,  LOW);}
    {digitalWrite (ConcRelay2 ,  LOW);}
    {digitalWrite (CompRelay3 ,  LOW);} 
    {digitalWrite (ValveRelay4 , HIGH);}
     
  
  // Notifies that the end cycle button has been pressed
  lcd.clear();
  lcd.setCursor(1,0); //sets cursor to column 1, row 0
  lcd.print("Program Ended!"); //prints label
  lcd.setCursor(0,1); //sets cursor to column 0, row 1
  lcd.print("60s to shut down"); //prints label
  delay(60000);
}}


// Code End

better if the variable was named int unloaderValve = 5;

Gain insight to what the numbers are doing by adding Serial.prints

Now the numbers will show their stuff.

Thank you for the quick reply Idahowalker! Ok I'm new to the serial.print feature so I'm assuming that the tick indicates that this function is momentary rather than a fixed time? I'm a little too dense to pick up what you're clueing me in on here, can you elaborate a bit further?

Also, yes, I agree the name for that int isn't intuitive for anyone reviewing the code. It just made sense at the time since the valve was controlled by relay 4 of a 4 relay bank. i will clean it up, thank you!

Could you make the text of the code look better ?

For example this does not look good:

if ((unsigned long)(currentMillis - psiStopTime) >= solenoidInterval){digitalWrite (ValveRelay4 , LOW);} //cuts power to solenoid after solenoidInterval time

this is better:

if (currentMillis - psiStopTime >= solenoidInterval)
{
  // cuts power to solenoid after solenoidInterval time
  digitalWrite (ValveRelay4, LOW);
}

And this is confusing:

 if ((unsigned long)(currentMillis - psiStartTime) >= warmInterval){ // allows concentrators to warm up prior to starting compressor, O2 purged through valve
 {digitalWrite (ValveRelay4 , LOW);}   //cuts power to solenoid after warmInterval time 
 {digitalWrite (CompRelay3 , HIGH);}         // if psi is less than start setpoint turn on compressor after warmInterval
 }

without confusion:

  if (currentMillis - psiStartTime >= warmInterval)
  { 
    // allows concentrators to warm up prior to starting compressor, 
    // O2 purged through valve
    digitalWrite (ValveRelay4, LOW);   //cuts power to solenoid after warmInterval time 
    digitalWrite (CompRelay3 , HIGH);  // if psi is less than start setpoint turn on compressor after warmInterval
  }

You don't have to copy my style, you can have your own style.
Start by pressing Ctrl+T in the Arduino IDE. That is also in the menu: Tools / Autoformat.

To create a single delay, I use a 'bool' variable to tell if that delay is active at the moment. See my millis_single_delay.ino

When there is an issue, the recourse is to add serial.prints to gain info about the various conditions of your program. When the program is working, I take the serial prints out for increased program performance.

This is your stated issue. At first glance at your code, besides some cleaning up I did not see why. Thus a request for serial prints so that you can get more info.

OI! crap.... My oopsie.

I completely missed that. Let me ask you Is 3000 greater then 6000? You put the program to sleep for 6 seconds. You should not mix millis() and delay().

i tried simulating your code

    if ( (currentMillis - psiStartTime) >= warmInterval) { 

the problem with a statement above it what prevents it from repeating instead of just occurring once.

psiStartTime gets set when you want it to occur, currentMillis increases and the action taken, but it continues to be taken more than once.

the same it true for the other timer case with solenoidInterval

i think your code recognize specific state such as

  • monitoring the pressure for it to exceed some threshold
  • recognizing when that threshold is exceeded and take some action that may take some period of time
  • wait for that period to expire and probably start monitor for some other event such as the pressure dropping below some threshold
  • similarly take action when that threshold is exceeded

here's a version more conventionally formatted

#include <Wire.h> //allows communication over i2c devices
#include <EEPROM.h> //Electronically erasable programmable memory library

#define MyHW
#ifdef MyHW
struct LiquidCrystal_I2C  {
    LiquidCrystal_I2C (int a, int b, int c)  { };

    void clear (void)            { Serial.println (); };
    void backlight (void)  { };
    void init  (void)  { };
    void setCursor  (int a, int b)  { };

    void print  (char *s)        { Serial.print (s); };
    void print  (const char *s)  { Serial.print (s); };
    void print  (int i)          { Serial.print (i); };
};

struct Bounce {
    void attach (int pin)  { };
    void interval (int i)  { };
    void update (void)  { };
};

const int  pressureInput = A0;

const byte RedEnd      = A1;

const byte ConcRelay1  = 10;
const byte ConcRelay2  = 11;
const byte CompRelay3  = 12;
const byte ValveRelay4 = 13;

const int Start = 88;
const int Stop  = 92;

#else

#include <LiquidCrystal_I2C.h> //allows interfacing with LCD screens
#include <Bounce2.h> //Button debouncing library

//Inputs
int pressureInput = A7; //sets the analog input pin for the pressure transducer
int RedEnd = 10; //sets address of end loop button on Nano digital pins

//Digital Outputs
int ConcRelay1 = 2; //sets address of concentrator1 relay on digital pins found on Nano
int ConcRelay2 = 3; //sets address of concentrator2 relay on digital pins found on Nano
int CompRelay3 = 4; //sets address of compressor relay on digital pins found on Nano
int ValveRelay4 = 5; //sets address of unloader valve relay on digital pins found on Nano

//Start and stop pressure values
const int Start = 40; //concentrators and compressor start at 40 PSI
const int Stop = 85; //concentrators and compressor stop at 85 PSI

#endif

LiquidCrystal_I2C lcd (0x27, 16, 2); //sets the LCD I2C communication address; format (address, columns, rows)
Bounce debouncer = Bounce (); //instantiates a bounce object

// -----------------------------------------------------------------------------

// this is the EEPROM section
int eeAddress1 = 10;                // this sets the eeAddress1 tag and sets the address to 10, eeprom
int eeAddress2 = 20;                // this sets the eeAddress2 tag and sets the address to 20, eeprom

//Debounce section
int buttonState;                    // this set the tag "buttonState", to the current button state from the input pin
int lastButtonState = HIGH;          // this set the tag "lastButtonState", to the previous button state from the input pin
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 100;  // the debounce time; increase if the output flickers

// this is the "Clock"
unsigned long previousTime = 0;            // this sets the tag "previousTime", that will store the last time "delay" that was updated (unnecessary?)
unsigned long psiStopTime;               // time the PSI reached the stop point
unsigned long psiStartTime;             // time the PSI reached the start point

const long solenoidInterval = 30000;  // sets the interval time for solenoid to be open (30s)
const long warmInterval = 15000;     // sets time interval for concentrators to be on with valve open prior to compressor start

// -----------------------------------------------------------------------------
void setup () //setup routine, runs once when system turned on or reset
{
    //  this section assigns the inputs and outputs
 
    // inputs
    pinMode (RedEnd,INPUT_PULLUP);              // End loop button
    debouncer.attach (RedEnd);                // Attach the debouncer to REDEND with INPUT_PULLUP mode
    debouncer.interval (debounceDelay);   // interval in ms

    // outputs
    pinMode      (ConcRelay1, OUTPUT);            // concentrator1 relay
    digitalWrite (ConcRelay1, LOW);        // initially sets output tag "ConcRelay1" low
    pinMode      (ConcRelay2, OUTPUT);          // concentrator2 relay
    digitalWrite (ConcRelay2, LOW);       // initially sets output tag "ConcRelay2" low
    pinMode      (CompRelay3, OUTPUT);            // comperssor relay
    digitalWrite (CompRelay3, LOW);         // initially sets output tag "CompRelay3" low
    pinMode      (ValveRelay4, OUTPUT);         // unloader valve relay
    digitalWrite (ValveRelay4, LOW);      // initially sets output tag "ValveRelay4" low 
  
    // Retrieves the setpoints from the arduino eeprom so the unit can start up after a power fail
    EEPROM.get (eeAddress1, Start);         // retrieves the start psi from eeprom
    EEPROM.get (eeAddress2, Stop);          // retrieves the stop psi from eeprom
  
    //  Starts up the different libraries
    Serial.begin (9600); // start the serial monitor at 9600 baud
    lcd.init ();         // start the lcd library
    lcd.backlight ();    // turn on the lcd backlight
    lcd.clear ();        // clear the cld screen
    Wire.begin ();       // start the I2C library

    //Start up messge
    lcd.setCursor (2,0); //sets cursor to column 2, row 0
    lcd.print ("Hello There!"); //prints label
    lcd.setCursor (0,1); //sets cursor to column 0, row 1
    lcd.print ("Starting in 3sec");

    delay (3000);
    lcd.clear ();
}

// -----------------------------------------------------------------------------
void loop ()
{
    // this section monitors the live psi and turns the compressor and concentrators on or off based off setpoints
    int psi = analogRead (pressureInput);

    // this maps the raw analog input value to the converted PSI value         
    psi = map (psi, 102, 922, 0, 150);

    // if psi is greater then turn off concentrator 1, 2 & compressor
    if (psi >= Stop )
        digitalWrite (ConcRelay1 ,  LOW);
    if (psi >= Stop )
        digitalWrite (ConcRelay2 ,  LOW);
    if (psi >= Stop )
        digitalWrite (CompRelay3 ,  LOW);

    // this section keeps track of the millis counts (this is the "clock!")
    // millis is running in the background so any program delays wont effect the timing
    unsigned long currentMillis = millis (); // updates and holds a copy of the SecondMillis
    if (psi >= Stop ){
        digitalWrite (ValveRelay4 , HIGH);        // if psi is greater than stop setpoint turn on solenoid valve
        psiStopTime = currentMillis; // sets the time the stop point was reached to current time
    }

    if ( (currentMillis - psiStopTime) >= solenoidInterval){
        digitalWrite (ValveRelay4 , LOW);
    } //cuts power to solenoid after solenoidInterval time  

    if (psi <= Start){
        digitalWrite (ConcRelay1 , HIGH); // if psi is less than start setpoint turn on concentrator1
        digitalWrite (ConcRelay2 , HIGH); // if psi is less than start setpoint turn on concentrator2
        digitalWrite (ValveRelay4 , HIGH); // if psi is less than than start setpoint turn on solenoid valve
        psiStartTime = currentMillis; 
    }

    // allows concentrators to warm up prior to starting compressor, O2 purged through valve
    if ( (currentMillis - psiStartTime) >= warmInterval){
        digitalWrite (ValveRelay4 , LOW);   //cuts power to solenoid after warmInterval time 
        digitalWrite (CompRelay3 , HIGH);         // if psi is less than start setpoint turn on compressor after warmInterval
    }
  
    // This section prints the PSI value caluculated from transducer to the LCD screeen
    Serial.print (psi, 1); //prints value from previous line to serial
    Serial.println ("psi"); //prints label to serial

    lcd.setCursor (0,0); //sets cursor to column 0, row 0
    lcd.print ("Current= "); //prints label
    lcd.setCursor (10,0); //sets cursor to column 10, row 0
    lcd.print (psi); //prints pressure value to lcd screen
    lcd.setCursor (12,0); //sets cursor to column 12, row 0
    lcd.print ("PSI"); //prints label after value
    lcd.print ("   "); //to clear the display after large values or negatives

    lcd.setCursor (0,1); //sets cursor to column 0, row 1
    lcd.print ("Min=40 ; Max=85"); //prints Start and Stop pressure values



    // Update the Bounce instance :
    debouncer.update ();

   // this section defines function of RedEnd button 
    if (digitalRead (RedEnd)== LOW){
        digitalWrite (ConcRelay1 ,  LOW);
        digitalWrite (ConcRelay2 ,  LOW);
        digitalWrite (CompRelay3 ,  LOW); 
        digitalWrite (ValveRelay4 , HIGH);
     
  
        // Notifies that the end cycle button has been pressed
        lcd.clear ();
        lcd.setCursor (1,0); //sets cursor to column 1, row 0
        lcd.print ("Program Ended!"); //prints label
        lcd.setCursor (0,1); //sets cursor to column 0, row 1
        lcd.print ("60s to shut down"); //prints label

        delay (60000);
    }
}

Hi gcjr-

I agree the formatting is bad in my post after seeing yours. It makes review difficult. I will be reformatting in the next revision.

This is true which is why I was thinking about using while conditions for the the pressure ranges that the compressor would be on and off. I think that would solve the issue of the currentMillis being taken over and over. Is this a logical solution to you?

if there's no need to monitor anything else, you could simply use a delay.

but you still need to recognize the event

    if (psi >= Stop )

the above is repeated numerous times. it would make more sense that there is simply one place where that condition is tested and executed. same for

    if (psi<=Start)

not clear what the RedEnd input should do. it prevents other actions for 1 minute, but it is not like on on off switch

Hi again Idaho-

The delay is actually for a kill button, which when pressed puts all components of the system in a state which is safe to shut down the controller. The 60 seconds just gives me time to turn it off. This feature is actually working pretty well.

An example of the code I'm having trouble with is below.

In this case the psi has fallen below the start threshold. What should happen is the unloader solenoid (ValveRelay4) activates, stays on for 15 seconds (warmInterval) and then turns off, and stays off.

What is actually happening is that the unloader solenoid is on, and turns off briefly every 15 seconds in a loop. I can see the error in my logic in the code but I'm unsure of the best way to get it to perform as I expect. I was thinking of using while conditions, but I don't have experience with them. If using a while loop do I need to have the pressure monitoring and LCD setup in each while condition?

I have considered using a delay but I don't think that would solve the problem. I think that would just freeze those components for the delay time but I still encounter the issue of the unloader valve (ValveRelay4) turning off briefly every 15 seconds (warmInterval) rather than staying on for 15 seconds and turning off again until the psi<=Start is met again. Please see below.

The RedEnd input just puts all components of the system in a state which is safe to shut down the controller. The delay gives me 60 seconds to flip the off switch. This function is working as intended, to my surprise!

@Koepel I think your suggestion of using a boolean variable is a good one but I'm unsure how to implement it into my code given the example above. Do you think that would solve the the issue I'm experiencing and if so can you maybe give pseudo code example of how that might look?

Thanks very much to everyone for their suggestions, this is a great learning experience and I'm really thankful to have access to this communities knowledge set!

take a look at following

#include <Wire.h> //allows communication over i2c devices
#include <EEPROM.h> //Electronically erasable programmable memory library

#define MyHW
#ifdef MyHW
struct LiquidCrystal_I2C  {
    LiquidCrystal_I2C (int a, int b, int c)  { };

    void clear (void)            { Serial.println (); };
    void backlight (void)  { };
    void init  (void)  { };
    void setCursor  (int a, int b)  { };

    void print  (char *s)        { Serial.print (s); };
    void print  (const char *s)  { Serial.print (s); };
    void print  (int i)          { Serial.print (i); };
};

struct Bounce {
    void attach (int pin)  { };
    void interval (int i)  { };
    void update (void)  { };
};

const int  pressureInput = A0;

const byte RedEnd      = A1;

const byte ConcRelay1  = 10;
const byte ConcRelay2  = 11;
const byte CompRelay3  = 12;
const byte ValveRelay4 = 13;

const int Start = 88;
const int Stop  = 92;

const long solenoidInterval = 5000;
const long warmInterval     = 3000;

// -------------------------------------
#else

#include <LiquidCrystal_I2C.h> //allows interfacing with LCD screens
#include <Bounce2.h> //Button debouncing library

//Inputs
int pressureInput = A7; //sets the analog input pin for the pressure transducer
int RedEnd = 10; //sets address of end loop button on Nano digital pins

//Digital Outputs
int ConcRelay1 = 2; //sets address of concentrator1 relay on digital pins found on Nano
int ConcRelay2 = 3; //sets address of concentrator2 relay on digital pins found on Nano
int CompRelay3 = 4; //sets address of compressor relay on digital pins found on Nano
int ValveRelay4 = 5; //sets address of unloader valve relay on digital pins found on Nano

//Start and stop pressure values
const int Start = 40; //concentrators and compressor start at 40 PSI
const int Stop = 85; //concentrators and compressor stop at 85 PSI

const long solenoidInterval = 30000;  // 30 sec
const long warmInterval     = 15000;  // 15 sec

#endif

LiquidCrystal_I2C lcd (0x27, 16, 2); //sets the LCD I2C communication address; format (address, columns, rows)
Bounce debouncer = Bounce (); //instantiates a bounce object

// -----------------------------------------------------------------------------

// this is the EEPROM section
int eeAddress1 = 10;                // this sets the eeAddress1 tag and sets the address to 10, eeprom
int eeAddress2 = 20;                // this sets the eeAddress2 tag and sets the address to 20, eeprom

//Debounce section
byte butState;

// -----------------------------------------------------------------------------
void setup () //setup routine, runs once when system turned on or reset
{
    //  this section assigns the inputs and outputs
 
    // inputs
    pinMode (RedEnd,INPUT_PULLUP);              // End loop button
    butState = digitalRead (RedEnd);

    // outputs
    pinMode      (ConcRelay1, OUTPUT);            // concentrator1 relay
    digitalWrite (ConcRelay1, LOW);        // initially sets output tag "ConcRelay1" low
    pinMode      (ConcRelay2, OUTPUT);          // concentrator2 relay
    digitalWrite (ConcRelay2, LOW);       // initially sets output tag "ConcRelay2" low
    pinMode      (CompRelay3, OUTPUT);            // comperssor relay
    digitalWrite (CompRelay3, LOW);         // initially sets output tag "CompRelay3" low
    pinMode      (ValveRelay4, OUTPUT);         // unloader valve relay
    digitalWrite (ValveRelay4, LOW);      // initially sets output tag "ValveRelay4" low 
  
    // Retrieves the setpoints from the arduino eeprom so the unit can start up after a power fail
    EEPROM.get (eeAddress1, Start);         // retrieves the start psi from eeprom
    EEPROM.get (eeAddress2, Stop);          // retrieves the stop psi from eeprom
  
    //  Starts up the different libraries
    Serial.begin (9600); // start the serial monitor at 9600 baud
    lcd.init ();         // start the lcd library
    lcd.backlight ();    // turn on the lcd backlight
    lcd.clear ();        // clear the cld screen
    Wire.begin ();       // start the I2C library

    //Start up messge
    lcd.setCursor (2,0); //sets cursor to column 2, row 0
    lcd.print ("Hello There!"); //prints label
    lcd.setCursor (0,1); //sets cursor to column 0, row 1
    lcd.print ("Press button to start");

    lcd.clear ();
}

// -----------------------------------------------------------------------------
void monitor ()
{
    // measure pressure
    int psi = analogRead (pressureInput);
    psi = map (psi, 102, 922, 0, 150);

    // report pressure change
        char s [40];
        sprintf (s, "%3d psi, %3d min, %3d max", psi, Start, Stop);

        lcd.clear     ();
        lcd.setCursor (0,0);
        lcd.print     (s);

    // check for stop condition
    if (psi >= Stop )  {
        digitalWrite (ConcRelay1 ,  LOW);
        digitalWrite (ConcRelay2 ,  LOW);
        digitalWrite (CompRelay3 ,  LOW);
        digitalWrite (ValveRelay4 , HIGH);

        delay (solenoidInterval);
        digitalWrite (ValveRelay4 , LOW);
    }

    else if (psi <= Start){
        digitalWrite (ConcRelay1 , HIGH);
        digitalWrite (ConcRelay2 , HIGH);
        digitalWrite (ValveRelay4 , HIGH);

        delay (warmInterval);

        digitalWrite (ValveRelay4 , LOW);
        digitalWrite (CompRelay3 , HIGH);
    }
}

// -----------------------------------------------------------------------------
void loop ()
{
    enum { ST_IDLE, ST_RUN, ST_SHUTDOWN };
    static int state = ST_IDLE;

    switch (state)  {
    case ST_RUN:
        monitor ();
        break;

    case ST_SHUTDOWN:
        digitalWrite (ConcRelay1 ,  LOW);
        digitalWrite (ConcRelay2 ,  LOW);
        digitalWrite (CompRelay3 ,  LOW); 
        digitalWrite (ValveRelay4 , HIGH);

        lcd.clear ();
        lcd.setCursor (1,0); //sets cursor to column 1, row 0
        lcd.print ("Program Ended!"); //prints label

        state = ST_IDLE;
        break;

    case ST_IDLE:
        break;
    }

    byte but = digitalRead (RedEnd);
    if (butState != but)  {
        butState = but;
        delay (10);         // debounce

        if (LOW == but)  {  // press
            if (ST_IDLE == state)
                state = ST_RUN;
            else
                state = ST_SHUTDOWN;
        }
    }
}

Oh wow, ok, you took this to a whole new level! Thank you so much for taking the time to clean up my chicken scratch and introduce me to some new functions! After spending a couple hours reviewing I think I have some questions...

I'm a little unsure of what's going on here. Why have you assigned const bytes to the inputs and outputs? I don't see where that's necessary later in the code. Again, I'm a beginner so I'm sure I've missed something. Also, in this chunk of code you define the Start and Stop ints, but further down they are redefined using the values I had set? I'm not understanding the significance of const int Start = 88 and
const int Stop = 92, why is it necessary and why have you specifically chosen those values? I have the same question about the solenoid and warm intervals?

Your use of the delay is really very clever and I'm a little jealous I didn't think of it this way. I was dead set on using the millis function but looking at what you've done the delay makes much more sense because pressure does not need to be monitored during the solenoidInterval and warmInterval times, because it won't be changing!

I think I understand what's going on down in the loop but I just want to clarify. So on start up my "Hello there" message will be displayed and will be in ST_idle until I press the RedEnd button which will cause the program to enter into ST_Run? Once in ST_Run the program will loop through the monitor section until I hit the RedEnd again which will initiate the ST_shutdown case?

Again, thanks so much for the guidance here. I understand where my mistake in using the millis function was and have added a couple new functions to my vocabulary.

i think it's important to see different ways to solve problems.

first, set File->Preferences->Compiler Warnings to "More". this way the compiler will generate warnings when simple mistakes are made (e.g. = instead of ==)

it is a Constant (which should be Capitalized) which will make others reading the code aware of and which the compiler will generate an error if the code should attempt to assign a value to

i used a c-preprocessor directive to easily set values more appropriate for MyHardware. i wanted the range to be smaller because the MultiFunction Shield i test with has a multi turn pot and i didn't want to wait 15 and 30 sec.

in this case yes.

but what if you wanted to be able to hit a button to immediately stop the compressor?

yes. but the shutdown case executes just one cycle before advancing to ST_IDLE.

This makes total sense, now that I'm reviewing the code again.

Ok so I tested the code on my hardware and overall I really like the improvements to the functionality, especially the button features, but I'm still haunted by the RelayValve4 only turning off briefly every 15 seconds. The goal is to have RelayValve4 turn on for 15 seconds during ST_RUN then turn off, and stay off, until the else if condition is met.

I would assume that the same problem will arise when the else if condition is met.

This is another problem I'm seeing. The controller is almost constantly in a delay state so I have to keep my finger on the button for 15 or 30 seconds, depending on the condition that's running, in order for the ST_SHUTDOWN register.

Is it possible to put the delay(s) in an initialization state that runs only once when either the if or else if condition is met? I feel like it's groundhog day with this problem.

Here is the code, I had to to get rid of the sprintf function, it wasn't displaying correctly on my LCD. Also I moved the startup message down to the ST_IDLE case.

#include <Wire.h> //allows communication over i2c devices
#include <EEPROM.h> //Electronically erasable programmable memory library
#include <LiquidCrystal_I2C.h> //allows interfacing with LCD screens
#include <Bounce2.h> //Button debouncing library

//Inputs
int pressureInput = A7; //sets the analog input pin for the pressure transducer
int RedEnd = 10; //sets address of end loop button on Nano digital pins

//Digital Outputs
int ConcRelay1 = 2; //sets address of concentrator1 relay on digital pins found on Nano
int ConcRelay2 = 3; //sets address of concentrator2 relay on digital pins found on Nano
int CompRelay3 = 4; //sets address of compressor relay on digital pins found on Nano
int ValveRelay4 = 5; //sets address of unloader valve relay on digital pins found on Nano

//Start and stop pressure values
const int Start = 40; //concentrators and compressor start at 40 PSI
const int Stop = 85; //concentrators and compressor stop at 85 PSI

const long solenoidInterval = 30000;  // 30 sec
const long warmInterval     = 15000;  // 15 sec


LiquidCrystal_I2C lcd (0x27, 16, 2); //sets the LCD I2C communication address; format (address, columns, rows)
Bounce debouncer = Bounce (); //instantiates a bounce object

// -----------------------------------------------------------------------------

// this is the EEPROM section
int eeAddress1 = 10;                // this sets the eeAddress1 tag and sets the address to 10, eeprom
int eeAddress2 = 20;                // this sets the eeAddress2 tag and sets the address to 20, eeprom

//Debounce section
byte butState;

// -----------------------------------------------------------------------------
void setup () //setup routine, runs once when system turned on or reset
{
    //  this section assigns the inputs and outputs
 
    // inputs
    pinMode (RedEnd,INPUT_PULLUP);              // End loop button
    butState = digitalRead (RedEnd);

    // outputs
    pinMode      (ConcRelay1, OUTPUT);            // concentrator1 relay
    digitalWrite (ConcRelay1, LOW);        // initially sets output tag "ConcRelay1" low
    pinMode      (ConcRelay2, OUTPUT);          // concentrator2 relay
    digitalWrite (ConcRelay2, LOW);       // initially sets output tag "ConcRelay2" low
    pinMode      (CompRelay3, OUTPUT);            // comperssor relay
    digitalWrite (CompRelay3, LOW);         // initially sets output tag "CompRelay3" low
    pinMode      (ValveRelay4, OUTPUT);         // unloader valve relay
    digitalWrite (ValveRelay4, LOW);      // initially sets output tag "ValveRelay4" low 
  
    // Retrieves the setpoints from the arduino eeprom so the unit can start up after a power fail
    EEPROM.get (eeAddress1, Start);         // retrieves the start psi from eeprom
    EEPROM.get (eeAddress2, Stop);          // retrieves the stop psi from eeprom
  
    //  Starts up the different libraries
    Serial.begin (9600); // start the serial monitor at 9600 baud
    lcd.init ();         // start the lcd library
    lcd.backlight ();    // turn on the lcd backlight
    lcd.clear ();        // clear the cld screen
    Wire.begin ();       // start the I2C library

    //Start up messge
    lcd.setCursor (2,0); //sets cursor to column 2, row 0
    lcd.print ("Hello There!"); //prints label
    lcd.setCursor (0,1); //sets cursor to column 0, row 1
    lcd.print ("Press Red Button");

    lcd.clear ();
}

// -----------------------------------------------------------------------------
void monitor ()
{
    // measure pressure
    int psi = analogRead (pressureInput);
    psi = map (psi, 102, 922, 0, 150);

// This section prints the PSI value caluculated from transducer to the LCD screeen
  lcd.clear ();
  Serial.print(psi, 1); //prints value from previous line to serial
  Serial.println("psi"); //prints label to serial
  lcd.setCursor(0,0); //sets cursor to column 0, row 0
  lcd.print("Current= "); //prints label
  lcd.setCursor(10,0); //sets cursor to column 10, row 0
  lcd.print(psi); //prints pressure value to lcd screen
  lcd.setCursor(12,0); //sets cursor to column 12, row 0
  lcd.print("PSI"); //prints label after value
  lcd.print("   "); //to clear the display after large values or negatives

  lcd.setCursor(0,1); //sets cursor to column 0, row 1
  lcd.print ("Min=40 ; Max=85"); //prints Start and Stop pressure values

    // check for stop condition
    if (psi >= Stop )  {
        digitalWrite (ConcRelay1 ,  LOW);
        digitalWrite (ConcRelay2 ,  LOW);
        digitalWrite (CompRelay3 ,  LOW);
        digitalWrite (ValveRelay4 , HIGH);

        delay (solenoidInterval);
        
        digitalWrite (ValveRelay4 , LOW);
    }

    else if (psi <= Start){
        digitalWrite (ConcRelay1 , HIGH);
        digitalWrite (ConcRelay2 , HIGH);
        digitalWrite (ValveRelay4 , HIGH);

        delay (warmInterval);

        digitalWrite (ValveRelay4 , LOW);
        digitalWrite (CompRelay3 , HIGH);
    }
}

// -----------------------------------------------------------------------------
void loop ()
{
    enum { ST_IDLE, ST_RUN, ST_SHUTDOWN };
    static int state = ST_IDLE;

    switch (state)  {
    case ST_RUN:
        monitor ();
        break;

    case ST_SHUTDOWN:
        digitalWrite (ConcRelay1 ,  LOW);
        digitalWrite (ConcRelay2 ,  LOW);
        digitalWrite (CompRelay3 ,  LOW); 
        digitalWrite (ValveRelay4 , HIGH);

        lcd.clear ();
        lcd.setCursor (1,0); //sets cursor to column 1, row 0
        lcd.print ("Program Ended!"); //prints label
        delay(45000);
        
        state = ST_IDLE;
        break;

    case ST_IDLE:
       
        lcd.setCursor (2,0); //sets cursor to column 2, row 0
        lcd.print ("Hello There!"); //prints label
        lcd.setCursor (0,1); //sets cursor to column 0, row 1
        lcd.print ("Press Red Button");

        break;
    }

    byte but = digitalRead (RedEnd);
    if (butState != but)  {
        butState = but;
        delay (10);         // debounce

        if (LOW == but)  {  // press
            if (ST_IDLE == state)
                state = ST_RUN;
            else
                state = ST_SHUTDOWN;
        }
    }
}

The program was changed with the following:

  1. used the millis() function.
  2. Variable prevPsiWasStart is used to determine if first time in the start or stop state so can initialize the timer.
  3. Variables inStartTransition & inStopTransition is the timer is counting down to complete the start or a stop.

You can test it from this link

Please try the code:

#include <Wire.h> //allows communication over i2c devices
#include <EEPROM.h> //Electronically erasable programmable memory library
#include <LiquidCrystal_I2C.h> //allows interfacing with LCD screens
#include <Bounce2.h> //Button debouncing library

//Inputs
int pressureInput = A7; //sets the analog input pin for the pressure transducer
int RedEnd = 10; //sets address of end loop button on Nano digital pins

//Digital Outputs
int ConcRelay1 = 2; //sets address of concentrator1 relay on digital pins found on Nano
int ConcRelay2 = 3; //sets address of concentrator2 relay on digital pins found on Nano
int CompRelay3 = 4; //sets address of compressor relay on digital pins found on Nano
int ValveRelay4 = 5; //sets address of unloader valve relay on digital pins found on Nano

//Start and stop pressure values
const int Start = 40; //concentrators and compressor start at 40 PSI
const int Stop = 85; //concentrators and compressor stop at 85 PSI

const long solenoidInterval = 30000;  // 30 sec
const long warmInterval     = 15000;  // 15 sec

//GERRY MOD
bool prevPsiWasStart;
unsigned long prevPsiTime;
bool inStartTransition;
bool inStopTransition;

LiquidCrystal_I2C lcd (0x27, 16, 2); //sets the LCD I2C communication address; format (address, columns, rows)
Bounce debouncer = Bounce (); //instantiates a bounce object

// -----------------------------------------------------------------------------

// this is the EEPROM section
int eeAddress1 = 10;                // this sets the eeAddress1 tag and sets the address to 10, eeprom
int eeAddress2 = 20;                // this sets the eeAddress2 tag and sets the address to 20, eeprom

//Debounce section
byte butState;

// -----------------------------------------------------------------------------
void setup () //setup routine, runs once when system turned on or reset
{
  //  this section assigns the inputs and outputs

  // inputs
  pinMode (RedEnd, INPUT_PULLUP);             // End loop button
  butState = digitalRead (RedEnd);

  // outputs
  pinMode      (ConcRelay1, OUTPUT);            // concentrator1 relay
  digitalWrite (ConcRelay1, LOW);        // initially sets output tag "ConcRelay1" low
  pinMode      (ConcRelay2, OUTPUT);          // concentrator2 relay
  digitalWrite (ConcRelay2, LOW);       // initially sets output tag "ConcRelay2" low
  pinMode      (CompRelay3, OUTPUT);            // comperssor relay
  digitalWrite (CompRelay3, LOW);         // initially sets output tag "CompRelay3" low
  pinMode      (ValveRelay4, OUTPUT);         // unloader valve relay
  digitalWrite (ValveRelay4, LOW);      // initially sets output tag "ValveRelay4" low
  //GERRY MOD
  prevPsiWasStart = false;
  inStartTransition = false;
  inStopTransition = false;

  // Retrieves the setpoints from the arduino eeprom so the unit can start up after a power fail
  EEPROM.get (eeAddress1, Start);         // retrieves the start psi from eeprom
  EEPROM.get (eeAddress2, Stop);          // retrieves the stop psi from eeprom

  //  Starts up the different libraries
  Serial.begin (9600); // start the serial monitor at 9600 baud
  lcd.init ();         // start the lcd library
  lcd.backlight ();    // turn on the lcd backlight
  lcd.clear ();        // clear the cld screen
  Wire.begin ();       // start the I2C library

  //Start up messge
  lcd.setCursor (2, 0); //sets cursor to column 2, row 0
  lcd.print ("Hello There!"); //prints label
  lcd.setCursor (0, 1); //sets cursor to column 0, row 1
  lcd.print ("Press Red Button");

  lcd.clear ();
}

// -----------------------------------------------------------------------------
void monitor ()
{
  // measure pressure
  int psi = analogRead (pressureInput);
  psi = map (psi, 102, 922, 0, 150);

  // This section prints the PSI value caluculated from transducer to the LCD screeen
  lcd.clear ();
  //  Serial.print(psi, 1); //prints value from previous line to serial
  //  Serial.println("psi"); //prints label to serial

  lcd.setCursor(0, 0); //sets cursor to column 0, row 0
  lcd.print("Current= "); //prints label
  lcd.setCursor(10, 0); //sets cursor to column 10, row 0
  lcd.print(psi); //prints pressure value to lcd screen
  lcd.setCursor(12, 0); //sets cursor to column 12, row 0
  lcd.print("PSI"); //prints label after value
  lcd.print("   "); //to clear the display after large values or negatives

  lcd.setCursor(0, 1); //sets cursor to column 0, row 1
  lcd.print ("Min=40 ; Max=85"); //prints Start and Stop pressure values

  // check for stop condition
  if (psi >= Stop )  {
    digitalWrite (ConcRelay1 ,  LOW);
    digitalWrite (ConcRelay2 ,  LOW);
    digitalWrite (CompRelay3 ,  LOW);
									  

    /*GERRY MOD
      digitalWrite (ValveRelay4 , HIGH);

      delay (solenoidInterval);
      digitalWrite (ValveRelay4 , LOW);
    */
    if (prevPsiWasStart == true) { //First time
      prevPsiTime = millis();
      prevPsiWasStart = false;
      inStopTransition = true;
      inStartTransition = false;
    }


  }

  else if (psi <= Start) {
    digitalWrite (ConcRelay1 , HIGH);
    digitalWrite (ConcRelay2 , HIGH);


    /*GERRY MOD
      digitalWrite (ValveRelay4 , HIGH);
      delay (warmInterval);
      digitalWrite (ValveRelay4 , LOW);
      digitalWrite (CompRelay3 , HIGH);
    */
    if (prevPsiWasStart == false) { //First time
      prevPsiTime = millis();
      prevPsiWasStart = true;
      inStartTransition = true;
      inStopTransition = false;
    }
  }

  if (inStopTransition == true) {
    if (millis() - prevPsiTime < solenoidInterval) {
      digitalWrite (ValveRelay4 , HIGH);
      Serial.print("Stop in: ");
      Serial.println(1 + (solenoidInterval - millis() + prevPsiTime) / 1000);
    } else {
      digitalWrite (ValveRelay4 , LOW);
      inStopTransition = false;
      Serial.println("Stop done");
    }
  }
  if (inStartTransition == true) {
    if ((millis() - prevPsiTime < warmInterval)) {
      digitalWrite (ValveRelay4 , HIGH);
      Serial.print("Start in ");
      Serial.println(1 + (- millis() + prevPsiTime + warmInterval) / 1000);
    } else {
      digitalWrite (ValveRelay4 , LOW);
      digitalWrite (CompRelay3 , HIGH);
      inStartTransition = false;
      Serial.println("Start done");
    }
  }


}

// -----------------------------------------------------------------------------
void loop ()
{
  enum { ST_IDLE, ST_RUN, ST_SHUTDOWN };
  static int state = ST_IDLE;

  switch (state)  {
    case ST_RUN:
      monitor ();
      break;

    case ST_SHUTDOWN:
      digitalWrite (ConcRelay1 ,  LOW);
      digitalWrite (ConcRelay2 ,  LOW);
      digitalWrite (CompRelay3 ,  LOW);
      digitalWrite (ValveRelay4 , HIGH);

      lcd.clear ();
      lcd.setCursor (1, 0); //sets cursor to column 1, row 0
      lcd.print ("Program Ended!"); //prints label
      delay(45000);
      //GERRY MOD
      prevPsiWasStart = false;
      inStartTransition = false;
      inStopTransition = false;
      lcd.clear ();

      state = ST_IDLE;
      break;

    case ST_IDLE:

      lcd.setCursor (2, 0); //sets cursor to column 2, row 0
      lcd.print ("Hello There!"); //prints label
      lcd.setCursor (0, 1); //sets cursor to column 0, row 1
      lcd.print ("Press Red Button");

      break;
  }

  byte but = digitalRead (RedEnd);
  if (butState != but)  {
    butState = but;
    delay (10);         // debounce

    if (LOW == but)  {  // press
      if (ST_IDLE == state)
        state = ST_RUN;
      else
        state = ST_SHUTDOWN;
    }
  }
}

1 Like

I did not follow all details that were discussed here.
But I want to give a general advise:
It is always a good idea to write down the behaviour of a program in
normal but precise-naming words and if numbers in any kind are involved using example-numbers (= digits 0-9)

To avoid any misunderstandings caused through misconceptions about coding this description should avoid all programming terms.

As a small example of what I mean:

Pressure tank is at 1 psi
Compressor starts running to increase pressure up to 10 psi

The Arduino measures pressure continously
if pressure reaches 10 psi the unloader-relais shall be switched ON for 15 seconds
......

Such a description gives a clear picture of what the whole code shall do. Based on this description the other users can make a well suiting suggestion to achieve the wanted behaviour (for example a state-machine based on the switch-case statement or whatever)

Focusing on details gives detail answers which might keep the overall structure of the code in a bad suited way.

best regards Stefan

@gerivega : I tried your code in the WOKWI simulator the program was running always updating the display after pressing the button.

I tryied to move this "Push/pull"-Thing (which is a linear potentiometer???)
but the linear potentiometer did just jump once to the right and that's all.

So what should this code demonstrate? non-functional code?
best regards Stefan

yes. i see the problem. it repeatedly executes these conditionals as long as the pressure exceeds the thresholds.

it needs to recognize that the compressor has been run and not do it again unless the pressure is back with range

consider

i added a compressorFlag, compressorOn() and an else condition to clear the flag

#include <Wire.h> //allows communication over i2c devices
#include <EEPROM.h> //Electronically erasable programmable memory library

#define MyHW
#ifdef MyHW
struct LiquidCrystal_I2C  {
    LiquidCrystal_I2C (int a, int b, int c)  { };

    void clear (void)            { Serial.println (); };
    void backlight (void)  { };
    void init  (void)  { };
    void setCursor  (int a, int b)  { };

    void print  (char *s)        { Serial.print (s); };
    void print  (const char *s)  { Serial.print (s); };
    void print  (int i)          { Serial.print (i); };
};

struct Bounce {
    void attach (int pin)  { };
    void interval (int i)  { };
    void update (void)  { };
};

const int  pressureInput = A0;

const byte RedEnd      = A1;

const byte ConcRelay1  = 10;
const byte ConcRelay2  = 11;
const byte CompRelay3  = 12;
const byte ValveRelay4 = 13;

const int Start = 88;
const int Stop  = 92;

const long solenoidInterval = 5000;
const long warmInterval     = 3000;

// -------------------------------------
#else

#include <LiquidCrystal_I2C.h> //allows interfacing with LCD screens
#include <Bounce2.h> //Button debouncing library

//Inputs
int pressureInput = A7; //sets the analog input pin for the pressure transducer
int RedEnd = 10; //sets address of end loop button on Nano digital pins

//Digital Outputs
int ConcRelay1 = 2; //sets address of concentrator1 relay on digital pins found on Nano
int ConcRelay2 = 3; //sets address of concentrator2 relay on digital pins found on Nano
int CompRelay3 = 4; //sets address of compressor relay on digital pins found on Nano
int ValveRelay4 = 5; //sets address of unloader valve relay on digital pins found on Nano

//Start and stop pressure values
const int Start = 40; //concentrators and compressor start at 40 PSI
const int Stop = 85; //concentrators and compressor stop at 85 PSI

const long solenoidInterval = 30000;  // 30 sec
const long warmInterval     = 15000;  // 15 sec

#endif

LiquidCrystal_I2C lcd (0x27, 16, 2); //sets the LCD I2C communication address; format (address, columns, rows)
Bounce debouncer = Bounce (); //instantiates a bounce object

// -----------------------------------------------------------------------------

// this is the EEPROM section
int eeAddress1 = 10;                // this sets the eeAddress1 tag and sets the address to 10, eeprom
int eeAddress2 = 20;                // this sets the eeAddress2 tag and sets the address to 20, eeprom

//Debounce section
byte butState;

// -----------------------------------------------------------------------------
void setup () //setup routine, runs once when system turned on or reset
{
    //  this section assigns the inputs and outputs
 
    // inputs
    pinMode (RedEnd,INPUT_PULLUP);              // End loop button
    butState = digitalRead (RedEnd);

    // outputs
    pinMode      (ConcRelay1, OUTPUT);            // concentrator1 relay
    digitalWrite (ConcRelay1, LOW);        // initially sets output tag "ConcRelay1" low
    pinMode      (ConcRelay2, OUTPUT);          // concentrator2 relay
    digitalWrite (ConcRelay2, LOW);       // initially sets output tag "ConcRelay2" low
    pinMode      (CompRelay3, OUTPUT);            // comperssor relay
    digitalWrite (CompRelay3, LOW);         // initially sets output tag "CompRelay3" low
    pinMode      (ValveRelay4, OUTPUT);         // unloader valve relay
    digitalWrite (ValveRelay4, LOW);      // initially sets output tag "ValveRelay4" low 
  
    // Retrieves the setpoints from the arduino eeprom so the unit can start up after a power fail
    EEPROM.get (eeAddress1, Start);         // retrieves the start psi from eeprom
    EEPROM.get (eeAddress2, Stop);          // retrieves the stop psi from eeprom
  
    //  Starts up the different libraries
    Serial.begin (9600); // start the serial monitor at 9600 baud
    lcd.init ();         // start the lcd library
    lcd.backlight ();    // turn on the lcd backlight
    lcd.clear ();        // clear the cld screen
    Wire.begin ();       // start the I2C library

    //Start up messge
    lcd.setCursor (2,0); //sets cursor to column 2, row 0
    lcd.print ("Hello There!"); //prints label
    lcd.setCursor (0,1); //sets cursor to column 0, row 1
    lcd.print ("Press button to start");

    lcd.clear ();
}

// -----------------------------------------------------------------------------
int compressorFlag;

void compressorOn (
    int     sec )
{
    if (! compressorFlag)  {
        compressorFlag = 1;
        digitalWrite (ValveRelay4 , HIGH);
        delay (sec);
        digitalWrite (ValveRelay4 , LOW);
    }
}

// -----------------------------------------------------------------------------
void monitor ()
{
    // measure pressure
    int psi = analogRead (pressureInput);
    psi = map (psi, 102, 922, 0, 150);

    // report pressure change
        char s [40];
        sprintf (s, "%3d psi, %3d min, %3d max", psi, Start, Stop);

        lcd.clear     ();
        lcd.setCursor (0,0);
        lcd.print     (s);

    // check for stop condition
    if (psi >= Stop )  {
        digitalWrite (ConcRelay1 ,  LOW);
        digitalWrite (ConcRelay2 ,  LOW);
        digitalWrite (CompRelay3 ,  LOW);

        compressorOn (solenoidInterval);
    }

    else if (psi <= Start){
        digitalWrite (ConcRelay1 , HIGH);
        digitalWrite (ConcRelay2 , HIGH);

        compressorOn (warmInterval);

        digitalWrite (CompRelay3 , HIGH);
    }
    else
        compressorFlag = 0;
}

// -----------------------------------------------------------------------------
void loop ()
{
    enum { ST_IDLE, ST_RUN, ST_SHUTDOWN };
    static int state = ST_IDLE;

    switch (state)  {
    case ST_RUN:
        monitor ();
        break;

    case ST_SHUTDOWN:
        digitalWrite (ConcRelay1 ,  LOW);
        digitalWrite (ConcRelay2 ,  LOW);
        digitalWrite (CompRelay3 ,  LOW); 
        digitalWrite (ValveRelay4 , HIGH);

        lcd.clear ();
        lcd.setCursor (1,0); //sets cursor to column 1, row 0
        lcd.print ("Program Ended!"); //prints label

        state = ST_IDLE;
        break;

    case ST_IDLE:
        break;
    }

    byte but = digitalRead (RedEnd);
    if (butState != but)  {
        butState = but;
        delay (10);         // debounce

        if (LOW == but)  {  // press
            if (ST_IDLE == state)
                state = ST_RUN;
            else
                state = ST_SHUTDOWN;
        }
    }
}
1 Like

The slider represents the input analog sensor that reads the psi. So to the left means a low pressure and to the right means there is a high pressure reading.
The LEDs represent the relays. Violet for the valve, Orange for the compressor, cyan for the concentrators.

The programs starts the concentrators, compressors and the valves when the reading is below 40 psi and stops at 85 psi. So 40 and 85 are trigger points.

The added complexity is that when it starts there is a delay for the valve for 15 seconds.
And in turn when it has to stop there is a delay of 30 seconds before valve is switched off.

Hi gerivega,

you seem to have not understood what the problem with the simulation is:

I start the simulation. I keep the left-mouse-button down for 2 seconds to start
The LC-Display gets updated two times per second showing 64 psi
I waited for 20 seconds then clicked on the slider.
The slider jumped to the right. LC-Display shows 16 psi

and that's all that happends nothing more

The slider can't be moved left/right with the mouse any more
and all leds stay OFF


that's what I would call non-functional code

it might be a problem of WOKWI or trying to use WOKWI with firefox
but that's all I see.
best regards Stefan