/*
WWTP_Compressor_Controller_rev24
RedTar4
8/20/19-8/29/19
Analog Resolution is 0-1023 (204.8 per volt or 0.004883v per resolution)
Pressure sensor is linear:
0 psi = 0.5v = 102.4
150 psi = 4.5v = 921.6
*/
// this is the libraries section
#include <Wire.h> // Wire library
#include <LiquidCrystal_I2C.h> // Liquid Crystal I2C library
LiquidCrystal_I2C lcd(0x27,20,4); // Display address 0x27, I2C 20 x 4
#include <EEPROM.h> // EEPROM library
#include <Bounce2.h> // Bounce2 library
Bounce debouncer = Bounce(); // instantiate a bounce object
// this is the digital input button variables section
int P1 = 2; // button SET MENU' // this sets the tag as a discreate input to pin 2
int P2 = 3; // button + // this sets the tag as a discreate input to pin 3
int P3 = 4; // button - // this sets the tag as a discreate input to pin 4
// this is the menu section
int menu = 0; // this sets the variable tag menu to 0
// this is the analog input variable section
int CompPSIRaw = A0; // this sets the tag as an analog input to pin A0
// this is the digital output variables section
int CompAlarm = 9; // this sets the tag as a discrete output to pin 12
int CompRun = 10; // this sets the tag as a discrete output to pin 10
int CompUnloadValve = 11; // this sets the tag as a discrete output to pin 11
int CompDrain = 12; // this sets the tag as a discrete output to pin 12
// this is the variables section
int Start = LOW; // this sets the variable tag that stores the start psi set point tolow
int Stop = LOW; // this sets the variable tag that stores the stop psi set point to low
int CompRunBit = LOW; // this sets the variable tag CompRunBit to low
int CompUnloadValveBit = LOW; // this sets the variable tag CompUnloadValveBit to low
int CompDrainBit = LOW;
int CompDrainOn = LOW; // this sets the variable tag CompDrainOn bit
int CompDrainOff = LOW; // this sets the variable tag CompDrainOff bit
int CompDrainManual = LOW; // this sets the variable tag CompDrainManual to low
int CompDrainOffCalc = 0;
int CompAlarmBitL = LOW; // this sets the variable tag CompAlarmBitL to low
int CompAlarmBitH = LOW; // this sets the variable tag CompAlarmBitH to low
int CompManual = LOW; // this sets the variable tag manual to 0
int CompPSIValue = 0; // this sets the tag CompPSIAlarmL, that will store the value coming from the sensor
int CompPSIAlarmL = LOW; // this sets the tag CompPSIAlarmL, that will store the value for the raw alarm low setpoint
int CompPSIAlarmH = LOW; // this sets the tag CompPSIAlarmH, that will store the value for the raw alarm high setpoint
// 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
int eeAddress3 = 30; // this sets the eeAddress3 tag and sets the address to 30, eeprom
int eeAddress4 = 40; // this sets the eeAddress4 tag and sets the address to 40, eeprom
int eeAddress5 = 50; // this sets the eeAddress5 tag and sets the address to 50, eeprom
int eeAddress6 = 60; // this sets the eeAddress6 tag and sets the address to 60, eeprom
// this is the millis section, the "Clock"
long previousMillis = 0; // this sets the tag "previousMillis", that will store the last time "delay" that was updated
long interval = 30000; // this sets the tag "interval" for the menu(9) return timer
long intervalSec = 500; // this sets the tag "intervalSec", at which to blink (milliseconds), 500 = 1 second, 30000 = 1 minute
int ledStateSec = 0; // this sets the tag "ledStateSec",
// this is the Debounce section
int buttonState; // this set the tag "buttonState", to the current button state from the input pin
int lastButtonState = LOW; // 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
void setup()
{
// this section assigns the inputs and outputs
// inputs
pinMode(P1,INPUT_PULLUP); // button "MENU"
debouncer.attach(P1); // Attach the debouncer to P1 with INPUT_PULLUP mode
debouncer.interval(debounceDelay); // interval in ms
pinMode(P2,INPUT_PULLUP); // button "+" advance
debouncer.attach(P2); // Attach the debouncer to P2 with INPUT_PULLUP mode
debouncer.interval(debounceDelay); // interval in ms
pinMode(P3,INPUT_PULLUP); // button "-" decrease
debouncer.attach(P3); // Attach the debouncer to P3 with INPUT_PULLUP mode
debouncer.interval(debounceDelay); // interval in ms
// outputs
pinMode(CompAlarm, OUTPUT); // comperssor alarm relay
digitalWrite(CompAlarm, LOW); // initially sets output tag "CompAlarm" low
pinMode(CompRun, OUTPUT); // comperssor run relay
digitalWrite(CompRun, LOW); // initially sets output tag "CompRun" low
pinMode(CompUnloadValve, OUTPUT); // comperssor unloader valve relay
digitalWrite(CompUnloadValve, LOW); // initially sets output tag "CompUnloadValve" low
pinMode(CompDrain, OUTPUT); // comperssor drain valve relay
digitalWrite(CompDrain, LOW); // initially sets output tag "CompDrain" low
// this section 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
EEPROM.get(eeAddress3, CompPSIAlarmL); // retrieves the lo alarm from eeprom
EEPROM.get(eeAddress4, CompPSIAlarmH); // retrieves the hi alarm from eeprom
EEPROM.get(eeAddress5, CompDrainOn); // retrieves the hi alarm from eeprom
EEPROM.get(eeAddress6, CompDrainOff); // retrieves the hi alarm from eeprom
// this section 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
}
void loop()
{
// Update the Bounce instance :
debouncer.update();
// this is the menu selection section
if(digitalRead(P1)){menu=menu+1;} // press the MENU(P1)button and advance through the menu index by 1
debouncer.attach(P1); // Attach the debouncer to P1 with INPUT_PULLUP mode
debouncer.interval(debounceDelay); // intervalMin in ms
if(menu==0){DisplayPSI();} // go to the DisplayPSI subroutine
if(menu==1){DisplayStart();} // go to the DisplayStart subroutine
if(menu==2){DisplayStop();} // go to the DisplayStop subroutine
if(menu==3){DisplayAlarmLow();} // go to the DisplayAlarmLow subroutine
if(menu==4){DisplayAlarmHigh();} // go to the DisplayAlarmHigh subroutine
if(menu==5){DisplayCompDrainOn();} // go to the DisplayCompDrainOn subroutine
if(menu==6){DisplayCompDrainOff();} // go to the DisplayCompDrainOff subroutine
if(menu==7){DisplayCompDrainManual();} // go to the DisplayCompDrainManual subroutine
if(menu==8){DisplayCompMan();} // go to the DisplayAutoMan subroutine
if(menu==9){StoreAll(); delay(500); menu=0;} // go to the StoreAll subroutine and set the menu tag to 0
delay(100);
}
// this section declares the minutecount variable and sets its initial values
volatile unsigned long secondCount = 0; // use volatile for shared variables
void DisplayPSI () // main display
{
// 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
// only copies are used so accuracy is mantained
unsigned long currentMillis = millis(); // updates and holds a copy of the SecondMillis
if (currentMillis - previousMillis >= intervalSec)
{
previousMillis = currentMillis; // updates and holds a copy of the previousMillis
if (ledStateSec == LOW ){ledStateSec = HIGH; secondCount = secondCount + 1;}
else {ledStateSec = LOW;}
}
unsigned long secondCopy;
secondCopy = secondCount; //updates and holds a copy of the secondCount
// this section monitors the live psi and turns the compressor run bit on or off based off setpoints
int psi = analogRead(0); // this reads the analog input(A0) and scales it
psi = map(psi, 102, 921, 0, 150); // this maps the raw analog input value to the converted PSI value
if (psi <= Start){CompRunBit = HIGH;} // if psi is less than start setpoint turn on run bit
if (psi >= Stop ){CompRunBit = LOW;} // if psi is greater than stop setpoint turn off run bit
if (psi <= Start){CompUnloadValveBit = LOW;} // if psi is less than start setpoint turn off unload bit
if (psi >= Stop ){CompUnloadValveBit = HIGH;} // if psi is greater than stop setpoint turn on unload bit
// this section monitors the raw analog input for errors
CompPSIValue = analogRead(CompPSIRaw);
if (CompPSIValue < CompPSIAlarmL){CompAlarmBitL = HIGH;} // if comppsivalue is less than the CompPSIAlarmL bit, set alarm low bit high
if (CompPSIValue > CompPSIAlarmL){CompAlarmBitL = LOW;} // if comppsivalue is greater than the CompPSIAlarmL bit, set alarm low bit low
if (CompPSIValue < CompPSIAlarmH){CompAlarmBitH = LOW;} // if comppsivalue is less than the CompAlarmBitH bit, set alarm high bit low
if (CompPSIValue > CompPSIAlarmH){CompAlarmBitH = HIGH;} // if comppsivalue is greater than the CompAlarmBitH bit, set alarm high bit high
// this section controls the drain timing
if (CompDrainOn >= secondCount) {CompDrainBit = HIGH;}
else {CompDrainBit = LOW;}
int CompDrainOffCalc = CompDrainOff * 60;
if (CompDrainOffCalc <= secondCount + 1) {secondCount = 0;}
// this section turns on or off the digital outputs based on the control and alarm bits
digitalWrite(CompRun, CompRunBit && !CompAlarmBitL && !CompAlarmBitH); // comp run safety interlock if sensor fails
digitalWrite(CompUnloadValve, CompUnloadValveBit || CompAlarmBitL || CompAlarmBitH); // comp unload valve safety interlock if sensor fails
digitalWrite(CompAlarm, CompAlarmBitL || CompAlarmBitH); // comp alarm if sensor fails
digitalWrite(CompDrain, CompDrainBit); // comp drain valve
// this is the serial monitor setion for testing and debug. remove the "//" to print value to the serial monitor
// Serial.print(" Sensor raw value ");
// Serial.print(CompPSIValue);
// Serial.print(" Sensor psi value ");
// Serial.print(psi);
// Serial.print(", Start @ ");
// Serial.print(Start);
// Serial.print(", Stop @ ");
// Serial.print(Stop);
// Serial.print(",");
// Serial.print(" Low alarm ");
// Serial.print(CompPSIAlarmL);
// Serial.print(",");
// Serial.print(" High alarm ");
// Serial.print(CompPSIAlarmH);
// Serial.print(", CRB ");
// Serial.print(CompRunBit);
// Serial.print(", CUL ");
// Serial.print(CompUnloadValveBit);
// Serial.print(", CAL ");
// Serial.print(CompAlarmBitL);
// Serial.print(", CAH ");
// Serial.print(CompAlarmBitH);
// Serial.print(" CompDrain ");
// Serial.print(CompDrain);
// Serial.print(" Comp On ");
// Serial.print(CompDrainOn);
// Serial.print(" Comp Off ");
// Serial.print(CompDrainOff);
// Serial.print(" Comp Off calc ");
// Serial.print(CompDrainOffCalc);
// Serial.print(" ledState sec ");
// Serial.print(ledStateSec);
// Serial.print(" intervalSec ");
// Serial.print(intervalSec);
// Serial.print(", Seconds count ");
// Serial.print(secondCount);
// Serial.print(", Seconds copy ");
// Serial.print(secondCopy);
// Serial.print(", Previous Millis ");
Serial.println(previousMillis);
// this is the lcd section
// line 1
lcd.setCursor(0, 0); lcd.print("Currently @ "); // this prints whats in between the quotes
lcd.setCursor(13, 0); lcd.print(" "); // this clears the display field so anything left is deleted
lcd.setCursor(13, 0); lcd.print(psi); // this prints the tag value
lcd.setCursor(17, 0); lcd.print("PSI"); // this prints whats in between the quotes
// line 2
lcd.setCursor(0, 1); lcd.print(" Start @ "); // this prints whats in between the quotes
lcd.setCursor(13, 1); lcd.print(" "); // this clears the display field so anything left is deleted
lcd.setCursor(13, 1); lcd.print(Start); // this prints the tag value
lcd.setCursor(17, 1); lcd.print("PSI"); // this prints whats in between the quotes
// line 3
lcd.setCursor(0, 2); lcd.print(" Stop @ "); // this prints whats in between the quotes
lcd.setCursor(13, 2); lcd.print(" "); // this clears the display field so anything left is deleted
lcd.setCursor(13, 2); lcd.print(Stop); // this prints the tag value
lcd.setCursor(17, 2); lcd.print("PSI"); // this prints whats in between the quotes
// line 4
// this section displays the alarm/run status on lcd line 4
if (CompAlarmBitL && CompAlarmBitH == LOW); // if CompAlarmBitL and CompAlarmBitH alarm bits are low then its true and prints whats below
{
lcd.setCursor(0, 3); lcd.print(" "); // this clears the display field so anything left is deleted
lcd.setCursor(0, 3); lcd.print("Sensor OK "); // this prints whats in between the quotes
lcd.setCursor(11, 3); lcd.print(" Raw "); // this prints whats in between the quotes
lcd.setCursor(16, 3); lcd.print(" "); // this clears the display field so anything left is deleted
lcd.setCursor(16, 3); lcd.print(CompPSIValue); // this prints the tag value
}
if (CompAlarmBitL == HIGH){lcd.setCursor(0, 3); lcd.print("ALARM: "); lcd.setCursor(7, 3); lcd.print("Xmtr Open ");} // if the CompAlarmBitL alarm bit is high then its in alarm and prints text
if (CompAlarmBitH == HIGH){lcd.setCursor(0, 3); lcd.print("ALARM: "); lcd.setCursor(7, 3); lcd.print("Xmtr Short");} // if the CompAlarmBitH alarm bit is high then its in alarm and prints text
}
void DisplayStart() // this menu is for adjusting the start psi setpoint
{
// this section advances to menu 9 after 30 sec's, so the program doesn't stall if left on this menu selection
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval)
{previousMillis = currentMillis; menu = 9;}
// this section reads the +/- buttons and adjusts the start value
if(digitalRead(P2)== HIGH)
{
if (Start == 150){Start = 0;} // 150 is the max, sets back to 0
else {Start = Start + 1;} // incremnent by 1 per button press
}
if(digitalRead(P3) == HIGH)
{
if (Start == 0){Start = 150;} // 0 is the min, sets back to 150
else {Start = Start - 1;} // decrease by 1 per button press
}
// this is the lcd section
lcd.clear();
lcd.setCursor(0, 0); lcd.print(" Start PSI Menu:");
lcd.setCursor(0, 1); lcd.print(" Set Start PSI to");
lcd.setCursor(9, 3); lcd.print(Start,DEC);
delay(100);
}
void DisplayStop() // this menu is for adjusting the stop psi setpoint
{
// this section advances to menu 9 after 30 sec's, so the program doesn't stall if left on this menu selection
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval)
{previousMillis = currentMillis; menu = 9;}
// this section reads the +/- buttons and adjusts the stop value
if(digitalRead(P2) == HIGH)
{
if (Stop == 150){Stop = 0;} // 150 is the max, sets back to 0
else {Stop = Stop + 1;} // incremnent by 1 per button press
}
if(digitalRead(P3) == HIGH)
{
if (Stop == 0){Stop = 150;} // 0 is the min, sets back to 150
else {Stop = Stop - 1;} // decrease by 1 per button press
}
// this is the lcd section
lcd.clear();
lcd.setCursor(0, 0); lcd.print(" Stop PSI Menu:");
lcd.setCursor(0, 1); lcd.print(" Set Stop PSI to");
lcd.setCursor(9, 3); lcd.print(Stop,DEC);
delay(100);
}
void DisplayAlarmLow() // this menu is for adjusting the raw alarm low setpoint
{
// this section advances to menu 9 after 30 sec's, so the program doesn't stall if left on this menu selection
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval)
{previousMillis = currentMillis; menu = 9;}
// this section reads the +/- buttons and adjusts the raw low alarm setpoint
if(digitalRead(P2) == HIGH)
{
if (CompPSIAlarmL == 1023){CompPSIAlarmL = 0;} // 1023 is the max, sets to 0
else {CompPSIAlarmL = CompPSIAlarmL + 1;} // increase by 1 per button press
}
if(digitalRead(P3) == HIGH)
{
if (CompPSIAlarmL == 0){CompPSIAlarmL = 1023;} // 0 is the min, sets to 1023
else {CompPSIAlarmL = CompPSIAlarmL - 1;} // decrease by 1 per button press
}
// this is the lcd section
lcd.clear();
lcd.setCursor(0, 0); lcd.print(" Raw Alarm Lo Menu:");
lcd.setCursor(0, 1); lcd.print(" Set Lo Alarm to");
lcd.setCursor(9, 3); lcd.print(CompPSIAlarmL,DEC);
delay(100);
}
void DisplayAlarmHigh() // this menu is for adjusting the raw alarm high setpoint
{
// this section advances to menu 9 after 30 sec's, so the program doesn't stall if left on this menu selection
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval)
{previousMillis = currentMillis; menu = 9;}
// this section reads the +/- buttons and adjusts the raw high alarm setpoint
if(digitalRead(P2) == HIGH)
{
if (CompPSIAlarmH == 1023){CompPSIAlarmH = 0;} // 1023 is the max, sets to 0
else {CompPSIAlarmH = CompPSIAlarmH + 1;} // increase by 1 per button press
}
if(digitalRead(P3) == HIGH)
{
if (CompPSIAlarmH == 0){CompPSIAlarmH = 1023;} // 0 is the min, sets to 1023
else {CompPSIAlarmH = CompPSIAlarmH - 1;} // decrease by 1 per button press
}
// this is the lcd section
lcd.clear();
lcd.setCursor(0, 0); lcd.print(" Raw Alarm Hi Menu:");
lcd.setCursor(0, 1); lcd.print(" Set Hi Alarm to");
lcd.setCursor(9, 3); lcd.print(CompPSIAlarmH,DEC);
delay(100);
}
void DisplayCompDrainOn() // this menu is for adjusting the drain on time setpoint
{
// this section advances to menu 9 after 30 sec's, so the program doesn't stall if left on this menu selection
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval)
{previousMillis = currentMillis; menu = 9;}
// this section reads the +/- buttons and adjusts the drain on/off setpoint
if(digitalRead(P2) == HIGH)
{
if (CompDrainOn == 10){CompDrainOn = 0;} // 10 is the max, sets to 0
else {CompDrainOn = CompDrainOn + 1;} // increase by 1 per button press
}
if(digitalRead(P3) == HIGH)
{
if (CompDrainOn == 0){CompDrainOn = 10;} // 0 is the min, sets to 10
else {CompDrainOn = CompDrainOn - 1;} // decrease by 1 per button press
}
// this is the lcd section
lcd.clear();
lcd.setCursor(0, 0); lcd.print(" Drain On: ");
lcd.setCursor(0, 1); lcd.print("Set Drain on in sec");
lcd.setCursor(9, 3); lcd.print(CompDrainOn,DEC);
delay(100);
}
void DisplayCompDrainOff() // this menu is for adjusting the drain off time setpoint
{
// this section advances to menu 9 after 30 sec's, so the program doesn't stall if left on this menu selection
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval)
{previousMillis = currentMillis; menu = 9;}
// this section reads the +/- buttons and adjusts the drain on/off setpoint
if(digitalRead(P2) == HIGH)
{
if (CompDrainOff == 45){CompDrainOff = 0;} // 45 is the max, sets to 0
else {CompDrainOff = CompDrainOff + 1;} // increase by 1 per button press
}
if(digitalRead(P3) == HIGH)
{
if (CompDrainOff == 0){CompDrainOff = 45;} // 0 is the min, sets to 45
else {CompDrainOff = CompDrainOff - 1;} // decrease by 1 per button press
}
// this is the lcd section
lcd.clear();
lcd.setCursor(0, 0); lcd.print(" Drain off:");
lcd.setCursor(0, 1); lcd.print("Set Drain Off in min");
lcd.setCursor(9, 3); lcd.print(CompDrainOff,DEC);
delay(100);
}
void DisplayCompDrainManual() // this menu is for manually turning the drain on/off
{
// this section advances to menu 9 after 30 sec's, so the program doesn't stall if left on this menu selection
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval)
{previousMillis = currentMillis; menu = 9;}
// this section reads the +/- buttons and adjusts the raw high alarm setpoint
if(digitalRead(P2) == HIGH)
{
if (CompDrainManual == 1){CompDrainManual = 0;} // 1 is the max, sets to 0
else {CompDrainManual = CompDrainManual + 1;} // increase by 1 per button press
}
if(digitalRead(P3) == HIGH)
{
if (CompDrainManual == 0){CompDrainManual = 1;} // 0 is the min, sets to 1
else {CompDrainManual = CompDrainManual - 1;} // decrease by 1 per button press
}
digitalWrite(CompDrain, CompDrainManual); // turns on/off compDrain relay based on CompDrainManual
// this is the lcd section
lcd.clear();
lcd.setCursor(0, 0); lcd.print(" Comp Drain Man:");
lcd.setCursor(0, 1); lcd.print(" UP to turn On/Off");
if (CompDrainManual == HIGH){ lcd.setCursor(0, 3); lcd.print("Comp Drain, On");}
if (CompDrainManual == LOW){ lcd.setCursor(0, 3); lcd.print("Comp Drain, Off");}
delay(100);
}
void DisplayCompMan() // this menu is for manually turning on and off the compressor relay and unload valve relay
{
// this section reads the +/- buttons and adjusts the raw high alarm setpoint
if(digitalRead(P2) == HIGH)
{
if (CompManual == 1){CompManual = 0;} // 1 is the max, sets to 0
else {CompManual = CompManual + 1;} // increase by 1 per button press
}
if(digitalRead(P3) == HIGH)
{
if (CompManual == 0){CompManual = 1;} // 0 is the min, sets to 1
else {CompManual = CompManual - 1;} // decrease by 1 per button press
}
digitalWrite(CompRun, CompManual); // turns on comp run relay if Compmanual = 1
digitalWrite(CompUnloadValve, !CompManual); // turns off comp unload relay if Compmanual != 1
// this is the lcd section
lcd.clear();
lcd.setCursor(0, 0); lcd.print(" Compressor Man:");
lcd.setCursor(0, 1); lcd.print(" UP to turn On/Off");
if (CompManual == HIGH){ lcd.setCursor(0, 2); lcd.print("Comp On, Unload Off");}
if (CompManual == LOW){ lcd.setCursor(0, 2); lcd.print("Comp Off, Unload On");}
lcd.setCursor(0, 3); lcd.print("Dont forget to exit!");
delay(100);
}
// this section stores the setpoints into the arduino eeprom so the unit can start up after a power fail
void StoreAll()
{
lcd.clear();
EEPROM.put(eeAddress1, Start); // saves the start psi setpoint to eeprom if different from before
EEPROM.put(eeAddress2, Stop); // saves the stop psi setpoint to eeprom if different from before
EEPROM.put(eeAddress3, CompPSIAlarmL); // saves the raw low alarm setpoint to eeprom if different from before
EEPROM.put(eeAddress4, CompPSIAlarmH); // saves the raw high alarm setpoint to eeprom if different from before
EEPROM.put(eeAddress5, CompDrainOn); // retrieves the drain on time from eeprom
EEPROM.put(eeAddress6, CompDrainOff); // retrieves the drain off time from eeprom
// this is the lcd section
lcd.setCursor(0,0); lcd.print("SAVING IN");
lcd.setCursor(0,1); lcd.print("PROGRESS");
delay(400);
}
Comments