Feather ESP32 with HX711 and Bluetooth

Please tell us which board you are using.
For CircuitPython issues, ask in the Adafruit CircuitPython forum.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
pluesss
 
Posts: 32
Joined: Fri Apr 15, 2011 10:45 am

Feather ESP32 with HX711 and Bluetooth

Post by pluesss »

Hi,

I have a problem. I'm trying to use a Feather ESP32 with 8 HX711 and Bluetooth Classic.
For the HX711 I use the HX711_ADC library, for Bluetooth ther SerialBT library.

My setup seems to work as long as I'm only using Serial Output. As soon as a Bluetooth device (e. g. my phone) connects I get weird jumps in my data(see image)
I connected all SCK Pins from Pin 12 to SDA Pin
and all the DT Pins from A4 to Pin 21

Do you have an idea what could be causing this problem?
If you need more images or the complete code, let me know.

Thank you.
Attachments
image-1.png
image-1.png (138.07 KiB) Viewed 395 times

User avatar
adafruit_support_mike
 
Posts: 67485
Joined: Thu Feb 11, 2010 2:51 pm

Re: Feather ESP32 with HX711 and Bluetooth

Post by adafruit_support_mike »

Post a photo showing your hardware and connections and we'll take a look. 800x600 images usually work best.

Also post your code between CODE tags please.

User avatar
pluesss
 
Posts: 32
Joined: Fri Apr 15, 2011 10:45 am

Re: Feather ESP32 with HX711 and Bluetooth

Post by pluesss »

Hi Mike,

Thank you for your reply.
Here is my code:

Code: Select all

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

#include "BluetoothSerial.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

BluetoothSerial SerialBT;

//pins:
const int HX711_dout_1 = 18; //mcu > HX711 no 1 dout pin 18
const int HX711_sck_1  = 15; //mcu > HX711 no 1 sck pin 15

const int HX711_dout_2 = 5; //mcu > HX711 no 2 dout pin
const int HX711_sck_2  = 33; //mcu > HX711 no 2 sck pin

const int HX711_dout_3 = 4; //mcu > HX711 no 2 dout pin
const int HX711_sck_3  = 27; //mcu > HX711 no 2 sck pin

const int HX711_dout_4 = 36; //mcu > HX711 no 2 dout pin
const int HX711_sck_4  = 12; //mcu > HX711 no 2 sck pin

const int HX711_dout_5 = 21; //mcu > HX711 no 2 dout pin
const int HX711_sck_5  = 23; //mcu > HX711 no 2 sck pin

const int HX711_dout_6 = 17; //mcu > HX711 no 2 dout pin
const int HX711_sck_6  = 22; //mcu > HX711 no 2 sck pin

const int HX711_dout_7 = 16; //mcu > HX711 no 2 dout pin
const int HX711_sck_7  = 14; //mcu > HX711 no 2 sck pin

const int HX711_dout_8 = 19; //mcu > HX711 no 2 dout pin
const int HX711_sck_8  = 32; //mcu > HX711 no 2 sck pin

//HX711 constructor (dout pin, sck pin)
HX711_ADC LoadCell_1(HX711_dout_1, HX711_sck_1); //HX711 1
HX711_ADC LoadCell_2(HX711_dout_2, HX711_sck_2); //HX711 2
HX711_ADC LoadCell_3(HX711_dout_3, HX711_sck_3); //HX711 3
HX711_ADC LoadCell_4(HX711_dout_4, HX711_sck_4); //HX711 4
HX711_ADC LoadCell_5(HX711_dout_5, HX711_sck_5); //HX711 5
HX711_ADC LoadCell_6(HX711_dout_6, HX711_sck_6); //HX711 6
HX711_ADC LoadCell_7(HX711_dout_7, HX711_sck_7); //HX711 7
HX711_ADC LoadCell_8(HX711_dout_8, HX711_sck_8); //HX711 8

const int calVal_eepromAdress_1 = 0; // eeprom adress for calibration value load cell 1 (4 bytes)
const int calVal_eepromAdress_2 = 4; // eeprom adress for calibration value load cell 2 (4 bytes)
const int calVal_eepromAdress_3 = 8; // eeprom adress for calibration value load cell 3 (4 bytes)
const int calVal_eepromAdress_4 = 12; // eeprom adress for calibration value load cell 4 (4 bytes)
const int calVal_eepromAdress_5 = 16; // eeprom adress for calibration value load cell 5 (4 bytes)
const int calVal_eepromAdress_6 = 20; // eeprom adress for calibration value load cell 6 (4 bytes)
const int calVal_eepromAdress_7 = 24; // eeprom adress for calibration value load cell 7 (4 bytes)
const int calVal_eepromAdress_8 = 28; // eeprom adress for calibration value load cell 8 (4 bytes)
long t;

