A load cell gives a tiny signal that the HX711 amplifies and turns into a 24-bit number. The Pico W clocks it out on two GPIOs, DT on GP16 and SCK on GP17, with no library.
Power the HX711 from 3V3, connect the four load-cell wires, and the script tares itself at start-up. One calibration with a known weight turns raw counts into grams.
Wiring
| Raspberry Pi Pico W | HX711 load cell amplifier | Wire | Notes |
|---|---|---|---|
| — | E+ | — | To Load cell red (not drawn) |
| — | E- | — | To Load cell black (not drawn) |
| — | A- | — | To Load cell white (not drawn) |
| — | A+ | — | To Load cell green (not drawn) |
| 3V3 | VCC | red | 3V3 is pin 36. DT then switches at 3.3 V. |
| GND | GND | black | |
| GP16 | DT | green | GP16 is physical pin 21. |
| GP17 | SCK | yellow | GP17 is physical pin 22. |
2.6–5.5 V part, 3.3 V board. DT and SCK follow the module’s VCC. On 3.3 V boards, power the HX711 from 3.3 V; the load-cell excitation is then lower, but the readings are still fine after calibration.
Board quirks
- The read is bit-banged with interrupts briefly off: if SCK stays HIGH longer than 60 µs the HX711 powers down, and a Wi-Fi interrupt at the wrong moment could do that.
- Calibrate: start with the scale empty (it tares automatically), put a known weight on (a 1 kg atta packet works), note the Raw number and set
CAL_FACTOR = raw ÷ grams. - Wire colours vary between load cells. If the weight goes negative, swap the A+ and A− wires.
- At 3.3 V the excitation is lower than at 5 V, so each gram gives fewer counts — still plenty for a kitchen scale after calibration.
Code
# HX711 + load cell (kitchen-scale style) on a Raspberry Pi Pico W (MicroPython, no library).
# Wiring: VCC -> 3V3 (pin 36), GND -> GND, DT -> GP16 (pin 21), SCK -> GP17 (pin 22).
# Load cell: red -> E+, black -> E-, white -> A-, green -> A+ (colours vary - check your cell).
# Calibrate: run once with nothing on, then with a known weight, and set CAL_FACTOR.
from machine import Pin
import machine
import time
CAL_FACTOR = 420.0 # raw counts per gram <- replace with yours (see the guide)
dt = Pin(16, Pin.IN)
sck = Pin(17, Pin.OUT, value=0)
def read_raw():
t0 = time.ticks_ms()
while dt.value(): # DT goes LOW when a new conversion is ready (10 per second)
if time.ticks_diff(time.ticks_ms(), t0) > 500:
raise OSError("HX711 not ready - check DT/SCK and power")
value = 0
state = machine.disable_irq() # SCK HIGH longer than 60 us would power the HX711 down
try:
for _ in range(24):
sck.value(1)
sck.value(0)
value = (value << 1) | dt.value()
sck.value(1) # 25th pulse = channel A, gain 128 for the next reading
sck.value(0)
finally:
machine.enable_irq(state)
if value & 0x800000: # 24-bit two's complement
value -= 0x1000000
return value
def read_avg(n=10):
return sum(read_raw() for _ in range(n)) / n
print("HX711 on DT GP16 / SCK GP17 - taring, keep the scale empty")
time.sleep(1)
offset = read_avg(20)
print("Tare offset:", int(offset))
while True:
raw = read_avg(5)
grams = (raw - offset) / CAL_FACTOR
print("Raw {:9d} Weight {:8.1f} g".format(int(raw - offset), grams))
time.sleep_ms(500)# HX711 + load cell (kitchen-scale style) on a Raspberry Pi Pico W (MicroPython, no library).
# Wiring: VCC -> 3V3 (pin 36), GND -> GND, DT -> GP16 (pin 21), SCK -> GP17 (pin 22).
# Load cell: red -> E+, black -> E-, white -> A-, green -> A+ (colours vary - check your cell).
# Calibrate: run once with nothing on, then with a known weight, and set CAL_FACTOR.
from machine import Pin
import machine
import time
CAL_FACTOR = 420.0 # raw counts per gram <- replace with yours (see the guide)
dt = Pin(16, Pin.IN)
sck = Pin(17, Pin.OUT, value=0)
def read_raw():
t0 = time.ticks_ms()
while dt.value(): # DT goes LOW when a new conversion is ready (10 per second)
if time.ticks_diff(time.ticks_ms(), t0) > 500:
raise OSError("HX711 not ready - check DT/SCK and power")
value = 0
state = machine.disable_irq() # SCK HIGH longer than 60 us would power the HX711 down
try:
for _ in range(24):
sck.value(1)
sck.value(0)
value = (value << 1) | dt.value()
sck.value(1) # 25th pulse = channel A, gain 128 for the next reading
sck.value(0)
finally:
machine.enable_irq(state)
if value & 0x800000: # 24-bit two's complement
value -= 0x1000000
return value
def read_avg(n=10):
return sum(read_raw() for _ in range(n)) / n
print("HX711 on DT GP16 / SCK GP17 - taring, keep the scale empty")
time.sleep(1)
offset = read_avg(20)
print("Tare offset:", int(offset))
while True:
raw = read_avg(5)
grams = (raw - offset) / CAL_FACTOR
print("Raw {:9d} Weight {:8.1f} g".format(int(raw - offset), grams))
time.sleep_ms(500)Expected serial output
HX711 on DT GP16 / SCK GP17 - taring, keep the scale empty
Tare offset: 84213
Raw -12 Weight -0.0 g
Raw 419862 Weight 999.7 gHX711 on DT GP16 / SCK GP17 - taring, keep the scale empty Tare offset: 84213 Raw -12 Weight -0.0 g Raw 419862 Weight 999.7 g
Common errors
OSError: HX711 not ready - check DT/SCK and power
DT never went LOW: DT and SCK swapped, or no power. DT → GP16, SCK → GP17.
Readings jump by thousands
Loose load-cell joints or a flexing mount. Solder the wires and bolt the cell between two rigid plates.