#include "HX711_ADC.h"
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
// HX711 Load Cell
HX711_ADC LoadCell(9, 8);
// LCD
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] = {7, 6, A0, A1};
byte colPins[COLS] = {A2, A3, A4, A5};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// Pins
const int buzzer = 11;
const int solenoidPin = 10;
// Variables
String inputWeight = "";
float targetWeight = 0;
bool filling = false;
unsigned long prevTime1 = millis();
unsigned long prevTime2 = millis();
const long Time1 = 3000; // Alarm interval
const long Time2 = 1000; // LCD update interval
void setup() {
pinMode(buzzer, OUTPUT);
pinMode(solenoidPin, OUTPUT);
digitalWrite(solenoidPin, LOW); // Valve off
Serial.begin(9600);
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("Weighing Scale");
lcd.setCursor(3, 1);
lcd.print("With Alarm");
delay(2500);
lcd.clear();
// Auto tare on startup
lcd.setCursor(3, 0); lcd.print("Auto Tare...");
LoadCell.begin();
LoadCell.start(1000);
LoadCell.setCalFactor(0.42);
while (!LoadCell.update());
float initWeight = LoadCell.getData();
if (abs(initWeight) > 10.0) {
LoadCell.tareNoDelay();
while (!LoadCell.update());
}
lcd.clear();
}
void loop() {
handleKeypad();
unsigned long currentTime = millis();
LoadCell.update();
float weight = LoadCell.getData();
// Auto tare when scale is near zero and not filling
if (weight > -1.0 && weight < 1.0 && !filling) {
LoadCell.tareNoDelay();
while (!LoadCell.update());
}
// Alarm buzzer if weight exceeds target
if (filling && currentTime - prevTime1 > Time1) {
if (weight > targetWeight && targetWeight > 0) {
// Beep pattern
noTone(buzzer); delay(300);
tone(buzzer, 250); delay(300); noTone(buzzer); delay(300);
tone(buzzer, 450); delay(300); noTone(buzzer); delay(300);
}
prevTime1 = currentTime;
}
// Update display and solenoid control every second
if (currentTime - prevTime2 > Time2) {
if (filling) {
lcd.setCursor(0, 0);
lcd.print("Filling... ");
lcd.setCursor(0, 1);
lcd.print("Now: ");
lcd.print(weight, 1);
lcd.print("g / ");
lcd.print(targetWeight, 1);
lcd.print("g");
if (weight < targetWeight - 1.0) {
digitalWrite(solenoidPin, HIGH); // Open valve
} else {
digitalWrite(solenoidPin, LOW); // Close valve
filling = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Target Reached");
lcd.setCursor(0, 1);
lcd.print("Final: ");
lcd.print(weight, 1);
lcd.print("g");
tone(buzzer, 1000, 500);
delay(2000);
noTone(buzzer);
lcd.clear();
}
} else {
lcd.setCursor(0, 0);
lcd.print("Weight: ");
lcd.setCursor(0, 1);
lcd.print(weight, 1);
lcd.print(" g ");
}
prevTime2 = currentTime;
}
// Serial debug
Serial.print("Target: ");
Serial.print(targetWeight);
Serial.print("g | Current: ");
Serial.print(weight);
Serial.print("g | Filling: ");
Serial.println(filling ? "Yes" : "No");
}
// Keypad input handler
void handleKeypad() {
char key = keypad.getKey();
if (key != NO_KEY) {
if (key >= '0' && key <= '9') {
if (inputWeight.length() < 6) {
inputWeight += key;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Target (g): ");
lcd.setCursor(0, 1);
lcd.print(inputWeight);
}
} else if (key == '*') {
inputWeight = "";
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Input cleared");
delay(1000);
lcd.clear();
} else if (key == '#') {
if (inputWeight.length() > 0) {
targetWeight = inputWeight.toFloat();
filling = true;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Target set: ");
lcd.print(targetWeight);
lcd.print("g");
delay(1500);
lcd.clear();
inputWeight = "";
}
}
}
}