HX711 basierte Waage

Über den Beitrag

Mit einem HX711 Modul und einer Wägezelle ist es kinderleicht, eine erstaunlich exakte Waage zu bauen. In diesem Beitrag möchte ich zeigen wie das prinzipiell funktioniert.  

Mein Ziel war es, die gleiche Funktionalität wie die meiner digitalen Küchenwaage zu erreichen: 

  • Ausgabe des Gewichtes auf einem Display
  • Nur ein Knopf zum Anschalten und für Tara
  • Automatisches Ausschalten nach einer bestimmten Zeit

Der Beitrag ist folgendermaßen gegliedert:

Was ihr braucht

Typisches Set aus Wägezelle und HX711 Modul
Typisches Set aus Wägezelle und HX711 Modul

Zum Bau der Waage benötigt ihr eine Wägezelle und ein HX711 Modul. Beides könnt ihr im Set kaufen. Wenn ihr z.B. bei Amazon oder eBay nach „HX711 Wägezelle“ sucht, bekommt ihr Dutzende von Angeboten für wenige Euro. Wählt eine Wägezelle mit dem für euch passenden Gewichtsbereich. Ich habe mir eine 2 kg Zelle besorgt. 

Was ihr sonst benötigt, kann ich euch nicht in einer konkreten Einkaufsliste vorgeben, da es zu sehr davon abhängt, wie ihr eure Waage gestalten wollt. Lest am besten erstmal weiter und entscheidet dann selbst.

Das Messprinzip

Die Wägezelle wird durch das Gewicht der zu wiegenden Last leicht gebogen. Unter dem weißen Kleber sitzt ein Dehnungsmessstreifen, dessen Widerstand sich mit dem Dehnungsgrad, also mit dem Gewicht, ändert. Der Widerstand wird über den Spannungsabfall bestimmt und der wiederum mit einem A/D-Wandler ausgewertet. 

Die Änderung des Spannungsabfalls mit steigendem Gewicht ist recht gering. Ich habe wenige Millivolt pro Kilogramm gemessen. Der A/D-Wandler eines Arduino UNO bzw. eines ATmega328P ist dafür nicht geeignet. Der HX711 hingegen besitzt eine beeindruckende Auflösung von 24 Bit (= 16.777.216 Stufen).

Der HX711 selbst ist dabei eigentlich nur der sechzehnbeinige Chip auf dem Modul. Da er noch ein paar Elemente zur Beschaltung benötigt, bietet es sich an, zum Modul zu greifen. Wenn ihr euch trotzdem auch für die technischen Details des HX711 interessiert, dann findet ihr hier ein Datenblatt.

Verbauen der Wägezelle

Um ein bisschen Heimwerkern kommt ihr nicht herum. Die Wägezelle muss so eingebaut werden, dass sie sich unter Gewicht auch biegen kann. Ich habe dazu einfach ein Brett genommen und zwei gleich große Stücke abgesägt. Zwischen die Bretter kam die Wägezelle mit Abstandshaltern.

Die Wägezelle mit Abstandhaltern zwischen zwei Brettstücken
Die Wägezelle mit Abstandhaltern zwischen zwei Brettstücken

Durch das untere Brett habe ich zwei Löcher gebohrt und die Wägezelle mit zwei M5 Schrauben fixiert. Damit die Waage nicht direkt mit dem Brett aufliegt, habe ich ihr noch ein paar Füße spendiert: 

Unterseite der HX711 Waage
Unterseite der Waage

Für die andere Seite sind eigentlich M4 Schrauben vorgesehen. Um eine glatte Auflagefläche für das Wägegut zu behalten, wollte ich das obere Brett aber nicht durchbohren. Deswegen habe ich einfach ein paar Holzschrauben genommen.  

Von mir gewählte Schrauben
Von mir gewählte Schrauben

Die Kabel der Wägezelle werden folgendermaßen mit dem Modul verbunden:

  • Rot an E+
  • Schwarz an E-
  • Weiß an A-
  • Grün an E+
Anschluss der Wägezelle an das HX711 Modul
Anschluss der Wägezelle an das HX711 Modul

So sieht dann der Zwischenstand aus:

Die HX711 basierte Waage im Rohzustand
Die Waage im Rohzustand

Verwendung der HX711 ADC Bibliothek

Zur Ansteuerung des Moduls habe ich die HX711 ADC Bibliothek von Olav Kallhovd verwendet. Ihr könnt sie hier direkt von Github herunterladen oder ihr installiert sie über die Bibliotheksverwaltung der Arduino IDE. 

HX711 Grundschaltung

Minimumbeschaltung des HX711 am Arduino UNO
Minimumbeschaltung des HX711 am Arduino UNO

Das Modul kann mit Spannungen zwischen 2.6 und 5.5 Volt betrieben werden. Das Modul ist mit < 1.5 mA Stromverbrauch recht sparsam. Der DT-Pin wird mit dem Arduino Pin 4 verbunden, SCK kommt an Pin 5. Die Pins können auch geändert werden. 

Kalibrierung der Waage

Zur Kalibrierung braucht ihr einen Gegenstand mit bekanntem Gewicht. Das Gewicht sollte auf das Gramm genau bekannt und nicht zu klein sein. Am besten nehmt ihr eine zweite Waage zur Hilfe. 

Das Schöne an der hier verwendeten Bibliothek ist, dass sie euch das Leben – oder zumindest die Waagenkalibrierung – sehr einfach macht. Wählt aus den Beispielen der Bibliothek den Sketch „Calibration.ino“. Ich habe ihn hier unverändert abgedruckt:

