Weighing with an HX711 and a Load Cell

Draft. This tutorial has not been checked against the physical product yet. Confirm wiring, pin assignments and voltage limits against the product documentation before building it.
DifficultyAdvanced
CategorySensors
Supported boardsArduino Uno R3 and compatible ATmega328P boards
Time needed70 minutes
PrerequisitesDigital and Analog, and When Each Applies
Tested boardNot yet verified
Tested onNot yet verified
Arduino IDE versionNot yet verified
LibraryNot yet verified

What it does

A load cell is a piece of metal that bends very slightly under weight, with strain gauges bonded to it that change resistance as it bends. The change is tiny: a few microvolts per gram.

An Arduino’s analog input resolves about 5 millivolts, which is roughly a thousand times too coarse to see anything at all. The HX711 is the bridge. It is a 24-bit converter built specifically for load cells, with a built-in amplifier, and it turns those microvolts into numbers you can work with.

This is the most precise measurement in the library, and the one that most depends on doing the calibration properly.

Before you begin

Required parts and tools

  • An Arduino Uno or compatible board.
  • One HX711 module. This is Siratek product 2881.
  • A load cell, which is not included. Buy one rated a little above the heaviest thing you mean to weigh.
  • A soldering iron. The supplied ten-pin header is loose and must be soldered on.
  • Something rigid to mount the cell on, and a known weight for calibration.

The board has two sides

The green board is marked clearly:

  • J1, the load cell side: E+ E- A- A+ B- B+
  • JP2, the Arduino side: GND DT SCK VCC

E+ and E- excite the load cell. A- and A+ are the measurement input, channel A. B- and B+ are a second channel at lower gain, which you can ignore for a single cell.

Wiring the load cell

A four-wire load cell almost always uses these colours:

Wire To Meaning
Red E+ Excitation positive
Black E- Excitation negative
White A- Signal negative
Green A+ Signal positive

White and green are the pair that varies between manufacturers. If pressing down makes the reading go more negative, swap those two. Nothing is harmed by getting it wrong; the sign simply inverts.

Some cells have a fourth colour, often yellow, which is a shield. Connect it to GND or leave it; do not put it on a signal pin.

Mounting matters more than the electronics

This is the part people skip, and it is why a working circuit gives useless numbers.

A bar load cell is designed to be clamped at one end and loaded at the other, with the middle free to flex. The arrow on its side shows the direction the force should act.

  • Bolt one end to something solid. A cell held in the hand measures your hand.
  • Load the other end through a platform, with spacers so the cell can bend. If the platform touches the base anywhere else, the force bypasses the cell and the reading goes nowhere.
  • Keep the load central. Weight at the far corner of a wide platform reads differently from the same weight in the middle. That is not drift; it is the cell being bent in a way it was not designed for.

Spend the time on the mechanics. A perfectly calibrated cell mounted badly is worse than useless, because it looks right.

Two numbers you must find

Every load cell and every mounting produces its own two constants.

The offset, or tare: what the system reads with nothing on it. This is not zero, and it changes if you move the platform or tighten a bolt.

The scale factor: how many raw counts correspond to one gram. This depends on the cell’s rating, the HX711’s gain and your mounting.

Neither can be looked up. Both must be measured, with the procedure below, and both must be measured again if you change the mechanics in any way.

It is slow, and that is fine

The HX711 runs at 10 samples a second, or 80 if a pin on the chip is tied differently. Ten is plenty for a scale, and the slower rate is quieter.

It is also not SPI and not I2C, despite having a clock and a data pin. It is its own simple protocol, which the library bit-bangs, so any two digital pins work.

Pin reference

Module pin Connect to Purpose
GND Uno GND Ground
DT Uno D3 Data out of the HX711
SCK Uno D2 Clock from the Arduino
VCC Uno 5V Power
E+ E- A- A+ The load cell Red, black, white, green
An HX711 module with its load cell terminals on one side and four wires to the Arduino on the other, and a bar load cell clamped at one end with the platform on the other
The electronics are the easy half. How the cell is clamped decides whether the numbers mean anything.

Wiring steps

  1. Unplug the USB cable.
  2. Solder the ten-pin header to the board.
  3. Solder or screw the load cell’s four wires to E+, E-, A-, A+ by colour.
  4. GND to GND, VCC to 5V.
  5. DT to D3, SCK to D2.
  6. Mount the cell properly before taking it seriously.
  7. Plug the USB cable back in.

Software and libraries

Install HX711 by Bogdan Necula, or the similarly named library by Rob Tillaart. The sketches below use the first. Record which one, because their method names differ.

Minimal working example

Start with raw counts. They look meaningless and they are exactly what you need.

// Siratek: raw readings. Press on the platform and watch the numbers.

#include "HX711.h"

const int dataPin = 3;
const int clockPin = 2;

HX711 scale;

void setup() {
  Serial.begin(9600);
  scale.begin(dataPin, clockPin);
  Serial.println("Siratek: raw counts. Press down and see which way they move.");
}

void loop() {
  if (scale.is_ready()) {
    Serial.println(scale.read());
  } else {
    Serial.println("HX711 not ready. Check DT, SCK and power.");
  }
  delay(500);
}

