Kitchen Scale Intermediate

Build a digital kitchen scale using a load cell, HX711 amplifier, and OLED display

🔗Goal

Build a digital kitchen scale that weighs items using a load cell and HX711 amplifier, displays the weight on an OLED screen, and supports a tare button to zero out the container weight. This is a practical project that teaches you about analog-to-digital conversion, signal amplification, and calibration.

Here is how the system works at a high level:

graph LR
    A[Load Cell] -->|Strain signal| B[HX711 Amplifier]
    B -->|Digital data| C[ESP32]
    C -->|I2C| D[OLED Display]
    E[Tare Button] -->|GPIO| C

A load cell is a transducer that converts force (weight) into a tiny electrical signal — typically just a few millivolts. The HX711 is a 24-bit analog-to-digital converter designed specifically for load cells. It amplifies the signal and sends it to the ESP32 as a digital value. The ESP32 then converts this raw value into grams using a calibration factor and displays the result on the OLED.

The relationship between the raw reading and weight is linear:

$$\text{weight (g)} = \frac{\text{raw reading} - \text{tare offset}}{\text{calibration factor}}$$

🔗Prerequisites

You will need the following components:

ComponentQtyNotesBuy
ESP32 dev board1AliExpress | Amazon.de .co.uk .com
HX711 load cell amplifier module1AliExpress | Amazon.de .co.uk .com
Load cell11 kg, 5 kg, or 10 kg — choose based on what you plan to weighAliExpress | Amazon.de .co.uk .com
SSD1306 OLED display (0.96")1I2C interfaceAliExpress | Amazon.de .co.uk .com
Push button (tactile)1Momentary, normally openAliExpress | Amazon.de .co.uk .com
10k ohm resistor1Pull-down resistor for the buttonAliExpress | Amazon.de .co.uk .com
Breadboard1AliExpress | Amazon.de .co.uk .com
Jumper wires~12Male-to-male and male-to-femaleAliExpress | Amazon.de .co.uk .com

Links marked Amazon/AliExpress are affiliate links. We may earn a small commission at no extra cost to you.

Load cells come in different maximum capacities. A 1 kg cell is good for coffee and spices, 5 kg covers most kitchen ingredients, and 10 kg handles heavier items like flour bags. Choose the one that fits your use case — smaller capacity means higher precision for lighter items.

Arduino IDE libraries (install via Library Manager):

LibraryAuthorPurpose
HX711Bogdan Necula (bogde)Driver for the HX711 amplifier
Adafruit SSD1306AdafruitOLED display driver
Adafruit GFX LibraryAdafruitGraphics primitives (dependency)

🔗Tutorial

🔗Step 1: Wiring the load cell to the HX711

Load cells have four wires. The colors may vary between manufacturers, but the typical mapping is:

Load Cell WireHX711 PinCommon Color
Excitation+ (E+)E+Red
Excitation- (E-)E-Black
Signal+ (A+)A+White or Green
Signal- (A-)A-Green or White

If your load cell's colors do not match this table, check the datasheet that came with your specific load cell. Swapping A+ and A- will invert the readings (weight goes negative), which is easy to fix by swapping the two wires.

🔗Step 2: Wiring the HX711, OLED, and button to the ESP32

ComponentPinESP32 PinNotes
HX711VCC3.3V
HX711GNDGND
HX711DT (Data)GPIO 4Digital data output
HX711SCK (Clock)GPIO 5Clock input
OLEDVCC3.3V
OLEDGNDGND
OLEDSDAGPIO 21I2C data
OLEDSCLGPIO 22I2C clock
Tare buttonOne legGPIO 14
Tare buttonOther leg3.3V
10k resistorGPIO 14GNDPull-down: keeps GPIO 14 LOW when button is not pressed

Pin labels and GPIO numbers vary between ESP32 boards. Always check your board's pinout diagram. GPIO 21 and GPIO 22 are the default I2C pins on most ESP32-WROOM-32 DevKits.

The button circuit works as follows: when the button is not pressed, the 10k pull-down resistor keeps GPIO 14 at LOW (0V). When pressed, GPIO 14 connects to 3.3V and reads HIGH.

🔗Step 3: Calibration — finding your scale factor

Before the scale can display accurate weights, you need to determine the calibration factor for your specific load cell. This is a one-time process.

Upload this calibration sketch first:

#include "HX711.h"

#define HX711_DT  4
#define HX711_SCK 5

HX711 scale;

void setup() {
    Serial.begin(115200);
    Serial.println("HX711 Calibration");
    Serial.println("==================");

    scale.begin(HX711_DT, HX711_SCK);

    Serial.println("Remove all weight from the load cell.");
    Serial.println("Waiting 3 seconds...");
    delay(3000);

    scale.tare(20); // Average 20 readings for the zero point
    Serial.println("Tare complete.");

    Serial.println();
    Serial.println("Place a known weight on the load cell.");
    Serial.println("Then type the weight in grams into the Serial Monitor and press Enter.");
    Serial.println("(Example: type 100 for a 100g weight)");
}

void loop() {
    if (scale.is_ready()) {
        long rawValue = scale.get_value(10); // Average of 10 readings
        Serial.print("Raw value: ");
        Serial.println(rawValue);
    }

    // Read known weight from Serial input
    if (Serial.available()) {
        float knownWeight = Serial.parseFloat();
        if (knownWeight > 0) {
            long rawValue = scale.get_value(20);
            float calibrationFactor = (float)rawValue / knownWeight;
            Serial.println();
            Serial.print("Known weight: ");
            Serial.print(knownWeight, 1);
            Serial.println(" g");
            Serial.print("Raw value:    ");
            Serial.println(rawValue);
            Serial.print(">>> Calibration factor: ");
            Serial.println(calibrationFactor, 2);
            Serial.println();
            Serial.println("Copy this number into the main sketch as CALIBRATION_FACTOR.");
        }
    }

    delay(500);
}

Calibration steps:

  1. Upload the calibration sketch and open the Serial Monitor at 115200 baud.
  2. Make sure nothing is on the load cell. The sketch will auto-tare after 3 seconds.
  3. Place a known weight on the load cell (a kitchen item with a printed weight works, or use calibration weights).
  4. Note the Raw value shown in the Serial Monitor.
  5. Type the known weight in grams into the Serial Monitor input field and press Enter.
  6. The sketch will calculate and print your calibration factor. Write this number down.

🔗Step 4: Upload the main code

Replace the CALIBRATION_FACTOR value with the number you found during calibration.

#include "HX711.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// ---- Pin definitions ----
#define HX711_DT   4
#define HX711_SCK  5
#define TARE_BTN   14

// ---- OLED configuration ----
#define SCREEN_WIDTH  128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1  // No reset pin
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// ---- Calibration ----
// Replace this with the value from the calibration sketch.
const float CALIBRATION_FACTOR = 420.0;

// ---- Globals ----
HX711 scale;
float currentWeight = 0.0;
unsigned long lastReadTime = 0;
const unsigned long READ_INTERVAL = 200; // Read every 200ms

void displayWeight(float weight) {
    display.clearDisplay();

    // Title
    display.setTextColor(SSD1306_WHITE);
    display.setTextSize(1);
    display.setCursor(30, 0);
    display.print("Kitchen Scale");

    // Divider line
    display.drawLine(0, 12, 127, 12, SSD1306_WHITE);

    // Weight value — large text
    display.setTextSize(3);
    // Right-align the weight value
    String weightStr;
    if (weight >= 0) {
        weightStr = String(weight, 1);
    } else {
        weightStr = String(weight, 1);
    }

    // Calculate cursor position for right-alignment (before the "g" label)
    int16_t x1, y1;
    uint16_t w, h;
    display.getTextBounds(weightStr, 0, 0, &x1, &y1, &w, &h);
    int xPos = 90 - w; // Leave room for "g" on the right
    if (xPos < 0) xPos = 0;

    display.setCursor(xPos, 22);
    display.print(weightStr);

    // Unit label
    display.setTextSize(2);
    display.setCursor(95, 26);
    display.print("g");

    // Bottom instruction
    display.setTextSize(1);
    display.setCursor(20, 54);
    display.print("Press btn to tare");

    display.display();
}

void setup() {
    Serial.begin(115200);

    // Initialize button
    pinMode(TARE_BTN, INPUT);

    // Initialize OLED
    if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
        Serial.println("ERROR: SSD1306 OLED not found.");
        while (1) { delay(1000); }
    }
    display.clearDisplay();
    display.setTextColor(SSD1306_WHITE);
    display.setTextSize(1);
    display.setCursor(20, 28);
    display.print("Initializing...");
    display.display();

    // Initialize HX711
    scale.begin(HX711_DT, HX711_SCK);
    scale.set_scale(CALIBRATION_FACTOR);
    scale.tare(20); // Average 20 readings for zero point

    Serial.println("Kitchen Scale ready");
    Serial.print("Calibration factor: ");
    Serial.println(CALIBRATION_FACTOR, 2);
}

