HX711 together with I2C devices on same pins

I design a project based on a M5-StickC that read a sensor plugged on the 8 pins port.
I wish to use within the same sketch either a scale with the HX711 library or other sensors like pressure, temperature, etc using the I2C interface. For reason of simplicity for the user,
HX711 and I2C must use the same 4 pins of the port (GPIO 21, GPIO25, Grnd, +5V).
For the time being I didn't succeed to have both types working, with a sketch that first search for the i2C adress of a device and if unsuccessful assumes it is the HX711 interface.
Is there a hardware incompatibility ? If no i2c adress is found, I tried to use Wire.end() before
scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN); etc. , but get the message "class 'TwoWire' has no member named 'end'.
Thanks for help.

Welcome to the forum. We have a set of rules / conventions here to make helping you easer.

Basically words by themselves are of little use, we need to see code and schematics, along with links to unusual stuff. In your case the M5-StickC is a complete mistry to me and I suspect others.

So you might want to look at this How to get the best from this from this Forum before you proceed any further.

The ESP32 has a "end()" here. And it really does end the I2C bus and releases the pins.
So what is going on with your M5-StickC ? Does it not use the newest ESP32 software ?

The I2C bus is a open-drain bus, and the HX711 has normal digital signals. If you apply HX711 signals to a I2C device, then there could be a shortcut on the lines.
The HX711 module is for 5V, but the ESP32 is a 3.3V processor. You can modify the HX711 module for 3.3V.
There are probably a number of other things that can go wrong.

@Grumpy_Mike : OK. Here is the present state of the code. Note that many comments are in french... Sorry. I may produce a full english version.

/************************************************
 *  Auteur : D. Rouan  26/03/2021
 *   Gestion par un composant ESP32 M5Atom 
 *   de différents types de capteurs connectables à la carte
 *   pour mise en forme et envoi en bluetooth BLE 
 *   en particulier vers l'application FIZZIQ  
 *   (https://www.fizziq.org/arduino)
 *   Les capteurs envisagés et ayant été testés sont :
 *   - sonde de température de type CTN
 *   - hygromètre type DHT 11
 *   - balance basée sur ampli différentiel HX711
 *   - capteur de distance infrarouge type Sharp 2Y0A21
 *   - ... 
 *   
 *   Tous les capteurs sont connecté sur les pins 21 et 25 : soit en I2C, soit en twoWire (HX711 par ex)
 *   
 *   Suivant le capteur, un traitement est effectué avant d'envoyer une chaîne de
 *   caractères capteur:valeur,  comme "temperature:18.2", par BLE
 *   testé le 15/11/22 sur pression et température
 ***********************************************/

#include <M5StickCPlus.h>
//#include <M5Atom.h>
#include <AceWire.h>
//#include <Wire.h>
using ace_wire::TwoWireInterface;
using ace_wire::SimpleWireInterface;

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
#include <BMP180I2C.h>
#include "HX711.h"
/////////////////////////////////////////////////////////////////
#define WIRE_HAS_END 1
#define BUTTON_CHRGE  35
#define BUTTON_PIN0  0
#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" // Noter que le ESP32 est peer 
#define CHARACTERISTIC_UUID_TX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"

#define DELAY 5000 
#define I2C_ADDRESS 0x77 // pression

HX711 scale;
BMP180I2C bmp180(I2C_ADDRESS);
BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
const int LOADCELL_DOUT_PIN = 21;
const int LOADCELL_SCK_PIN = 25;
bool deviceConnected = false;
bool oldDeviceConnected = false;
String captname = "inconnu" ;
static char outstr[15];
int I2CAdress = 0 ; 
float id ; 
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string rxValue = pCharacteristic->getValue();

      if (rxValue.length() > 0) {
        Serial.println("*********");
        Serial.print("Received Value: ");
        for (int i = 0; i < rxValue.length(); i++)
          Serial.print(rxValue[i]);

        Serial.println();
        Serial.println("*********");
      }
    }
};

unsigned long lastTime = 0;
unsigned long timerDelay = 10000;
int capt = 0 ; // index capteur

// Accueil