//-------------------------------------------------------------------------------------
// HX711_ADC.h
// Arduino master library for HX711 24-Bit Analog-to-Digital Converter for Weigh Scales
// Olav Kallhovd sept2017
// Tested with      : HX711 asian module on channel A and YZC-133 3kg load cell
// Tested with MCU  : Arduino Nano, ESP8266
//-------------------------------------------------------------------------------------
// This is an example sketch on how to use this library
// Settling time (number of samples) and data filtering can be adjusted in the config.h file

// This example shows how to calibrate the load cell and optionally save the calibration  
// value to EEPROM, and also how to change the value.
// The value can later be fetched from EEPROM in your project sketch.

#include <HX711_ADC.h>
#include <EEPROM.h>

//HX711 constructor (dout pin, sck pin):
HX711_ADC LoadCell(4, 5);

int eepromAdress = 0;

unsigned long t = 0;

void calibrate() {
  Serial.println("***");
  Serial.println("Start calibration:");
  Serial.println("It is assumed that the mcu was started with no load applied to the load cell.");
  Serial.println("Now, place your known mass on the loadcell,");
  Serial.println("then send the weight of this mass (i.e. 100.0) from serial monitor.");
  float m = 0;
  boolean f = 0;
  while (f == 0) {
    LoadCell.update();
    if (Serial.available() > 0) {
      m = Serial.parseFloat();
      if (m != 0) {
        Serial.print("Known mass is: ");
        Serial.println(m);
        f = 1;
      }
      else {
        Serial.println("Invalid value");
      }
    }
  }
  float c = LoadCell.getData() / m;
  LoadCell.setCalFactor(c);
  Serial.print("Calculated calibration value is: ");
  Serial.print(c);
  Serial.println(", use this in your project sketch");
  f = 0;
  Serial.print("Save this value to EEPROM adress ");
  Serial.print(eepromAdress);
  Serial.println("? y/n");
  while (f == 0) {
    if (Serial.available() > 0) {
      char inByte = Serial.read();
      if (inByte == 'y') {
        #if defined(ESP8266) 
        EEPROM.begin(512);
        #endif
        EEPROM.put(eepromAdress, c);
        #if defined(ESP8266)
        EEPROM.commit();
        #endif
        EEPROM.get(eepromAdress, c);
        Serial.print("Value ");
        Serial.print(c);
        Serial.print(" saved to EEPROM address: ");
        Serial.println(eepromAdress);
        f = 1;

      }
      else if (inByte == 'n') {
        Serial.println("Value not saved to EEPROM");
        f = 1;
      }
    }
  }
  Serial.println("End calibration");
  Serial.println("For manual edit, send 'c' from serial monitor");
  Serial.println("***");
}

void changeSavedCalFactor() {
  float c = LoadCell.getCalFactor();
  boolean f = 0;
  Serial.println("***");
  Serial.print("Current value is: ");
  Serial.println(c);
  Serial.println("Now, send the new value from serial monitor, i.e. 696.0");
  while (f == 0) {
    if (Serial.available() > 0) {
      c = Serial.parseFloat();
      if (c != 0) {
        Serial.print("New calibration value is: ");
        Serial.println(c);
        LoadCell.setCalFactor(c);
        f = 1;
      }
      else {
        Serial.println("Invalid value, exit");
        return;
      }
    }
  }
  f = 0;
  Serial.print("Save this value to EEPROM adress ");
  Serial.print(eepromAdress);
  Serial.println("? y/n");
  while (f == 0) {
    if (Serial.available() > 0) {
      char inByte = Serial.read();
      if (inByte == 'y') {
        #if defined(ESP8266)
        EEPROM.begin(512);
        #endif
        EEPROM.put(eepromAdress, c);
        #if defined(ESP8266)
        EEPROM.commit();
        #endif
        EEPROM.get(eepromAdress, c);
        Serial.print("Value ");
        Serial.print(c);
        Serial.print(" saved to EEPROM address: ");
        Serial.println(eepromAdress);
        f = 1;
      }
      else if (inByte == 'n') {
        Serial.println("Value not saved to EEPROM");
        f = 1;
      }
    }
  }
  Serial.println("End change calibration value");
  Serial.println("***");
}

void setup() {
  Serial.begin(9600); delay(10);
  Serial.println();
  Serial.println("Starting...");
  LoadCell.begin();
  long stabilisingtime = 2000; // tare preciscion can be improved by adding a few seconds of stabilising time
  LoadCell.start(stabilisingtime);
  if (LoadCell.getTareTimeoutFlag()) {
    Serial.println("Tare timeout, check MCU>HX711 wiring and pin designations");
  }
  else {
    LoadCell.setCalFactor(1.0); // user set calibration value (float)
    Serial.println("Startup + tare is complete");
  }
  while (!LoadCell.update());
  calibrate();
}
void loop() {
  //update() should be called at least as often as HX711 sample rate; >10Hz@10SPS, >80Hz@80SPS
  //longer delay in sketch will reduce effective sample rate (be carefull with delay() in the loop)
  LoadCell.update();

  //get smoothed value from the data set
  if (millis() > t + 250) {
    float i = LoadCell.getData();
    Serial.print("Load_cell output val: ");
    Serial.println(i);
    t = millis();
  }

  //receive from serial terminal
  if (Serial.available() > 0) {
    char inByte = Serial.read();
    if (inByte == 't') LoadCell.tareNoDelay();
    else if (inByte == 'c') changeSavedCalFactor();
  }

  //check if last tare operation is complete
  if (LoadCell.getTareStatus() == true) {
    Serial.println("Tare complete");
  }

}

 

 