void setup() {
  pinMode(13,OUTPUT);
  digitalWrite(13,HIGH);

  SerialBT.begin("Sensor");
  
  Serial.begin(115200); delay(10);
  Serial.println();
  Serial.println("Starting...");

  float calibrationValue_1; // calibration value load cell 1
  float calibrationValue_2; // calibration value load cell 2
  float calibrationValue_3; // calibration value load cell 3
  float calibrationValue_4; // calibration value load cell 4
  float calibrationValue_5; // calibration value load cell 5
  float calibrationValue_6; // calibration value load cell 6
  float calibrationValue_7; // calibration value load cell 7
  float calibrationValue_8; // calibration value load cell 8


  calibrationValue_1 = 15047.51815; // 
  calibrationValue_2 =  15113.95977; // 
  calibrationValue_3 = 15000.34862; // 
  calibrationValue_4 = 15164.6648; // 
  calibrationValue_5 = 15092.51094; //
  calibrationValue_6 = 15296.13; // 
  calibrationValue_7 = 14981.29179; // 
  calibrationValue_8 = 14975.02278; // 
  
#if defined(ESP8266) || defined(ESP32)
  //EEPROM.begin(512); // uncomment this if you use ESP8266 and want to fetch the value from eeprom
#endif
  //EEPROM.get(calVal_eepromAdress_1, calibrationValue_1); // uncomment this if you want to fetch the value from eeprom
  //EEPROM.get(calVal_eepromAdress_2, calibrationValue_2); // uncomment this if you want to fetch the value from eeprom

  LoadCell_1.begin();
  LoadCell_2.begin();
  LoadCell_3.begin();
  LoadCell_4.begin();
  LoadCell_5.begin();
  LoadCell_6.begin();
  LoadCell_7.begin();
  LoadCell_8.begin();

  long stabilizingtime = 2000; // tare preciscion 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
  
  byte loadcell_1_rdy = 0;
  byte loadcell_2_rdy = 0;
  byte loadcell_3_rdy = 0;
  byte loadcell_4_rdy = 0;
  byte loadcell_5_rdy = 0;
  byte loadcell_6_rdy = 0;
  byte loadcell_7_rdy = 0;
  byte loadcell_8_rdy = 0;
  
  while ((loadcell_1_rdy ) < 1) { //run startup, stabilization and tare, both modules simultaniously + loadcell_2_rdy + loadcell_3_rdy + loadcell_4_rdy + loadcell_5_rdy + loadcell_6_rdy + loadcell_7_rdy + loadcell_8_rdy
    if (!loadcell_1_rdy) loadcell_1_rdy = LoadCell_1.startMultiple(stabilizingtime, _tare);
    if (!loadcell_2_rdy) loadcell_2_rdy = LoadCell_2.startMultiple(stabilizingtime, _tare);
    if (!loadcell_3_rdy) loadcell_3_rdy = LoadCell_3.startMultiple(stabilizingtime, _tare);
    if (!loadcell_4_rdy) loadcell_4_rdy = LoadCell_4.startMultiple(stabilizingtime, _tare);
    if (!loadcell_5_rdy) loadcell_5_rdy = LoadCell_5.startMultiple(stabilizingtime, _tare);
    if (!loadcell_6_rdy) loadcell_6_rdy = LoadCell_6.startMultiple(stabilizingtime, _tare);
    if (!loadcell_7_rdy) loadcell_7_rdy = LoadCell_7.startMultiple(stabilizingtime, _tare);
    if (!loadcell_8_rdy) loadcell_8_rdy = LoadCell_8.startMultiple(stabilizingtime, _tare);
  }
  if (LoadCell_1.getTareTimeoutFlag()) {
    Serial.println("Timeout, check MCU>HX711 no.1 wiring and pin designations");
  }
  if (LoadCell_2.getTareTimeoutFlag()) {
    Serial.println("Timeout, check MCU>HX711 no.2 wiring and pin designations");
  }
  if (LoadCell_3.getTareTimeoutFlag()) {
    Serial.println("Timeout, check MCU>HX711 no.3 wiring and pin designations");
  }
  if (LoadCell_4.getTareTimeoutFlag()) {
    Serial.println("Timeout, check MCU>HX711 no.4 wiring and pin designations");
  }
  if (LoadCell_5.getTareTimeoutFlag()) {
    Serial.println("Timeout, check MCU>HX711 no.5 wiring and pin designations");
  }
  if (LoadCell_6.getTareTimeoutFlag()) {
    Serial.println("Timeout, check MCU>HX711 no.6 wiring and pin designations");
  }
  if (LoadCell_7.getTareTimeoutFlag()) {
    Serial.println("Timeout, check MCU>HX711 no.7 wiring and pin designations");
  }
  if (LoadCell_8.getTareTimeoutFlag()) {
    Serial.println("Timeout, check MCU>HX711 no.8 wiring and pin designations");
  }
  LoadCell_1.setCalFactor(calibrationValue_1); // user set calibration value (float)
  LoadCell_2.setCalFactor(calibrationValue_2); // user set calibration value (float)
  LoadCell_3.setCalFactor(calibrationValue_3); // user set calibration value (float)
  LoadCell_4.setCalFactor(calibrationValue_4); // user set calibration value (float)
  LoadCell_5.setCalFactor(calibrationValue_5); // user set calibration value (float)
  LoadCell_6.setCalFactor(calibrationValue_6); // user set calibration value (float)
  LoadCell_7.setCalFactor(calibrationValue_7); // user set calibration value (float)
  LoadCell_8.setCalFactor(calibrationValue_8); // user set calibration value (float)
}

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

  // check for new data/start next conversion:
  if (LoadCell_1.update()) newDataReady = true;
  LoadCell_2.update();
  LoadCell_3.update();
  LoadCell_4.update();
  LoadCell_5.update();
  LoadCell_6.update();
  LoadCell_7.update();
  LoadCell_8.update();
  

  //get smoothed value from data set
  if ((newDataReady)) {
    if (millis() > t + serialPrintInterval) {

      float LC1 = 100*float(LoadCell_1.getData());
      float LC2 = 100*float(LoadCell_2.getData());
      float LC3 = 100*float(LoadCell_3.getData());
      float LC4 = 100*float(LoadCell_4.getData());
      float LC5 = 100*float(LoadCell_5.getData());
      float LC8 = 100*float(LoadCell_6.getData());  
      float LC7 = 100*float(LoadCell_7.getData());
      float LC6 = 100*float(LoadCell_8.getData());
      
      String sendBT="";
      sendBT += String(LC1);
      sendBT += ", ";
      sendBT += String(LC2);
      sendBT += ", ";
      sendBT += String(LC3);
      sendBT += ", ";
      sendBT += String(LC4);
      sendBT += ", ";
      sendBT += String(LC5);
      sendBT += ", ";
      sendBT += String(LC6);
      sendBT += ", ";
      sendBT += String(LC7);
      sendBT += ", ";
      sendBT += String(LC8);
      
SerialBT.println(sendBT);
Serial.println(sendBT);
    
      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_1.tareNoDelay();
      LoadCell_2.tareNoDelay();
      LoadCell_3.tareNoDelay();
      LoadCell_4.tareNoDelay();
      LoadCell_5.tareNoDelay();
      LoadCell_6.tareNoDelay();
      LoadCell_7.tareNoDelay();
      LoadCell_8.tareNoDelay();
    }
  }

  //check if last tare operation is complete
  if (LoadCell_1.getTareStatus() == true) {
    Serial.println("Tare load cell 1 complete");
  }
  if (LoadCell_2.getTareStatus() == true) {
    Serial.println("Tare load cell 2 complete");
  }
  if (LoadCell_3.getTareStatus() == true) {
    Serial.println("Tare load cell 3 complete");
  }
  if (LoadCell_4.getTareStatus() == true) {
    Serial.println("Tare load cell 4 complete");
  }
  if (LoadCell_5.getTareStatus() == true) {
    Serial.println("Tare load cell 5 complete");
  }
  if (LoadCell_6.getTareStatus() == true) {
    Serial.println("Tare load cell 6 complete");
  }
  if (LoadCell_7.getTareStatus() == true) {
    Serial.println("Tare load cell 7 complete");
  }
  if (LoadCell_8.getTareStatus() == true) {
    Serial.println("Tare load cell 8 complete");
  }
}
Attached two photos of the sensor. The distance between the Bottom and Top HX711 is ~20cm. They are connected through a cable in the middle of the whole thing.
Attachments
i01_HX711.png
i01_HX711.png (857.89 KiB) Viewed 377 times
i01_BottomView.jpg
i01_BottomView.jpg (289.9 KiB) Viewed 378 times
i01_TopView.jpg
i01_TopView.jpg (303.24 KiB) Viewed 378 times