int ID_capteur() {
  Serial.println("Recherche capteur sur I2C");
  int address;
  int error;
  for (address = 1; address < 127; address++) {
        Wire.beginTransmission(
            address);  // Data transmission to the specified device address
                       // starts.   
        error = Wire.endTransmission(); 
        if (error == 0) {
            Serial.print(address, HEX);
            Serial.print(" ");
            I2CAdress = address ;
            break;

        } else
            Serial.print(".");

        delay(50);
  }

  if (I2CAdress == 0)  {
    //Wire.end();
    //Wire.begin(23, 33);

    delay(100);
    scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
    Serial.println();
    Serial.println(" Capteur I2C inconnu recherche 2 wire"); 
    if (scale.is_ready()) {
      scale.set_scale(); 
      Serial.println("Balance trouvée");   
      Serial.println("Tare... remove any weights from the scale.");
      delay(5000);
      scale.tare();
      Serial.println("Tare done...");
      capt = 0 ;
      captname ="poids" ;
    }
    else Serial.println("HX711 not found");
  }  
  Serial.println();
  return I2CAdress; 
}

void setup() {  
  M5.begin() ;
    // ports série de debug 
  Serial.begin(115200);
  
  delay(2000);
  scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
  Wire.begin(21, 25);

 // Create the BLE Server  
  BLEDevice::init("Arduino Kaptor");

  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
                    CHARACTERISTIC_UUID_TX,
                    BLECharacteristic::PROPERTY_NOTIFY
                  );
                      
  pCharacteristic->addDescriptor(new BLE2902());

  BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
                       CHARACTERISTIC_UUID_RX,
                      BLECharacteristic::PROPERTY_WRITE
                    );

  pRxCharacteristic->setCallbacks(new MyCallbacks());

  // Start the service
  pService->start();
  // Start advertising
  pServer->getAdvertising()->start();
  Serial.println("Waiting a client connection to notify...");
  
  // 
  capt =  ID_capteur(); // quel capteur ?
  Serial.println(capt, HEX);
  switch (capt){
    case 8:
      captname = "temperature" ;
      break;
    case 119 : //0x77:
      captname = "pression"  ;
      if (!bmp180.begin())
      {
        Serial.println("begin() failed. check your BMP180 Interface and I2C Address.");
        while (1);
      }

  //reset sensor to default parameters.
      bmp180.resetToDefaults();

  //enable ultra high resolution mode for pressure measurements
      bmp180.setSamplingMode(BMP180MI::MODE_UHR);
      break;
    case 0x66:
      captname = "toto" ;
      break;
    case 0x55:
      captname = "titi" ; 
      break;
    case 0x0:
      captname = "poids" ;
      break;
    default:
      captname = "inconnu"; 
       
  }
  Serial.println("**** capteur : "+captname);
}

////////////////////////// LOOP 
void loop() {
  int i;
  String   affich ;
  float x;

  switch (capt){
    case (8):
      Wire.requestFrom(capt,2);
      while(Wire.available())
      {
        char c = Wire.read();
        int xl = int(c)  ;
        if (xl < 0) xl += 256 ;
        Serial.println("I2C Low : ");
        Serial.print(xl);
        //delay(100);
        c = Wire.read();
        int xh = int(c) ;
        Serial.println("I2C high : ");
        Serial.print(xh); 
        x = float(xl + xh*256) ;   ;
      }
       break;
    
    case (0x77) :
      if (!bmp180.measureTemperature())
      {
        Serial.println("could not start temperature measurement, is a measurement already running?");
        return;  
      }
      do
      {
        delay(100);
      } while (!bmp180.hasValue());
     
      Serial.print("Temperature BMP180: "); 
      Serial.print(bmp180.getTemperature()); 
      Serial.println(" degC");
    
      //start a pressure measurement. pressure measurements depend on temperature measurement, you should only start a pressure 
      //measurement immediately after a temperature measurement. 
      if (!bmp180.measurePressure())
      {
        Serial.println("could not start perssure measurement, is a measurement already running?");
        return;
      }
    
      //wait for the measurement to finish. proceed as soon as hasValue() returned true. 
      do
      {
        delay(100);
      } while (!bmp180.hasValue());
    
      Serial.print("Pressure: "); 
      x = bmp180.getPressure() ;
      Serial.print(x);
      Serial.println(" Pa");
      break ;
    case 0x0 : 
      if (scale.is_ready()) {
        scale.set_scale();  
        long reading = -scale.get_units(10)/1000; 
        Serial.print("Poids : ");
        Serial.println(reading);
        x = reading ;
      }  
      else Serial.println("scale not ready");
      break;
    default :
      break;  
    }   
  dtostrf(x,7, 2, outstr);
  affich  = captname + ":"  + outstr ;

   // affichage moniteur     
    Serial.println(affich);      
  // envoi BLE 
    if (deviceConnected) {        
       uint8_t arr[20]  ;
       for( i =0; i< affich.length(); i++){
         arr[i] = affich[i] ;
       }
       pCharacteristic->setValue(arr, affich.length());
       pCharacteristic->notify(); 
  }

  // disconnecting
  if (!deviceConnected && oldDeviceConnected) {
        delay(500); // give the bluetooth stack the chance to get things ready
        pServer->startAdvertising(); // restart advertising
        Serial.println("disconnected : start advertising");
        oldDeviceConnected = deviceConnected;
   }
    // connecting
    if (deviceConnected && !oldDeviceConnected) {
    // do stuff here on connecting
        Serial.println("reconnected ");
        oldDeviceConnected = deviceConnected;
    }
    delay(DELAY); // attend XX secondes avant la prochaine mesure
  }

