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
- Description: A microcontroller board based on the ATmega328P. It has 14 digital input/output pins, 6 analog inputs, a USB connection, a power jack, an ICSP header, and a reset button.
- Purpose: Acts as the main controller for the circuit, processing input from the load cell and managing the output.
HX711 Load Cell (5kg)
- Description: A precision load cell with a maximum capacity of 5kg. It includes an integrated HX711 ADC for converting the analog signal from the load cell into a digital signal.
- Purpose: Measures weight and provides the data to the Arduino for processing.
Comment V2
- Description: A placeholder component for documentation purposes.
- Purpose: Not utilized in the circuit but included for clarity in the design.
Wiring Details
Arduino UNO
- 5V: Connected to VCC of HX711 Load Cell
- GND: Connected to GND of HX711 Load Cell
- D5: Connected to CLK of HX711 Load Cell
- D4: Connected to DAT of HX711 Load Cell
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.