Startet den Sketch und öffnet den seriellen Monitor. Wartet bis folgende Meldung kommt:

Wagenkalibrierung am seriellen Monitor
Wagenkalibrierung am seriellen Monitor, Eingabe des bekannten Gewichtes

Dann nehmt euer Gewicht, legt es auf die Waage, gebt das Gewicht in Gramm ein und drückt Enter oder auf Senden. Notiert euch den „calibration value“ oder lasst ihn ins EEPROM des Arduino UNO schreiben. Dann wird munter das Gewicht ausgespuckt:

Die Waage im "Regelbetrieb"
Ergebnis der Waagenkalibrierung

Wenn das Gewicht ein wenig driftet, dann wiederholt die Kalibrierung und versucht mal eine längere „stabilisingtime“ (Zeile 145).  

Regelbetrieb am PC
Mein „Eichmaß“

Regelbetrieb der HX711 Waage

Nachdem ihr die Waage kalibriert habt, könnt ihr nun in den Regelbetrieb gehen. Dafür bietet sich der Sketch „Read_1x_load_cell.ino“ an, zumindest als Grundlage. Ihr müsst lediglich in Zeile 41 euren Kalibrierfaktor eintragen oder – falls ihr ihn im EEPROM habt – Zeile 45 entkommentieren. Ansonsten funktioniert der Sketch „out of the box“. Wenn ihr einen ESP8266 verwendet, müsst ihr zusätzlich noch Zeile 43 entkommentieren.

Für die Tara gebt ihr ein „t“ im seriellen Monitor ein.

/*
   -------------------------------------------------------------------------------------
   HX711_ADC
   Arduino library for HX711 24-Bit Analog-to-Digital Converter for Weight Scales
   Olav Kallhovd sept2017
   -------------------------------------------------------------------------------------
*/

/*
   Settling time (number of samples) and data filtering can be adjusted in the config.h file
   For calibration and storing the calibration value in eeprom, see example file "Calibration.ino"

   The update() function checks for new data and starts the next conversion. In order to acheive maximum effective
   sample rate, update() should be called at least as often as the HX711 sample rate; >10Hz@10SPS, >80Hz@80SPS.
   If you have other time consuming code running (i.e. a graphical LCD), consider calling update() from an interrupt routine,
   see example file "Read_1x_load_cell_interrupt_driven.ino".

   This is an example sketch on how to use this library
*/

#include <HX711_ADC.h>
#include <EEPROM.h>

//pins:
const int HX711_dout = 4; //mcu > HX711 dout pin
const int HX711_sck = 5; //mcu > HX711 sck pin

//HX711 constructor:
HX711_ADC LoadCell(HX711_dout, HX711_sck);

const int calVal_eepromAdress = 0;
long t;

void setup() {
  Serial.begin(57600); delay(10);
  Serial.println();
  Serial.println("Starting...");

  LoadCell.begin();
  float calibrationValue; // calibration value (see example file "Calibration.ino")
  calibrationValue = 696.0; // uncomment this if you want to set the calibration value in the sketch
#if defined(ESP8266)|| defined(ESP32)
  //EEPROM.begin(512); // uncomment this if you use ESP8266/ESP32 and want to fetch the calibration value from eeprom
#endif
  //EEPROM.get(calVal_eepromAdress, calibrationValue); // uncomment this if you want to fetch the calibration value from eeprom

  long stabilizingtime = 2000; // preciscion right after power-up can be improved by adding a few seconds of stabilizing time
  boolean _tare = true; //set this to false if you don't want tare to be performed in the next step
  LoadCell.start(stabilizingtime, _tare);
  if (LoadCell.getTareTimeoutFlag()) {
    Serial.println("Timeout, check MCU>HX711 wiring and pin designations");
    while (1);
  }
  else {
    LoadCell.setCalFactor(calibrationValue); // set calibration value (float)
    Serial.println("Startup is complete");
  }
}

void loop() {
  static boolean newDataReady = 0;
  const int serialPrintInterval = 0; //increase value to slow down serial print activity

  // check for new data/start next conversion:
  if (LoadCell.update()) newDataReady = true;

  // get smoothed value from the dataset:
  if (newDataReady) {
    if (millis() > t + serialPrintInterval) {
      float i = LoadCell.getData();
      Serial.print("Load_cell output val: ");
      Serial.println(i);
      newDataReady = 0;
      t = millis();
    }
  }

  // receive command from serial terminal, send 't' to initiate tare operation:
  if (Serial.available() > 0) {
    float i;
    char inByte = Serial.read();
    if (inByte == 't') LoadCell.tareNoDelay();
  }

  // check if last tare operation is complete:
  if (LoadCell.getTareStatus() == true) {
    Serial.println("Tare complete");
  }

}

 

Vielleicht wollt ihr beim Einschalten nicht tarieren? Dann ändert in Zeile 48 den Wert für _tare auf false. Ihr bekommt dann einen „Fantasiewert“ als Messergebnis. Schreibt euch diesen Wert auf und zieht ihn von zukünftigen Messergebnissen ab. Damit habt ihr die Tara sozusagen eingefroren. 