Thanks Koepel for the clue. In fact I used both a M5-StickC that is bricked now (the shortcut on the lines that you mention ?) and a M5-Atom (a simpler version with no screen). I updated as you recommand the ESP32 library (versio 2.05) through the board manager but then I got in severe troubles probably because this version require OSX 11+ and I'm on 10.13.6. No more compilation was possible. I then get back to ESP32 1.05 and recovered the previous status with Wire.end not recognized... The trick I found is to first look for the HX711 and if
unsuccessful to launch Wire.begin and search for an I2c adress.
Anyway thanks for the answer.

That is not a happy Christmas story :christmas_tree:

Are you stuck at that OSX version ? The ESP32 has got many improvements and fixes for the Arduino compatible libraries in the last years. If you run into new problems and ask on this forum, then you might be on your own.

The ESP32 has boot firmware that is not easily bricked. Perhaps there is a way to recover it. Don't try a full sketch, but a sketch that blinks or led or so.

Testing the HX711 before the I2C might not be safe. If a I2C Slave sees its own I2C address in the pattern of the pulses, then it pulls SDA low. That causes a shortcut on the SDA line. However, the more I look into it, the more I'm convinced that such a pattern will not occur as long as not both devices are connected :thinking:

I'm missing a clear separation of the code with a single variable. You seem to try to squeeze multiple functionality into a single variable.
What about a variable "mode" and a big switch-case statement in the loop ?

enum 
{ 
  NONE,
  I2C, 
  HX711 
} mode; 

I tried something in the Wokwi simulator. But somehow, it does not work: CombiningPins.ino - Wokwi ESP32, STM32, Arduino Simulator

I'm using the default pins for I2C:

pin D21 = SDA = DT
pin D22 = SCL = SCK

If I remove the DT and SCK to the HX711 module, then the I2C device can be seen. However, I can not see the HX711 with the library "HX711 Arduino Library" from https://github.com/bogde/HX711.
Wokwi does not have a BMP180, so I used a MPU-6050.

There is a "Logic Analyzer" in the circuit, it will try to store data on your computer.
If you want to see the data, install PulseView: https://sigrok.org/wiki/Downloads (you don't need sigrok, only PulseView). PulseView has a decoder for I2C.

That's the point: the idea is to plug ONE sensor at a time, so there should not be a mess and unproper levels on devices.
I'll have a look to your various advices.
Thanks again Koepel

The Stick-C+ does not even accept any load with this message :
Connecting......................................____
A fatal error occurred: Failed to connect to ESP32: Invalid head of packet (0x80)
:face_with_raised_eyebrow:

Is there a "Load" button ? This might be interesting: https://github.com/espressif/arduino-esp32/issues/1253

You were right Koepel: the ESP32 was not dead but in singular state with no display and just writing the same message on the serial port but ignoring any input.
Thanks to Tuupola Bricked M5StickC after bad AXP192 config? | M5Stack Community I have been able yesterday to reload the firmware after many attempts (G0 grounded and reset pressed randomly while launching the load command).
Happy to be back on track...
Thanks for advices.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.