Three things to check here, in order.

Does it say “not ready”? Then the wiring is wrong, and nothing else will work.

Do the numbers change when you press? If not, the load cell wiring or the mounting is at fault, not the board.

Do they go up when you press down? If they go down, swap the white and green wires.

Calibration

Now the two constants. This is the part that turns counts into grams.

// Siratek: find the offset and the scale factor for YOUR cell and mounting.
// Follow the prompts. Write both numbers down.

#include "HX711.h"

HX711 scale;

// The weight of the object you will use. Measure it on a kitchen scale.
const float knownGrams = 500.0;

void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ;
  }

  scale.begin(3, 2);

  Serial.println("Siratek: remove everything from the platform, then send any character.");
  while (Serial.available() == 0) {
    delay(50);
  }
  while (Serial.available()) {
    Serial.read();
  }

  scale.tare(20);                       // average twenty readings for the zero
  long offset = scale.get_offset();
  Serial.print("offset = ");
  Serial.println(offset);

  Serial.print("Now put the ");
  Serial.print(knownGrams, 0);
  Serial.println(" g weight on, then send any character.");
  while (Serial.available() == 0) {
    delay(50);
  }

  long loaded = scale.get_value(20);    // averaged, with the offset removed
  float factor = loaded / knownGrams;

  Serial.print("raw with weight = ");
  Serial.println(loaded);
  Serial.print("scale factor = ");
  Serial.println(factor, 4);
  Serial.println();
  Serial.println("Put both numbers into the weighing sketch.");
}

void loop() {
}

Use the heaviest weight you can that is still within the cell’s rating. Calibrating a 5 kg cell with a 20 g weight gives a factor dominated by noise.

A litre of water is a kilogram, near enough, and most people have a bottle.

Weighing

// Siratek: a scale, using the two numbers you measured.

#include "HX711.h"

HX711 scale;

// From the calibration sketch. Yours will differ, and they are not optional.
const long myOffset = 0;
const float myFactor = 1.0;

void setup() {
  Serial.begin(9600);
  scale.begin(3, 2);

  scale.set_offset(myOffset);
  scale.set_scale(myFactor);

  Serial.println("Siratek: scale ready.");
}

void loop() {
  // Average ten readings. A single one jumps around by a gram or two.
  float grams = scale.get_units(10);

  Serial.print(grams, 1);
  Serial.println(" g");

  delay(500);
}

Averaging ten readings is the difference between a scale and a random number generator. At this resolution the last digit is always moving, and the eye reads a jittering display as broken even when the average is correct.

Drift, and why a tare button is worth adding

Leave a calibrated scale running and the zero wanders, by a gram or two over an hour. Strain gauges are temperature sensitive, and the metal itself relaxes.

Real scales handle this by taring every time you use them, and so should yours: a button that calls scale.tare() costs one pin and removes the problem entirely.

if (digitalRead(tareButton) == LOW) {
  scale.tare(20);
  Serial.println("tared");
}

Expected result

Raw counts that move clearly when you press on the platform, and after calibration, a weight in grams accurate to a gram or two with a stable reading.

Put the known weight back on and check it reads what it should. Then put it in a different place on the platform and check again: a large difference tells you about the mounting, not the electronics.

Troubleshooting

Symptom Likely cause Check or fix
“not ready” forever DT and SCK swapped, or no power Check all four Arduino wires
Raw value never changes Load cell wiring, or bad mounting Check colours, then the mechanics
Reading goes down when you press Signal pair reversed Swap white and green
Wildly fluctuating raw values A load cell wire not connected Reseat; check solder joints
Weight roughly right but out by a factor Wrong scale factor Recalibrate with a known weight
Reads zero no matter what set_scale() with the default Put your own factor in
Zero wanders over an hour Temperature and metal relaxation Normal; add a tare button
Different reading at the platform’s edge Off-centre loading Expected; load centrally
Changed after tightening a bolt Mechanics changed Recalibrate
Reading saturates under load Cell over its rating Use a cell rated above your maximum
Noisy near a motor Microvolt signals pick up interference Separate the supplies; keep leads short

Next steps

  • Easier first: Digital and Analog, and When Each Applies, for why an analog pin cannot do this.
  • Related products: a 16×2 LCD to show the weight, and a push button for tare.
  • Next project: a kitchen scale with a display and a tare button, which is a genuinely useful object rather than a demonstration.

Sources and attribution

All text, wiring guidance and code in this tutorial are original Siratek work.

  • HX711 datasheet for the 24-bit conversion, the sample rates and the channel arrangement.
  • The E+ E- A- A+ B- B+ and GND DT SCK VCC headers and the loose ten-pin header were read from the Siratek product photographs for item 2881. The same photographs show the board supplied without a load cell, which is why one appears in the parts list.

Load cell wire colours are near-universal but not guaranteed, so the tutorial gives a test rather than asserting them. Offset and scale factor are presented as values the reader must measure, as they depend on the individual cell and its mounting. No third-party tutorial text, diagrams, photographs or code has been reproduced here.

Product used in this tutorial: HX711 Weight Load Module Sensor
Shop
Sidebar
0 Wishlist
0 Cart