void loop() {
    // Handle tare button
    if (digitalRead(TARE_BTN) == HIGH) {
        Serial.println("Tare button pressed");
        display.clearDisplay();
        display.setTextSize(1);
        display.setCursor(30, 28);
        display.print("Taring...");
        display.display();

        scale.tare(20);
        delay(500); // Brief pause so the user sees the message
    }

    // Read weight at interval
    if (millis() - lastReadTime >= READ_INTERVAL) {
        lastReadTime = millis();

        if (scale.is_ready()) {
            currentWeight = scale.get_units(5); // Average of 5 readings

            // Filter out tiny noise around zero
            if (abs(currentWeight) < 0.5) {
                currentWeight = 0.0;
            }

            displayWeight(currentWeight);

            Serial.print("Weight: ");
            Serial.print(currentWeight, 1);
            Serial.println(" g");
        }
    }
}

🔗Step 5: Using the scale

  1. Upload the main sketch and let it initialize. The OLED should show "Initializing..." briefly, then display 0.0 g.
  2. Place a container (bowl, plate) on the load cell and press the tare button to zero it out.
  3. Add your ingredient. The weight updates in real time on the OLED screen.
  4. Press the tare button again any time you want to reset to zero (for example, between ingredients).

For the most stable readings, place the load cell on a flat, hard surface. Soft surfaces like tablecloths or cutting boards can introduce vibrations and inaccurate readings.