User avatar
adafruit_support_mike
 
Posts: 67485
Joined: Thu Feb 11, 2010 2:51 pm

Re: Feather ESP32 with HX711 and Bluetooth

Post by adafruit_support_mike »

You're probably seeing the effects of EMF pickup. Every wire is an antenna, and the photo above shows a lot of loose wiring around the ESP32.

The first and best solution to EMF problems is distance. The strength of a radiated field drops off in proportion to the square of the distance, so moving the source twice as far away removes 3/4 of the unwanted signal.

Sometimes adding distance is impossible though, so the next option is cancellation. If you run a signal through one strand of twisted pair wire, and run its connection to GND through the other strand, each half of the signal will be exposed to nearly the same EMF. The current in the wires flows in opposite directions though, so the induced signal cancels itself.

The third option is shielding.

If you put a block of metal in an electric field, electrons in the metal will move toward the positive side of the field. There's nothing in the metal to stop them until they reach the surface, so that's where they end up. The spaces the electrons left (called 'holes') move toward the negative side of the field, and end up on that surface.

The layers of electrons and holes on opposite sides of the block create their own electric field, pointing the opposite direction from the external field. As long as that field is weaker than the external field, electrons in the center of the metal will still be pulled toward the positive side of the external field. Things only stop when the field created by the layers of electrons and holes on the surface exactly cancels the external field.

