Cirkit Designer LogoCirkit DesignerYour all-in-one circuit design IDE Launch Cirkit Designer App

Arduino-Based Load Cell Scale with HX711

View and Edit Project In Cirkit DesignerImage of Arduino-Based Load Cell Scale with HX711

Circuit Documentation

Summary

This circuit utilizes an Arduino UNO microcontroller to interface with an HX711 Load Cell. The HX711 is a precision 24-bit analog-to-digital converter (ADC) designed for weigh scales and industrial control applications. The Arduino UNO processes the data from the load cell and provides a simple interface for tare, calibration, and streaming weight data.

Component List

Arduino UNO

HX711 Load Cell (5kg)

Comment V2


Wiring Details

Arduino UNO


Documented Code

// HX711 simple sequential flow: tare -> cal <kg> -> stream (kg)
// Library: "HX711" by Bogdan Necula (Bogde)
// Wiring: DAT -> D4, SCK -> D5

#include <HX711.h>

const uint8_t PIN_DOUT = 4;   // DAT
const uint8_t PIN_SCK  = 5;   // CLK

// Tunables
const uint8_t AVG_TARE    = 10;    // samples for tare
const uint8_t AVG_CAL     = 10;    // samples for calibration
const uint8_t AVG_STREAM  = 5;     // samples per streamed reading
const unsigned long STREAM_MS = 200; // stream period (ms)

HX711 scale;

enum Stage { WAIT_TARE, WAIT_CAL, STREAMING };
Stage stage = WAIT_TARE;

unsigned long lastStream = 0;
String inLine;

void printIntro() {
  Serial.println(F("HX711 simple flow: tare -> cal <kg> -> streaming"));
  Serial.println(F("Commands:"));
  Serial.println(F("  tare          (no load)"));
  Serial.println(F("  cal <kg>      (known mass applied, e.g., cal 1.000)"));
  Serial.println(F("  reset         (restart flow)"));
  Serial.println();
  Serial.println(F("Step 1: Ensure no load, then type: tare"));
}

void setup() {
  Serial.begin(115200);
  while (!Serial) { /* wait for USB */ }

  scale.begin(PIN_DOUT, PIN_SCK);
  scale.set_gain(128);

  printIntro();
}

void handleSerial() {
  while (Serial.available()) {
    char c = (char)Serial.read();
    if (c == '\r') continue;
    if (c == '\n') {
      inLine.trim();
      inLine.toLowerCase();

      if (inLine == "reset") {
        stage = WAIT_TARE;
        Serial.println(F("Reset. Back to Step 1: type 'tare' with no load."));
      } else if (stage == WAIT_TARE) {
        if (inLine == "tare") {
          Serial.print(F("Taring ("));
          Serial.print(AVG_TARE);
          Serial.println(F(" samples)..."));
          scale.tare(AVG_TARE);
          Serial.print(F("Offset = "));
          Serial.println(scale.get_offset());
          stage = WAIT_CAL;
          Serial.println(F("Step 2: Place known mass and type: cal <kg> (e.g., cal 1.000)"));
        } else if (inLine.length()) {
          Serial.println(F("Type 'tare' to continue (no load)."));
        }
      } else if (stage == WAIT_CAL) {
        if (inLine.startsWith("cal ")) {
          // Parse kg value after "cal "
          double kg = inLine.substring(4).toFloat();
          if (kg <= 0.0) {
            Serial.println(F("ERR: cal <kg> must be > 0, e.g., cal 1.000"));
          } else {
            // Robust calibration: flush a couple of conversions so the new load is latched
            (void)scale.read();  // flush #1
            (void)scale.read();  // flush #2

            // Average fresh raw readings
            long rawAvg = scale.read_average(AVG_CAL);
            long offset = scale.get_offset();
            long delta  = rawAvg - offset;

            Serial.print(F("rawAvg="));
            Serial.print(rawAvg);
            Serial.print(F("  delta="));
            Serial.println(delta);

            if (delta == 0) {
              Serial.println(F("ERR: no change from tare; check mass or re-tare."));
            } else {
              double counts_per_kg = (double)delta / kg;
              scale.set_scale(counts_per_kg);  // get_units() now returns kg
              Serial.print(F("Cal OK. counts_per_kg="));
              Serial.println(counts_per_kg, 1);

              // Quick verification read
              double kg_now = scale.get_units(AVG_CAL);
              Serial.print(F("verify kg="));
              Serial.println(kg_now, 3);

              Serial.println(F("Streaming kg... (type 'reset' to redo)"));
              stage = STREAMING;
              lastStream = 0;
            }
          }
        } else if (inLine.length()) {
          Serial.println(F("Type 'cal <kg>' e.g., cal 1.000"));
        }
      } else {
        // STREAMING: allow 'reset'
      }

      inLine = ""; // clear buffer
    } else {
      inLine += c;
    }
  }
}

void loop() {
  handleSerial();

  if (stage == STREAMING) {
    unsigned long now = millis();
    if (now - lastStream >= STREAM_MS) {
      lastStream = now;
      double kg = scale.get_units(AVG_STREAM);   // returns kg (scale set by cal)
      long rawAvg = scale.read_average(AVG_STREAM);
      long offset = scale.get_offset();
      long delta  = rawAvg - offset;

      Serial.print(F("kg="));
      Serial.print(kg, 3);
      Serial.print(F("  raw(avg)="));
      Serial.print(rawAvg);
      Serial.print(F("  delta="));
      Serial.println(delta);
    }
  }
}

This documentation provides a comprehensive overview of the circuit, detailing the components used, their connections, and the code that drives the functionality of the system.