Ich habe die HX711 basierte Waage dann gegen meine Küchenwaage getestet… 

Es treten an: meine Küchenwaage...
Es treten an: meine Küchenwaage…
... gegen den HX711 Eigenbau.
… gegen den HX711 Eigenbau.

… und die Ergebnisse stimmten aufs Gramm!

Ausgabe über ein OLED-Display

Um die Waage vom PC unabhängig zu machen, braucht ihr ein Ausgabemedium. Ich habe dazu ein kleines OLED-Display ausgewählt, das nur wenige Milliampere Strom benötigt. Es wird über I2C mit Hilfe der Bibliotheken Adafruit GFX und Adafruit SSD1306 angesteuert. Falls ihr das auch tun wollt könnt ihr die Bibliotheken von Github über die Links herunterladen oder über die Bibliotheksverwaltung installieren. Auf die Details gehe ich hier nicht ein, denn das würde den Rahmen sprengen. Außerdem wollt ihr ja vielleicht auch ganz andere Displays einsetzen oder Sieben-Segmentanzeigen.

Ausgabe über ein TFT-Display
Ausgabe über ein TFT-Display

Nun noch paar Anmerkungen zum folgenden Sketch. Ein bisschen Aufwand habe ich betrieben um das Gewicht rechtsbündig anzuzeigen. Das wird in der Funktion floatToDisplayString bewerkstelligt. Die Funktion ermittelt zunächst die Zahl der freien Stellen (blanks) und hängt dann das Gewicht als String dran. 

Taramessungen werden über Interrupts an Pin 2 angefordert. Ausgelöst wird der Interrupt über einen Taster. Auf Tasterdruck wird die Variable taraRequest true und dadurch in der loop Schleife eine Taramessung initiiert. Während der Taramessung gibt die Waage ein „Wait“ auf dem Display aus. 

Der Rest des Sketches sollte halbwegs selbsterklärend sein (das behauptet natürlich jeder…). Wenn ihr fragen habt, fragt!

#include <Wire.h>
#include <HX711_ADC.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 7 // we don't have a reset, but the constructor expects it 

Adafruit_SSD1306 display(OLED_RESET);
HX711_ADC LoadCell(4, 5);

byte interruptPin=2;
volatile bool taraRequest = false;

void setup()   {                
  pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), taraEvent, RISING);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x64)
  display.clearDisplay();
  display.setTextSize(4);
  display.setTextColor(WHITE);
  display.setCursor(10,4);
  display.println("Wait");
  display.display();
  LoadCell.begin();
  LoadCell.start(2000); 
  LoadCell.setCalFactor(883.73); 
}


void loop() {
  float weightAsFloat = 0.0;
  unsigned long t = 0;
  
  LoadCell.update();
  
  if (millis() > t + 250) {
    weightAsFloat = LoadCell.getData();
    displayWeight(weightAsFloat);
    t = millis();  
  }
  if(taraRequest){
    doTara();
    taraRequest = false;
  }
}

void displayWeight(float weight){
  String weightAsString = "";
  weightAsString = floatToDisplayString(weight);
  display.clearDisplay();
  display.setCursor(0,4);
  display.println(weightAsString);
  display.display();
}

void doTara(){
  LoadCell.tareNoDelay();
  display.clearDisplay();
  display.setCursor(10,4);
  display.println("Wait");
  display.display();
  while(LoadCell.getTareStatus()== false){
    LoadCell.update();
    delay(50);
  }
}

void taraEvent(){
  taraRequest = true;
}

String floatToDisplayString(float floatValue){
  String stringValue=" ";
  int intValue = (int)(round(floatValue));
  if(intValue<0){
    stringValue="";
  }
  uint8_t blanks = 3 - int(log10(abs(intValue)));
  for(int i=0; i<blanks; i++){
    stringValue+=" ";
  }
  stringValue+=(String)intValue;
  return stringValue; 
}

 

Und so sieht es dann aus:

HX711 Waage OLED Display und Tara - Taster
OLED Display und Tara – Taster

Der nächste Evolutionsschritt: Die Waage geht schlafen

Dann wollte ich, dass die Waage bzw. ihre Komponenten in einen Standby Modus gehen, wenn über einige Zeit weder eine Gewichtsänderung stattfindet, noch eine neue Taramessung angefordert wird. Da der Arduino UNO im Schlafmodus immer noch viel Strom verbraucht (siehe mein vorletzter Beitrag über Sleep Modes), habe ich hier den „nackten“ ATmega328P verwendet. Wie man mit den ATmega328P mit der Arduino IDE programmiert, habe ich hier beschrieben. Die Schaltung dazu sieht folgendermaßen aus: 

Vollständige Schaltung für die Waage mit Display und Taraknopf
Vollständige Schaltung für die Waage mit Display und Taraknopf

Im Sketch zu dieser Variante habe ich die Variable lastWeightAsFloat eingeführt, die den Wert der jeweils letzten Messung speichert. Dieser Wert wird mit dem aktuellen Messwert verglichen. Solange sich das letzte und das aktuelle Gewicht unterscheiden (Differenz < 1 g), ist die Waage offensichtlich in Benutzung. Und so lange wird die Variable tLastChange immer wieder auf millis aktualisiert. Das gleiche passiert bei einer Taramessung. Einmal pro Hauptschleife wird tLastChange mit millis verglichen. Überschreitet die Differenz 120.000 (= 2 min), wird die Waage in den Schlaf geschickt. Zunächst wird dazu das Display ausgeschaltet, dann das HX711 Modul und schließlich wird der ATmega328P in den Tiefschlafmodus versetzt.