🔗Mounting the load cell

Most bar-type load cells need to be mounted with one end fixed and the other end free to deflect. A common setup:

  1. Screw one end of the load cell to a rigid base (a piece of wood or 3D-printed plate).
  2. Attach a flat platform (another piece of wood or acrylic) to the other end.
  3. The platform is where you place items to weigh.

Check your load cell's datasheet for the correct mounting orientation — the arrow printed on the cell typically indicates the direction of applied force.

🔗Common Issues and Solutions

ProblemCauseFix
Readings drift slowly over timeTemperature changes affecting the load cell, or unstable mountingLet the scale warm up for a few minutes. Tare before each use. Ensure the load cell is rigidly mounted
Weight reads negativeLoad cell wires A+ and A- swappedSwap the white and green wires on the HX711, or multiply the calibration factor by -1
OLED shows "ERROR: SSD1306 OLED not found"Wrong I2C address or wiring issueCheck SDA→GPIO 21, SCL→GPIO 22. Try I2C address 0x3D instead of 0x3C (some OLEDs use a different address)
Display shows weight but it is wrongCalibration factor incorrectRe-run the calibration sketch with a known weight. Double-check that you entered the weight in grams
Readings jump around wildlyElectrical noise, loose wiring, or unstable surfaceCheck all connections. Use shorter wires. Place the load cell on a solid, flat surface. Increase the averaging count in get_units()
HX711 never becomes readyDT and SCK pins swapped, or module not poweredVerify DT→GPIO 4, SCK→GPIO 5. Check 3.3V power to the HX711
Tare button does not respondPull-down resistor missing or wrong GPIOEnsure 10k resistor connects GPIO 14 to GND. Check that the button connects GPIO 14 to 3.3V when pressed
Scale cannot measure small amounts accuratelyLoad cell capacity too large for the weightA 10 kg cell has lower resolution for sub-gram measurements. Use a 1 kg cell for precision with small items