CODE
#include <Keypad.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// LCD setup
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Keypad setup
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {4, 5, 6, 7};
byte colPins[COLS] = {8, 9, 10, 11};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// Flow sensor
const byte flowPin = 2;
volatile int pulseCount = 0;
// Relay
const int relayPin = 12;
// Buzzer
const int buzzerPin = 3;
// Variables
unsigned long setVolume = 0;
unsigned long userSetVolume = 0;
unsigned long currentVolume = 0;
float calibrationFactor = 0.414; // Sensor-specific calibration (pulses/ml)
float userCorrectionFactor = 0.988; // Overfill adjustment
bool filling = false;
unsigned long lastUpdateTime = 0;
void setup() {
Serial.begin(9600);
pinMode(flowPin, INPUT_PULLUP);
pinMode(relayPin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
digitalWrite(relayPin, HIGH); // Pump OFF
digitalWrite(buzzerPin, LOW);
attachInterrupt(digitalPinToInterrupt(flowPin), pulseCounter, RISING);
lcd.init();
lcd.backlight();
updateLCD();
}
void loop() {
char key = keypad.getKey();
if (key) {
if (key >= '0' && key <= '9' && !filling) {
userSetVolume = userSetVolume * 10 + (key - '0');
setVolume = userSetVolume;
beep(100);
updateLCD();
}
else if (key == '*' && !filling) {
userSetVolume = 0;
setVolume = 0;
currentVolume = 0;
beep(100);
updateLCD();
}
else if (key == '#' && !filling) {
if (userSetVolume > 0) {
beep(200);
startFilling();
}
}
else if (key == 'A' && filling) {
stopFilling(true); // Manual stop
}
}
if (filling) {
unsigned long currentTime = millis();
if (currentTime - lastUpdateTime >= 1000) {
lastUpdateTime = currentTime;
float flowRate = (pulseCount / calibrationFactor); // ml/sec
currentVolume += flowRate;
pulseCount = 0;
updateLCD();
if (currentVolume >= setVolume) {
stopFilling(false); // Auto stop
}
}
}
}
void pulseCounter() {
pulseCount++;
}
void startFilling() {
currentVolume = 0;
pulseCount = 0;
filling = true;
// Apply correction factor to avoid overfilling
setVolume = userSetVolume * userCorrectionFactor;
digitalWrite(relayPin, LOW); // Pump ON
updateLCD();
lastUpdateTime = millis();
}
void stopFilling(bool userStopped) {
// ✅ Count any remaining pulses before stopping
float flowRate = (pulseCount / calibrationFactor); // ml
currentVolume += flowRate;
pulseCount = 0;
filling = false;
digitalWrite(relayPin, HIGH); // Pump OFF
lcd.setCursor(0, 0);
lcd.print("Set Value:");
lcd.print(userSetVolume);
lcd.print("ml ");
lcd.setCursor(0, 1);
if (userStopped) {
lcd.print("Stopped: ");
} else {
lcd.print("Filled: ");
beep(500);
}
lcd.print(currentVolume); // Show actual filled amount
lcd.print("ml ");
Serial.print("Set Value: ");
Serial.print(userSetVolume);
Serial.print("ml, Filled: ");
Serial.print(currentVolume);
Serial.println("ml");
}
void updateLCD() {
lcd.setCursor(0, 0);
lcd.print("Set Value:");
lcd.print(userSetVolume);
lcd.print("ml ");
lcd.setCursor(0, 1);
if (filling) {
lcd.print("Filling: ");
lcd.print(currentVolume);
lcd.print("ml ");
} else if (currentVolume == 0) {
lcd.print("Ready ");
}
}
void beep(int duration) {
digitalWrite(buzzerPin, HIGH);
delay(duration);
digitalWrite(buzzerPin, LOW);
}