Ein Interrupt weckt den ATmega328P wieder. Da der Taster für die Taramessung einen Interrupt auslöst, übernimmt er auch die Weckfunktion.

#include <Wire.h>
#include <HX711_ADC.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <avr/sleep.h>
#define OLED_RESET 9 // we don't have a reset, but the constructor expects it 

Adafruit_SSD1306 display(OLED_RESET);
HX711_ADC LoadCell(4, 5);

int interruptPin = 2;   // tara and wake-up pin 
int powerOnPin = 6;
volatile bool taraRequest = false;
float weightAsFloat = 0.0; // current weight (as float)
float lastWeightAsFloat = 9999.0;  // former weight
unsigned long t = 0;    // system time of last weight measurement 
unsigned long tLastChange = 0;  // system time of last change of weight

void setup()   {  
  pinMode(interruptPin, INPUT);
  pinMode(powerOnPin, OUTPUT);
  digitalWrite(powerOnPin, HIGH);
  initBalance();
  attachInterrupt(digitalPinToInterrupt(interruptPin), taraEvent, RISING);
}

void loop() {
  LoadCell.update();
  /* In one loop a) measurement is done or b) a tara or c) the balance will be send to sleep
  or d) nothing happens */
  if (millis() > (t + 250)) {
    weightAsFloat = LoadCell.getData();
    displayWeight(weightAsFloat);
    if(abs(weightAsFloat-lastWeightAsFloat) >=1){
      tLastChange = millis();
      lastWeightAsFloat = weightAsFloat;  
    }
    t = millis();
  }
  
  if(taraRequest){
    doTara();
    taraRequest = false;
  }
  
  if(millis() > (tLastChange + 120000)){ // after 2 min of no weight change or tara the balance shall fall asleep
    sleepAndWakeUp();
  }
}

void initBalance(){
  taraRequest = false;
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x64)
  display.clearDisplay();
  display.setTextSize(4);
  display.setTextColor(WHITE);
  display.setCursor(10,4);
  display.println("Wait");
  display.display();
  LoadCell.begin();
  LoadCell.start(2000); 
  LoadCell.setCalFactor(883.73); 
  weightAsFloat = 0.0;
  lastWeightAsFloat = 9999.0;
  t = 0;
}

void displayWeight(float weight){
  String weightAsString = "";
  weightAsString = floatToDisplayString(weight);
  display.clearDisplay();
  display.setCursor(0,4);
  display.println(weightAsString);
  display.display();
}

/* The following function displays the weight. The weight is therefore
 * changed into a string. The weight shall be displaey on the right side,
 * therefore the string begins with blanks.  
 */
String floatToDisplayString(float floatValue){
  String stringValue=" ";
  int intValue = (int)(round(floatValue));
  if(intValue<0){
    stringValue="";
  }
  uint8_t blanks = 3 - int(log10(abs(intValue)));
  for(int i=0; i<blanks; i++){
    stringValue+=" ";
  }
  stringValue+=(String)intValue;
  return stringValue; 
}

void doTara(){    // tara
  LoadCell.tareNoDelay();
  display.clearDisplay();
  display.setCursor(10,4);
  display.println("Wait");
  display.display();
  while(LoadCell.getTareStatus()== false){
    LoadCell.update();
    delay(50);
  }
  tLastChange = millis();
}

void taraEvent(){
  taraRequest = true;
}

void sleepAndWakeUp(){
  LoadCell.powerDown();            // switch off HX711
  display.ssd1306_command(SSD1306_DISPLAYOFF);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // deep sleep mode
  cli();
  sleep_enable();
  sleep_bod_disable(); // disable brown-out detector
  sei();
  sleep_cpu();
  /* ATmega328P sleeps */
  sleep_disable();
  LoadCell.powerUp();            // switch on HX711
  display.ssd1306_command(SSD1306_DISPLAYON);
  initBalance();
}

 

Mit diesem Aufbau habe ich im Schlafmodus einen Stromverbrauch von 139 Mikroampere ermittelt. Das sind 3.3 Milliamperestunden pro Tag. Ein Akku sollte also einige Zeit halten.

Die Waage ganz ausschalten

Dann habe ich mir überlegt, wie man die Waage ganz ausschalten kann, ohne einen zusätzlichen Schalter einzubauen (denn das kann ja jeder!). Genau genommen lautet die Frage, wie sich die Waage selbst ausschalten kann.

Ich habe die Aufgabenstellung mit einem Thyristor gelöst. Ein Thyristor hat eine gewisse Verwandtschaft mit einem Transistor. Er besitzt drei Anschlüsse, nämlich die Kathode, die Anode und das Gate. Ein kleiner Stromimpuls am Gate macht den Übergang von Anode zu Kathode leitend. Im Gegensatz zum Transistor bleibt der Thyristor leitend, solange der sogenannte Haltestrom überschritten wird. Bei dem von mir verwendeten MCR100-6 liegt der Haltestrom typischerweise bei 0.5 Milliampere. Da der Stromverbrauch im Sleep Modus wesentlich geringer ist, schließt der Thyristor. „Gezündet“ wird der Thyristor mit Hilfe des Taraknopfes. So sieht die Schaltung dazu aus:

Die sich selbst abschaltende HX711 Waagenschaltung
Die sich selbst abschaltende Waagenschaltung

