#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// Set the LCD address to 0x27 or 0x3F depending on your module
LiquidCrystal_I2C lcd(0x27, 16, 2); // 16 columns and 2 rows
// Custom bar characters (levels 1 to 5)
byte bar0[8] = { B11111, B10001, B10001, B10001, B10001, B10001, B10001, B11111 };
byte bar1[8] = { B10000, B10000, B10000, B10000, B10000, B10000, B10000, B10000 };
byte bar2[8] = { B11000, B11000, B11000, B11000, B11000, B11000, B11000, B11000 };
byte bar3[8] = { B11100, B11100, B11100, B11100, B11100, B11100, B11100, B11100 };
byte bar4[8] = { B11110, B11110, B11110, B11110, B11110, B11110, B11110, B11110 };
byte bar5[8] = { B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111 };
const int turbidityPin = A0;
int getAverageReading(int pin, int samples = 10) {
long sum = 0;
for (int i = 0; i < samples; i++) {
sum += analogRead(pin);
delay(10); // small delay between samples
}
return sum / samples;
}
void setup() {
lcd.init(); // Initialize the LCD
lcd.backlight(); // Turn on the backlight
lcd.setCursor(0, 0); // Set cursor to column 0, row 0
lcd.print("Hello, World!");
lcd.setCursor(0, 1); // Set cursor to column 0, row 1
lcd.print("I2C LCD Test");
Serial.begin(9600);
// Create custom bar characters
lcd.createChar(0, bar0);
lcd.createChar(1, bar1);
lcd.createChar(2, bar2);
lcd.createChar(3, bar3);
lcd.createChar(4, bar4);
lcd.createChar(5, bar5);
}
void loop() {
int sensorValue = getAverageReading(turbidityPin);
float voltage = sensorValue * (5.0 / 1023.0);
// float turbidity = -1120.4 * sq(voltage) + 5742.3 * voltage - 4352.9;
float turbidity = map(sensorValue, 1023, 500, 0, 300);
// Clamp negative NTU to 0
if (turbidity < 0) turbidity = 0;
// Interpret water status
String status;
if (turbidity < 1) status = "Very Clear";
else if (turbidity < 5) status = "Clear";
else if (turbidity < 10) status = "Slightly Muddy";
else if (turbidity < 50) status = "Muddy";
else if (turbidity < 100) status = "Very Muddy";
else status = "Extremely Turbid";
// Display NTU
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("NTU: ");
lcd.print(turbidity, 1); // 1 decimal place
// Draw bar graph (0–10 scale mapped to blocks)
int level;
if (turbidity < 1) level = 0;
else if (turbidity < 5) level = 1;
else if (turbidity < 10) level = 2;
else if (turbidity < 50) level = 3;
else if (turbidity < 100) level = 4;
else level = 5; // for very turbid, max bars
int bars = level;
lcd.setCursor(11, 0);
for (int i = 0; i < 10; i++) {
if (i < bars)
lcd.write(byte(5)); // full block
else
lcd.write(byte(0)); // empty block
}
// Display status on line 2
lcd.setCursor(0, 1);
lcd.print(status.substring(0, 16)); // Fit in 16 characters
// Serial Monitor Output
Serial.print("Sensor Value: ");
Serial.print(sensorValue);
Serial.print(" | Voltage: ");
Serial.print(voltage, 3); // 3 decimal places
Serial.print(" V | Turbidity: ");
Serial.print(turbidity, 2); // 2 decimal places
Serial.println(" NTU");
delay(1000);
}