#include "Wire.h" //allows communication over i2c devices
#include "LiquidCrystal_I2C.h" //allows interfacing with LCD screens
#include <avr/pgmspace.h>
#define relay1 A2
#define relay2 A3
#define menu 4
#define up 5
#define down 6
#define set 7
//Pressure sensor 1
const int pressureInput1 = A1; //select the analog input pin for the pressure transducer
const int pressureInput2 = A0;
const int pressureZero = 88.064; //analog reading of pressure transducer at 0psi
const int pressureMax = 921.6; //analog reading of pressure transducer at 100psi
const int pressuretransducermaxPSI = 100; //psi value of transducer being used
const int baudRate = 9600; //constant integer to set the baud rate for serial monitor
const int sensorreadDelay = 250; //constant integer to set the sensor read delay in milliseconds
int Ratio_CV[9] = {100 , 90 , 80 , 70 , 60, 50, 40, 30, 20};
int index_ratio=0;
const char* valve[2] = {"TDV_A" , "TDV_S"};
const char* model_A[38] = {"50x50" ,"65x65" ,"80x65" ,"80x80" ,"100x65" ,"100x80" ,"100x100",
"125x80" ,"125x100" ,"125x125" ,"150x100" ,"150x125" ,"150x150" ,"200x125" ,"200x150",
"200x200" ,"250x150" ,"250x200" ,"250x250" ,"300x150" ,"300x200" ,"300x250" ,"300x300",
"350x200" ,"350x250" ,"350x300" ,"350x350" ,"400x250" ,"400x300" ,"400x400" ,"450x250",
"450x300" ,"450x450" ,"500x350" ,"500x500" ,"600x600" ,"700x500" ,"700x700"};
const char* model_S[14] ={"50x50" ,"65x65" ,"80x80" ,"100x100" ,"125x125" ,"150x150" ,
"200x200" ,"250x250" ,"300x300", "350x350","400x400","450x450","500x500","600x600"};
bool ratio_setting = false;
int model_index = 0;
int model_index_temp = 0;
int index_S=0;
bool settings = false;
bool save_settings = false;
const int CV_A[38][9] PROGMEM=
{
{75, 72, 67, 60, 52, 45, 36, 27, 18},
{124, 119, 110, 98, 86, 73, 59, 45, 29},
{126, 121, 113, 100, 88, 75, 60, 46, 30},
{172, 165, 153, 136, 120, 102, 82, 63, 41},
{129, 124, 115, 102, 90, 77, 61, 47, 31},
{173, 166, 155, 138, 121, 103, 82, 63, 41},
{364, 350, 325, 290, 255, 217, 173, 133, 87},
{175, 168, 156, 139, 122, 104, 83, 64, 42},
{366, 351, 327, 291, 256, 217, 174, 134, 87},
{526, 505, 470, 418, 368, 313, 250, 193, 125},
{369, 354, 329, 293, 258, 219, 175, 135, 88},
{529, 508, 472, 420, 370, 314, 252, 194, 126},
{831, 798, 742, 660, 581, 494, 395, 304, 198},
{531, 510, 474, 422, 371, 316, 253, 194, 126},
{833, 799, 743, 662, 582, 495, 396, 305, 198},
{1485, 1425, 1325, 1180, 1038, 882, 706, 544, 353},
{834, 801, 745, 663, 583, 496, 397, 305, 199},
{1486, 1426, 1326, 1180, 1039, 883, 706, 544, 354},
{2475, 2376, 2210, 1967, 1731, 1471, 1177, 906, 589},
{838, 804, 748, 666, 586, 498, 398, 307, 199},
{1487, 1427, 1327, 1181, 1040, 884, 707, 544, 354},
{2477, 2378, 2211, 1968, 1732, 1472, 1178, 907, 589},
{3076, 2953, 2746, 2444, 2151, 1828, 1462, 1126, 732},
{1487, 1428, 1328, 1182, 1040, 884, 707, 545, 354},
{2478, 2379, 2213, 1969, 1733, 1473, 1178, 907, 590},
{3077, 2954, 2747, 2445, 2152, 1829, 1463, 1127, 732},
{3570, 3427, 3187, 2837, 2496, 2122, 1698, 1307, 850},
{2479, 2380, 2213, 1970, 1733, 1473, 1179, 908, 590},
{3080, 2957, 2750, 2447, 2154, 1831, 1464, 1128, 733},
{4796, 4605, 4282, 3811, 3354, 2851, 2281, 1756, 1141},
{2482, 2383, 2216, 1972, 1736, 1475, 1180, 909, 591},
{3081, 2958, 2751, 2448, 2155, 1831, 1465, 1128, 733},
{6058, 5816, 5408, 4814, 4236, 3601, 2880, 2218, 1442},
{3576, 3433, 3192, 2841, 2500, 2125, 1700, 1309, 851},
{7479, 7180, 6677, 5943, 5230, 4445, 3566, 2738, 1780},
{10770, 10339, 9615, 8558, 7531, 6401, 5121, 3943, 2563},
{7481, 7182, 6679, 5944, 5231, 4446, 3557, 2739, 1780},
{15128, 14523, 13506, 12021, 10578, 8991, 7193, 5539, 3600}
};
int CV_S[14][9]=
{
{62, 60, 55, 49, 43, 37, 29, 23, 15},
{90, 86, 80, 72, 63, 53, 43, 33, 21},
{140, 134, 125, 111, 98, 83, 67, 51, 33},
{300, 288, 268, 238, 210, 178, 143, 110, 71},
{428, 411, 382, 340, 299, 254, 204, 157, 102},
{673, 646, 601, 535, 471, 400, 320, 246, 160},
{1200, 1152, 1071, 954, 839, 713, 571, 439, 286},
{2000, 1920, 1786, 1589, 1398, 1189, 951, 732, 476},
{2500, 2400, 2232, 1986, 1748, 1486, 1189, 915, 595},
{2900, 2784, 2589, 2304, 2028, 1724, 1379, 1062, 690},
{3900, 3744, 3482, 3099, 2727, 2318, 1854, 1428, 928},
{5200, 4992, 4643, 4132, 3636, 3091, 2473, 1904, 1237},
{7000, 6720, 6250, 5562, 4895, 4160, 3328, 2563, 1666},
{8800, 8448, 7857, 6992, 6154, 5230, 4184, 3222, 2094}
};
bool valve_type = false;
bool valve_type_temp = false;
float pressureValue1_psi = 0;
float pressureValue2_psi = 0;
float pressureValue1_bar = 0;
float pressureValue2_bar = 0;
float pressureValue12_psi=0;
float pressureValue12_bar=0;
//set initial values for set point in both bar and PSI
float set_point1_m3_h = 123;
float set_point1_m3_h_temp = 123;
float set_point1_usgpm = 4.403*123;
float set_point2_m3_h = 150;
float set_point2_m3_h_temp = 150;
float set_point2_usgpm = 4.403*150;
float orig_dppsi = 0;
float orig_dpbar = 0;
float flowrate_m3_h = 0.0;
float flowrate_usgpm = 0.0;
int CvValue=0; // Cv value for the valve
int Ratio=100;
bool first_screen=true;
//custom datatype define to do pressure setting in different units
enum unit_pressure {psi , bar};
// default unit for pressue
unit_pressure current_unit_P = psi;
//custom datatype define to do pressure setting in different units
enum unit_flow {m3_h , usgpm};
// default unit for pressue
unit_flow current_unit_F = m3_h;
//defining variables for pressure tracking in both bar and PSI
float flowValue1_psi = 0;
float flowValue1_bar = 0;
float flowValue2_psi = 0;
float flowValue2_bar = 0;
unsigned char selectedItem = 0;
LiquidCrystal_I2C lcd(0x27, 20, 4);
void setup() {
Serial.begin(9600);
pinMode(up, INPUT);
pinMode(down, INPUT);
pinMode(set, INPUT);
pinMode(menu, INPUT);
model_index=7;
lcd.init();
lcd.backlight();
}
void loop() {
if (readButton(menu) == HIGH) {
delay(200); // Debounce
Serial.print("menu button pressed");
selectedItem = selectedItem + 1;
if(selectedItem > 6) selectedItem = 1;
lcd.clear();
if(save_settings == true)
{
save_settings = false;
settings = false;
selectedItem = 0;
}
}
if(save_settings == false)
{
switch (selectedItem) {
case 0:
displayNormalOperation();
break;
case 1:
displaySettings1();
lcd.setCursor(18,0); lcd.print("<");
break;
case 2:
displaySettings1();
lcd.setCursor(18,1); lcd.print("<");
break;
case 3:
displaySettings1();
lcd.setCursor(18,2); lcd.print("<");
break;
case 4:
displaySettings1();
lcd.setCursor(18,3); lcd.print("<");
break;
case 5:
displaySettings2();
lcd.setCursor(18,0); lcd.print("<");
break;
case 6:
displaySettings2();
lcd.setCursor(18,1); lcd.print("<");
break;
}
}
if(readButton_ud(up) == HIGH)
{
if(ratio_setting)
{
index_ratio--;
if(index_ratio < 0) index_ratio = 8;
}
switch (selectedItem) {
case 0:
break;
case 1:
set_point1_m3_h_temp++;
break;
case 2:
set_point2_m3_h_temp++;
break;
case 3:
valve_type_temp = !valve_type_temp;
if(valve_type_temp==HIGH)
{
if(model_index_temp>13) model_index_temp = 13;
}
break;
case 4:
model_index_temp++;
if(valve_type_temp==LOW)
{
if(model_index_temp>37) model_index_temp = 0;
}
else{
if(model_index_temp>13) model_index_temp = 0;
}
break;
case 5:
break;
case 6:
break;
}
}
if(readButton_ud(down) == HIGH)
{Serial.println("down pressed");
if(ratio_setting)
{
index_ratio++;
if(index_ratio >= 9) index_ratio = 0;
}
switch (selectedItem) {
case 0:
break;
case 1:
set_point1_m3_h_temp--;
break;
case 2:
set_point2_m3_h_temp--;
break;
case 3:
valve_type_temp = !valve_type_temp;
if(valve_type_temp==HIGH)
{
if(model_index_temp>13) model_index_temp = 13;
}
break;
case 4:
model_index_temp--;
if(valve_type_temp == LOW)
{
if(model_index_temp<0) model_index_temp = 37;
}
else{
if(model_index_temp<0) model_index_temp = 14;
}
break;
case 5:
break;
case 6:
break;
}
}
if(readButton(set) == HIGH)
{
if(settings == false)
{
ratio_setting = !ratio_setting;
Serial.println(ratio_setting);
}
if(save_settings == true)
{
set_point1_m3_h = set_point1_m3_h_temp;
set_point2_m3_h = set_point2_m3_h_temp;
valve_type = valve_type_temp;
model_index = model_index_temp;
save_settings = false;
settings = false;
selectedItem = 0;
}
if(settings == true)
{
displaySaveScreen();
}
}
delay(100); // Small delay to prevent flickering
}
void displayNormalOperation() {
settings = false;
save_settings = false;
set_point1_m3_h_temp = set_point1_m3_h;
set_point2_m3_h_temp = set_point2_m3_h;
valve_type_temp = valve_type;
model_index_temp = model_index;
if(valve_type == LOW)
{CvValue=pgm_read_word_near(&(CV_A[model_index][index_ratio]));}
else
{CvValue=CV_S[model_index][index_ratio];}
pressure_measurement();
flowrate_m3_h= (sqrt(abs(pressureValue12_psi)) / 1.167) * CvValue;
flowrate_usgpm = (sqrt(abs(pressureValue12_bar)) / 1.167) * CvValue;
lcd.setCursor(0,0); //sets cursor to column 0, row 0
lcd.print("FLOW :"); //prints label
lcd.print(flowrate_m3_h, 1); //prints flowrate_psi value to lcd screen, 1 digit on float
lcd.print("M3/H "); //prints label
lcd.print(" "); //prints label
if(ratio_setting)
{
lcd.setCursor(19,1); lcd.print("<");
}
else{
lcd.setCursor(19,1); lcd.print(" ");
}
lcd.setCursor(0,1); //sets cursor to column 0, row 1
lcd.print("RATIO :"); //prints label
lcd.print(Ratio_CV[index_ratio]); //prints Ratio value to lcd screen, 1 digit on float
lcd.print("%"); //prints label after value
lcd.print(" "); //to clear the display after large values or negatives
lcd.setCursor(0,2); //sets cursor to column 0, row 2
lcd.print("LIVE DP:"); //prints label
lcd.print(pressureValue12_psi, 1); //prints pressure value to lcd screen, 2 digit on float
lcd.print("psi"); //prints label after value
lcd.print(" "); //to clear the display after large values or negatives
lcd.setCursor(0,3); //sets cursor to column 0, row 3
lcd.print(" SP1:"); //prints label
lcd.print(set_point1_m3_h, 1); //prints pressure value to lcd screen, 2 digit on float
lcd.print(" SP2:"); //prints label after value
lcd.print(set_point2_m3_h , 1);
//turning on relay if condition meet
if(set_point1_m3_h <= flowrate_m3_h)
{
digitalWrite(relay1 , HIGH);
}
else
{//turn off relay if condition do not meet
digitalWrite(relay1 , LOW);
}
//turn on second relay if condition meet
if(set_point2_m3_h <= flowrate_m3_h)
{
digitalWrite(relay2 , HIGH);
}
else
{//turn off relay if condition do not meet
digitalWrite(relay2 , LOW);
}
}
void displaySettings1()
{
settings = true;
save_settings = false;
ratio_setting = false;
lcd.setCursor(0,0); //sets cursor to column 0, row 0
lcd.print("SET SP1:"); //prints label
lcd.print(set_point1_m3_h_temp, 1); //prints flowrate_psi value to lcd screen, 1 digit on float
lcd.print("M3/H "); //prints label
lcd.setCursor(0,1); //sets cursor to column 0, row 1
lcd.print("SET SP2:"); //prints label
lcd.print(set_point2_m3_h_temp, 1); //prints flowrate_psi value to lcd screen, 1 digit on float
lcd.print("M3/H "); //prints label
lcd.setCursor(0,2); //sets cursor to column 0, row 0
lcd.print("VALVE :"); //prints label
lcd.print(valve[valve_type_temp]); //prints flowrate_psi value to lcd screen, 1 digit on float
//lcd.print("M3/H "); //prints label
lcd.setCursor(0,3); //sets cursor to column 0, row 0
lcd.print("MODEL :"); //prints label
if(valve_type == false)
{
lcd.print(model_A[model_index_temp]);
}
else
{
lcd.print(model_S[model_index_temp]);
}
}
void displaySettings2()
{
settings = true;
save_settings = false;
lcd.setCursor(0,0); //sets cursor to column 0, row 0
lcd.print("UNIT(F):"); //prints label
lcd.print("M3/H"); //prints label
lcd.setCursor(0,1); //sets cursor to column 0, row 0
lcd.print("UNIT(P):"); //prints label
lcd.print("BAR"); //prints label
}
void displaySaveScreen()
{
if(save_settings == false)
{
lcd.clear();
}
save_settings = true;
lcd.setCursor(0,0); //sets cursor to column 0, row 0
lcd.print("SAVE THE VALUES?"); //prints label
lcd.setCursor(0,2); //sets cursor to column 0, row 2
lcd.print("PRESS SET TO SAVE"); //prints label
lcd.setCursor(0,3); //sets cursor to column 0, row 3
lcd.print("PRESS MENU TO CANCEL"); //prints label
}
void pressure_measurement()
//function to read pressure values
{
pressureValue1_psi = analogRead(pressureInput1); //reads value from input pin and assigns to variable
pressureValue2_psi = analogRead(pressureInput2);
pressureValue1_psi = ((pressureValue1_psi-pressureZero)*pressuretransducermaxPSI)/(pressureMax-pressureZero); //conversion equation to convert analog reading to psi
pressureValue2_psi = ((pressureValue2_psi-pressureZero)*pressuretransducermaxPSI)/(pressureMax-pressureZero); //conversion equation to convert analog reading to psi
if(pressureValue1_psi< 0) pressureValue1_psi = 0;
if(pressureValue2_psi< 0) pressureValue2_psi = 0;
pressureValue12_psi = pressureValue1_psi - pressureValue2_psi;
// if(pressureValue12_psi < 0) pressureValue12_psi = pressureValue12_psi*-1;
//bar to psi conversion
pressureValue1_bar = pressureValue1_psi/14.5038;
pressureValue2_bar = pressureValue2_psi/14.5038;
pressureValue12_bar = pressureValue12_psi/14.5038;
}
int readButton(int pin) {
if (digitalRead(pin) == HIGH) { // If the button is pressed (HIGH)
unsigned long current_time = millis(); // Capture the current time
while (digitalRead(pin) == HIGH) { // While the button is pressed
}
if((millis() - current_time) >= 100) { // If pressed for at least 100ms
return HIGH;
}
}
return LOW; // If not pressed for 100ms or not pressed at all, return LOW
}
int readButton_ud(int pin) {
if (digitalRead(pin) == HIGH) { // If the button is pressed (HIGH)
unsigned long current_time = millis(); // Capture the current time
while (digitalRead(pin) == HIGH) { // While the button is pressed
if((millis() - current_time) >= 100) { // If pressed for at least 100ms
return HIGH;
}
}
}
return LOW; // If not pressed for 100ms or not pressed at all, return LOW
}