Dabei gab es noch ein Problem: Solange der Thyristor leitet, bleibt auch die Spannung am Gate hoch. Da wir hier nun eine Verbindung zur Tarafunktion haben, bleibt auch die Spannung am Interruptpin hoch (orangefarbene Leitung). Damit funktioniert die Tara Anforderung nicht mehr. Deshalb habe ich noch eine Diode eingebaut, die den Weg in diese Richtung versperrt.

Ihr könnt den vorherigen Sketch verwenden. Zeile 122 bis 125, also die Aktionen nach dem Wake-Up, werden natürlich nie ausgeführt und können entsprechend gelöscht werden. 

Bei der Auslegung der Stromversorgung ist zu beachten, dass am Thyristor ca. 0.8 Volt abfallen. Entsprechend weniger steht den Bauteilen zur Verfügung. Bei 5 Volt Stromversorgung ist das für die hier verwendeten Bauteile kein Problem. 

Danksagung

Bei Olav Kallhovd möchte ich mich für seine schöne Bibliothek bedanken. Die Bibliotheken von Adafruit haben mir bei der Ansteuerung des Displays geholfen. 

Die Waage auf dem Beitragsbild habe ich Gerhard Gellinger auf Pixabay zu verdanken. Den Arduino im Hintergrund habe ich schon mehrfach verwendet. Er stammt von Seven_au auf Pixabay

26 thoughts on “HX711 basierte Waage

  1. Hallo Wolfgang,

    die Erklärung ist echt super!
    Aufgrund der Größe meiner Stockwaage und weil ich mehr Pins brauche, bin auch auf einen ESP32 umgestiegen.
    Hier habe ich ein Problem und evtl. hast du mir eine Idee oder einen Tipp. Der ESP32 bietet einen Deep Sleep an. Dieser Startet das ganze System neu und somit auch die Waage immer bei Null. Auf der Wage stehen aber die Bienenkästen und wenn das System bei Null startet, messe ich kein Gewicht. Ich zerbreche mir seit Tagen den Kopf, wie ich die Wage beim Reset richtig starte, aber das System nicht Null ausgibt.
    Hast du evtl eine Idee oder mir einen Tip. Das Prblem hatte ich auch beim Wemos D1.

    Gruß

    Kay

    1. Hallo Kay, du möchtest also keine Tara beim Start. Die kannst du verhindern, indem du _tare auf false setzt.

      boolean _tare = false;
      LoadCell.start(stabilizingtime, _tare);

      Den Wert, den du damit bei deiner ersten Messung ermittelst (der dürfte sehr groß sein) musst du dann später von deinen Messwerten abziehen. Eine fixe Tara, sozusagen.

      Hoffe das hilft!

  2. Hallo,
    ich habe eine Frage.
    Ich möchte gerne 2 Wägezellen benutzen. Eine Anzeige habe ich, ihr kann ich sagen das bei einem bestimmten Ohmwert 0kg und bei einem höheren Ohmwert zb 10kg sind. Die Werte dazwischen werden dann selbst erzeugt. Brauche ich dafür überhaupt den HX711?

    Gruß Peter

    1. Hallo Peter, die Wägezelle ändert ihren Widerstand mit dem Gewicht. Das funktioniert über Dehnungsmessstreifen. Der Effekt, also die Widerstandsänderung ist allerdings äußerst gering. Der Widerstand wird über die abfallende Spannung gemessen. Die Spannungsänderung ist entsprechend auch sehr gering. Da kommt der HX711 ins Spiel, der eine gigantische Auflösung von 24 bit (= 16.777.216) hat. Da ist zum Beispiel der A/D-Wandler des Arduino mit seinen 10 bit ( = 1.023) sehr grob dagegen. Das reicht schlicht nicht aus. Wenn man einen Widerstandsmesser mit ausreichender Empfindlichkeit hat, kann man sich den Umweg über den HX711 im Prinzip sparen. VG, Wolfgang

  3. Hallo zusammen,
    Ich möchte mir eine Waage bauen für meine Bienen Völker um die Futter Vorrat zu ermitteln.
    Die Bienen stehen ca.5 bis 10 Entfernung von meinem Haus entfernt,
    Mene Frage ;
    Könnte mir jemand helfen eine Waage zu bauen und die daten per SMS übermittelt?
    Danke im voraus
    Micha

    1. Hallo Micha,

      ich kann dir keine Fertiglösung anbieten, aber zumindest vom Prinzip her ist das nicht schwer. Du brauchst außer den im Beitrag beschriebenen Teilen lediglich ein SMS-fähiges Modul wie z.B. das SIM800L und eine SIM Karte. Ich wollte immer mal einen Beitrag über solche Module machen, bin aber noch nicht dazu gekommen. Nachteil ist, dass man erst mal die SIM Karte braucht mit der ganzen Registrierung und Identifikation und dann laufende Kosten für die SMS hat. Ich würde deshalb andere Möglichkeiten in Betracht ziehen. Reicht dein W-Lan vielleicht bis zu den Bienen? Dann könntest du die Daten auf den Browser übermitteln, z.B. mit einem WEMOS Board. Das habe ich hier beschrieben. Oder du könntest die Daten über IFTTT (if this then that) als Benachrichtigung (also nicht SMS) auf das Handy schicken. Das habe ich hier beschrieben. Oder Übermittlung per 433 MHz Funk, dann hast du die Daten allerdings nicht auf dem Handy, sondern auf einem zweiten Arduino, aber könntest sie z.B. auf einem Display anzeigen.

  4. Hallo Wolfgang,
    das ist ein tolles Projekt und ich möchte mich bei Dir für die klasse Dokumentation bedanken.
    Ich möchte mehrere Waagen gleichzeitig über längere Zeiträume betreiben um Gewichtsveränderungen zu protokollieren und dann grafisch darzustellen. Hast Du eventuell einen Tip für mich wie ich den Wert regelmässig an eine LANAdresse:Port senden kann um ihn dann dort mit vorhandenenTools abzugreifen und in eine DB zu schreiben bzw. grafisch aufzubereiten?
    Danke für jede Hilfestellung.
    Liebe Grüsse,
    Rudi

    1. Hallo Rudi,

      vielen Dank für’s Feedback. In meinem Beitrag über ESP-01 Boards habe ich beschrieben, wie man Daten per W-LAN an einen Browser sendet. Allerdings würde ich als Board nicht den ESP-01 nehmen, da er nicht genügend Pins hat. Nimm ein ESP-12 Board wie z.B. das WEMOS Board. Alternativ kannst du auch einen Arduino mit W-LAN oder LAN Modul einsetzen.

      Damit hast du allerdings die Daten erst im Browser, aber noch nicht in einer Datei oder Datenbank. Mit HTML kommt man da nicht weit, sondern müsste php oder Java Script Lösungen einsetzen. Damit müsste ich mich selbst auch erstmal beschäftigen. Aber dazu gibt es bestimmt einiges im Netz.

      VG, Wolfgang

  5. Hallo, ich habe die Waage bereits zum Laufen gebracht, verzweifle aber gerade an einer „Kleinigkeit?“.
    Ich möchte, dass sich die Waage nach dem Einschalten nicht automatisch tariert. Hab schon mit der calibrationValue experimentiert, kam aber zu keiner Lösung. Können Sie mir da Weiterhelfen?

    MfG
    Simon Wagner

    1. Hallo Simon, das haben wohl auch andere vermisst. Und die gute Nachricht ist, dass der Autor der Bibliothek da etwas implementiert hat. Installiere – falls nicht schon geschehen – die aktuellste Version der Bibliothek und schau dort in den Read_1x_load_cell.ino Beispielsketch. Anscheinend ist die LoadCell.start() Funktion erweitert worden. Ändere einfach _tare von true in false und schon wird nicht mehr tariert:

      boolean _tare = true; //set this to false if you don’t want tare to be performed in the next step
      LoadCell.start(stabilizingtime, _tare);

      Ich muss das gelegentlich mal in meinem Beitrag ergänzen.

  6. Hallo,
    danke für den Artikel. Ich habe da eine Frage zum Anschluss von mehreren Wägezellen an einer Waage (Gewicht soll über 3-4 Wägezelle gemessen werden). Kann man das über ein HX711 machen oder pro Wägezelle ein HX711? Ich habe zwar Schaltungen gefunden, wo 4 Wägezelle an einen HX711 angeschlossen wurden, diese Wägezellen haben aber nur 3 Kabel. Ist auch möglich, diese Art von Wägezellen (mit 4 Adern) an einem HX711 anzuschließen?
    Schonmal Danke und Grüße,
    Stefan

    1. Hallo Stefan,

      interessante Frage. Eigentlich hat der HX711 nur zwei Kanäle und die Bibliothek benutzt nur den Kanal A. Kanal B soll eine zu geringe Verstärkung haben um gut messen zu können. In der Bibliothek findet man einen Beispielsketch, der zeigt, wie man zwei (oder mehr) HX711 Module ausliest. Das würde bedeuten, dass man nur eine Wägezelle pro HX711 Modul auslesen kann. Kann es seine, dass dort wo mehrere Zellen verwendet werden, diese zusammengeschlossen sind? So etwas kann man machen, wenn man z.B. eine 200 kg Waage bauen will und die auf 4 x 50 kg Zellen aufgebaut ist. Dann liest du einen Gesamtwert aus. Ein individuelles Auslesen ginge nicht nach meinem Verständnis. Vielleicht kannst du mir mal den Link zusenden für das Beispiel, dass du gefunden hast.

      VG, Wolfgang

      1. Hallo Wolfgang,
        genau sowas ähnliches wie dein Beispiel (4x50kg > 200kg Waage) hatte ich vor.
        Ein Beispiel habe ich hier:
        https://youtu.be/LIuf2egMioA?t=40 (Schaltbild bei Sekunde 40)
        und bei der ct 2/2018 (leider hinter einer Paywall):
        https://www.heise.de/select/ct/2018/2/1515450954216728
        Bei beiden werden vier (dreiadrige) Wägezelle an ein HX711 angeschlossen und ausgelesen. Ein Beispiel mit vieradrigen habe ich leider nicht gefunden. Das Beispielsketch mit mit zwei HX711 Module habe ich auch gesehen. Ich hatte nur gehofft, dass es eine elegantere Lösung als vier HX711 gibt, weil dann das Kalibrieren etwas aufwändiger ist.

        Grüße, Stefan

  7. Hallo Wolfgang
    Dank Deinem Blog habe ich es geschafft 2 Waagen zu bauen, als Basis nutzte ich jedoch einen Wemos D1 mini. Eine Waage mit einer 20Kg Zelle und die Zweite mit 4 x 20Kg Zellen, das läuft mit dem CalibSketch und dem Sketch aus dem Abschnitt Regelbetrieb, tiptop.
    Ich schaffe es jedoch nicht dem Sketch mit TFT und Tara Button zum laufen zu bringen. Der D1Mini blinkt ununterbrochen nach dem Upload, das Display bleibt dunkel und im seriellen Monitor sehe ich nur wirre Zeichen.
    Hast Du mir ein Tipp woran das liegen könnte, respektive wie ich Deinen „TFT Tara Button Sketch“ auf einem D1 Mini zum laufen bringe? Als TFT habe ich übrigens SSD1306 und SH1105 zur Verfügung.
    Mit den Besten Grüssen
    Fredi

    1. Hallo Fredi,

      Fehlersuche aus der Ferne ist noch schwieriger als so schon. Ich würde jetzt so vorgehen:
      1) Prüfen, ob der Pull-Down Widerstand am Taster richtig verbunden ist
      2) wegen der wirren Zeichen: ist die Baudrate richtig eingestellt
      3) Generell alle Kabel überprüfen und evtl. mal austauschen (ich hatte mal ein kaputtes Steckbrückenkabel und habe mir einen Wolf gesucht)
      4) Das TFT Display mal entfernen – geht es jetzt mit dem seriellen Monitor?
      5) Das TFT Display separat versuchen „zum Laufen“ zu bringen.
      6) Ist die Displaygröße bei der Initialisierung richtig gewählt? display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

      Mehr fällt mir erstmal nicht ein. Wenn du das Problem identifizieren kannst, wäre es schön, wenn du das teilen könntest. Viel Erfolg!

      VG, Wolfgang

      1. Hallo Wolfgang
        Besten Dank für Deinen Input, werde mich der Sache annehmen und hier berichten. Vielen Dank für Deine Unterstützung.
        Fredi

  8. Hallo Wolfgang!
    Herzlichen Dank für die Zusammenstellung und das Bereitstellen der Informationen und Sketches zum HX711, dies hier hat erheblich zu meinem Verständnis der elektronischen Waage geholfen!

    Ich habe das ganze mit einem Arduino Nano ausprobiert, wenn ich Deinen Sketch mit Display und Tarafunktion verwende, sind Messungen zwar möglich, aber werden dauernd durch „Wait“ und einer (ungewollten) Tarierung der Waage unterbrochen, irgendeine Fehlerschleife muss vorliegen. Zuerst hatte ich einen defekten Taster in Verdacht, aber dieser ist in Ordnung,auch so erkenne ich jetzt keinen offensichtlichen Fehler in meiner Schaltung. Habe ich da vielleicht etwas übersehen?

    Herzliche Grüße,
    Marcel

    1. Wenn die Waage immer wieder tariert, wird anscheinend immer wieder ungewollt ein Interrupt ausgelöst. Da hätte ich auch als erstes den Taster im Verdacht gehabt. Da er es nicht ist, würde ich als nächstes den Pull-Down Widerstand überprüfen. Ist der richtig an GND angeschlossen? Wenn es das auch nicht ist, wird es schwieriger. Irgendwo her muss das High Signal ja kommen, das den Interrupt auslöst.

      Oder du drehst die Logik dann mal um – Interrupt wird bei „LOW“ ausgelöst:
      pinMode(interruptPin, INPUT) –> pinMode(interruptPin, INPUT_PULLUP) und
      attachInterrupt(digitalPinToInterrupt(interruptPin), taraEvent, RISING); –> attachInterrupt(digitalPinToInterrupt(interruptPin), taraEvent, FALLING);
      und natürlich den Pull-Down Widerstand entfernen und den Taster an GND anstelle VCC.

      1. Danke für den Tipp!
        Da lag dann auch der Fehler, der Pull-down-Widerstand lief ins Leere… Jetzt geht alles wie gedacht! Vielen Dank!

  9. Hallo und danke für den tollen Beitrag.

    Auf der Suche nach einer Möglichkeit Meßdaten, hier Gewicht zu erfassen, kam ich auf deine Seite.

    Eine Frage hierzu:
    Ich möchte Milligramm bis max. 200 Gramm zu erfassen, ist dieses hiermit möglich?

    Lieben Gruß

    1. Hallo, ich selbst habe nicht im Milligramm Bereich getestet, aber ich habe bei den Kundenfragen bei Amazon einen Hinweis für die 1kg Version gefunden:

      Welche empfindlichkeit hat dieser 1kg sensor? ab welchem gewicht misst er und wie genau? max. 1kg, richtig?
      Antwort:Ich habe damit el. Bauteile gewogen welche unter 1g Gewicht hatten. Referenzgewichte von 0.5g bis 50g zeigten bei 10 Versuchen immer denn richtigen, gleichen Wert.
      Von W. R. am 10. September 2019
      Der Sensor hat eine Empfindlichkeit von 1mV/V. Habe damit ein Wägesystem mit einer Auflösung von 10 mg aufgebaut. Die Linearität ist sehr gut.
      Von 10mg bis 1 kg keine Abweichung.
      Von Wolfgang… am 11. September 2019

      Zumindest 10 mg Auflösung scheinen zu funktionieren. Aber nochmal, ich habe es selbst nicht ausprobiert (das war ein anderer Wolfgang!).

  10. Danke für den tollen Beitrag!
    Das wollte ich schon lange mal ausprobieren. Die Teile liegen schon ewig bei mir rum.
    Bin über den stabilen Wert (ohne Schirmung) erstaunt.
    Viele Grüße aus dem Süden

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.