#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define ENCODER_CLK 18
#define ENCODER_DT 19
volatile int pulseCount = 0;
float flowRate = 0.0;
float totalLiters = 0.0;
unsigned long lastCalc = 0;
unsigned long lastDisplay = 0;
void IRAM_ATTR onPulse() {
pulseCount++;
}
void setup() {
Serial.begin(115200);
Serial.println("Starting...");
Wire.begin(21, 22);
delay(500); // ✅ Give I2C time to settle
// ✅ Try both common Wokwi I2C addresses
lcd = LiquidCrystal_I2C(0x27, 16, 2);
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("WINDMILL FLOW");
lcd.setCursor(0, 1);
lcd.print(" CALCULATOR ");
delay(2000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" ESD PROJECT ");
lcd.setCursor(0, 1);
lcd.print(" Spin the knob");
delay(2000);
lcd.clear();
pinMode(ENCODER_CLK, INPUT_PULLUP);
pinMode(ENCODER_DT, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), onPulse, FALLING);
lastCalc = millis();
lastDisplay = millis();
Serial.println("Ready!");
}
void loop() {
unsigned long now = millis();
// Calculate flow every 1 second
if (now - lastCalc >= 1000) {
noInterrupts();
int p = pulseCount;
pulseCount = 0;
interrupts();
flowRate = p / 7.5; // L/min
totalLiters += flowRate / 60.0; // L
lastCalc = now;
Serial.print("Flow: ");
Serial.print(flowRate, 2);
Serial.print(" L/min | Total: ");
Serial.print(totalLiters, 3);
Serial.println(" L");
}
// Update LCD every 600ms
if (now - lastDisplay >= 600) {
lastDisplay = now;
lcd.setCursor(0, 0);
lcd.print("Flow:");
if (flowRate < 10) lcd.print(" ");
lcd.print(flowRate, 1);
lcd.print(" L/min ");
lcd.setCursor(0, 1);
lcd.print("Tot: ");
lcd.print(totalLiters, 3);
lcd.print(" L ");
}
}