If you carve out an empty space inside the block, nothing inside that space will feel either electric field. The metal shields the space inside it from external electric fields.

The same thing happens to voltage and current induced by an external magnetic field, so the conductive surface shields anything inside it from external electromagnetic fields. The general arrangement is called a Faraday Cage.

That's why radio devices like the ESP32 are covered by a metal can.. it's a Faraday cage that keeps EMF radiating from the components and traces inside the can from getting out. The only signal that gets through the can is the one connected to the antenna.

Coaxial cable has a center conductor and a flexible outer shield that acts like a Faraday cage. There are also various kinds of shielded cable.. a good USB-C cable will have multiple shields around pairs of data lines.

Making sure a shield works usually takes an oscilloscope, and usually requires some tweaking, so it tends to be a last resort.

User avatar
pluesss
 
Posts: 32
Joined: Fri Apr 15, 2011 10:45 am

Re: Feather ESP32 with HX711 and Bluetooth

Post by pluesss »

Hi Mike,

Thank you for your very detailed answer.
However, before ordering new cables and starting to solder everything again:
Wouldn't these problems generate a more "periodic" signal than I get?
I cannot detect any pattern in these jumps. And it seems to be random on all channels.
Also the jumps always seems to be some sort of a "level shift/ offset" but continues there nicely and than jumps back to the normal level...
I also tried to add more / less "disturbance" by holding it closer or further away from other devices. But that doesn't change anything at all.

What do you think?

User avatar
adafruit_support_mike
 
Posts: 67485
Joined: Thu Feb 11, 2010 2:51 pm

Re: Feather ESP32 with HX711 and Bluetooth

Post by adafruit_support_mike »

Look for a correlation between the spikes and anything else happening in the circuit. So far the only know correlation is proximity to the radio, and the most likely suspect for interference from a radio is EMF.

User avatar
pluesss
 
Posts: 32
Joined: Fri Apr 15, 2011 10:45 am

Re: Feather ESP32 with HX711 and Bluetooth

Post by pluesss »

Just if somebody else has the same problem....

After a lot of testing and soldering, I finally found the problem....

I just had to upgrade the ESP32 library in the Arduino IDE. the BluetoothSerial got an update which solved the problem as it seems...

Thank you for your help.

User avatar
adafruit_support_mike
 
Posts: 67485
Joined: Thu Feb 11, 2010 2:51 pm

Re: Feather ESP32 with HX711 and Bluetooth

Post by adafruit_support_mike »

Hmm.. glad to hear you found the problem. Happy hacking!

Locked
Please be positive and constructive with your questions and comments.

Return to “Feather - Adafruit's lightweight platform”