Skip to content

Instantly share code, notes, and snippets.

@fxprime
Created August 20, 2025 14:52
Show Gist options
  • Save fxprime/1b4273910dc8d116782fe42df22e8f67 to your computer and use it in GitHub Desktop.
Save fxprime/1b4273910dc8d116782fe42df22e8f67 to your computer and use it in GitHub Desktop.
#include <Arduino.h>
#include "HX711.h"
#include <Preferences.h>
// HX711 circuit wiring
#define LOADCELL_DOUT_PIN 27
#define LOADCELL_SCK_PIN 26
HX711 scale;
Preferences preferences;
float calibration_factor = 1.0;
const int num_samples = 3;
float known_weights[num_samples];
long raw_readings[num_samples];
void waitForUserInput(const char* prompt, float* value) {
Serial.println(prompt);
while (Serial.available()) Serial.read(); // clear buffer
while (true) {
if (Serial.available()) {
String input = Serial.readStringUntil('\n');
input.trim();
*value = input.toFloat();
if (*value > 0) break;
Serial.println("Invalid input. Please enter a positive number:");
}
delay(100);
}
}
void waitForUserConfirm(const char* prompt) {
Serial.println(prompt);
Serial.println("Type 'y' and press Enter to continue...");
while (Serial.available()) Serial.read(); // clear buffer
while (true) {
if (Serial.available()) {
String input = Serial.readStringUntil('\n');
input.trim();
if (input.equalsIgnoreCase("y")) break;
Serial.println("Please type 'y' and press Enter to confirm.");
}
delay(100);
}
}
void setup() {
Serial.begin(115200);
while (!Serial) delay(10);
scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
preferences.begin("hx711", false);
float calib = preferences.getFloat("calib", 0.0);
Serial.print("[DEBUG] Read calibration factor from preferences: ");
Serial.println(calib, 6);
bool hasCalib = calib != 0.0 && !isnan(calib);
if (hasCalib) {
Serial.print("Found calibration factor in preferences: ");
Serial.println(calib, 6);
Serial.println("Type 'y' and press Enter to recalibrate, 's' to show raw data, or any other key to skip calibration.");
while (Serial.available()) Serial.read(); // clear buffer
bool doCalib = false;
while (true) {
if (Serial.available()) {
String input = Serial.readStringUntil('\n');
input.trim();
if (input.equalsIgnoreCase("y")) {
doCalib = true;
break;
} else if (input.equalsIgnoreCase("s")) {
Serial.println("\n--- RAW LOADCELL DATA MODE ---");
Serial.println("Press any key to exit raw data mode.");
while (true) {
if (Serial.available()) {
Serial.readStringUntil('\n');
break;
}
long raw = scale.read();
Serial.print("Raw: ");
Serial.println(raw);
delay(500);
}
Serial.println("Exiting raw data mode.\n");
Serial.println("Type 'y' and press Enter to recalibrate, or any other key to skip calibration.");
while (Serial.available()) Serial.read(); // clear buffer
continue;
} else {
break;
}
}
delay(100);
}
if (!doCalib) {
Serial.println("Skipping calibration. Using saved calibration factor.");
preferences.end();
waitForUserConfirm("Remove all weight from scale. Ready to tare?");
scale.tare();
Serial.println("Tare done.");
return;
}
Serial.println("Proceeding with calibration...");
} else {
Serial.println("No calibration factor found. Calibration is required.");
Serial.println("Type 's' and press Enter to show raw data for loadcell test, or any other key to continue.");
while (Serial.available()) Serial.read(); // clear buffer
bool showRaw = false;
while (true) {
if (Serial.available()) {
String input = Serial.readStringUntil('\n');
input.trim();
if (input.equalsIgnoreCase("s")) showRaw = true;
break;
}
delay(100);
}
if (showRaw) {
Serial.println("\n--- RAW LOADCELL DATA MODE ---");
Serial.println("Press any key to exit raw data mode.");
while (true) {
if (Serial.available()) {
Serial.readStringUntil('\n');
break;
}
long raw = scale.read();
Serial.print("Raw: ");
Serial.println(raw);
delay(500);
}
Serial.println("Exiting raw data mode.\n");
}
}
Serial.println("HX711 scale calibration");
waitForUserConfirm("Remove all weight from scale. Ready to tare?");
scale.tare();
Serial.println("Tare done.");
for (int i = 0; i < num_samples; i++) {
Serial.print("\nPlace known weight sample #");
Serial.print(i + 1);
Serial.println(" on the scale.");
waitForUserConfirm("When ready, confirm to take measurement.");
raw_readings[i] = scale.get_units(15); // filtered average
Serial.print("Raw reading: ");
Serial.println(raw_readings[i]);
waitForUserInput("Enter the actual weight in grams:", &known_weights[i]);
Serial.print("Recorded: ");
Serial.print(known_weights[i]);
Serial.println(" g");
waitForUserConfirm("Remove the weight and confirm to continue to next sample.");
}
// Calculate calibration factor (average of all samples)
float sum_factor = 0;
for (int i = 0; i < num_samples; i++) {
if (known_weights[i] > 0) {
sum_factor += (float)raw_readings[i] / known_weights[i];
}
}
calibration_factor = sum_factor / num_samples;
Serial.print("\nCalibration factor calculated: ");
Serial.println(calibration_factor, 6);
waitForUserConfirm("Save calibration factor to preferences?");
bool ok = preferences.putFloat("calib", calibration_factor);
Serial.print("[DEBUG] preferences.putFloat returned: ");
Serial.println(ok ? "true" : "false");
preferences.end(); // Ensure preferences are saved and closed
Serial.print("[DEBUG] Saved calibration factor: ");
Serial.println(calibration_factor, 6);
Serial.println("Calibration factor saved to preferences.");
Serial.println("Restart the device to use the calibrated scale.");
}
void loop() {
// After calibration, you can use the calibration factor as follows:
preferences.begin("hx711", false); // open in read/write mode for compatibility
float calib = preferences.getFloat("calib", 1.0);
Serial.print("[DEBUG] loop() read calibration factor: ");
Serial.println(calib, 6);
preferences.end();
float calib_abs = fabs(calib);
scale.set_scale(calib_abs);
float weight = scale.get_units(10);
if (calib < 0) weight = -weight;
Serial.print("Weight: ");
Serial.print(weight, 2);
Serial.println(" g");
delay(1000);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment