Hey Rudi,
I took a dive into this, and discovered the fix is simple, but in the interests of education (give a man a fish / teach a man to fish) I figured Iāll post up my whole adventure.
Hopefully it will help you better understand how to problem solve these issues, and also seeing some of the rabbit holes I went down based on assumptions I made to fill in information your posts didnāt provide will help you to write good questions on a forum (which can be a bit of an art in itself).
Iāve never used either of these devices before. I first noticed you were using A4 and A5 for your HX711, so I assumed both the HX711 and LCD had I2C interfaces.
To start debugging this, letās open up the waveshare lcd header (.h) and .cpp files and take a look at what happens when you call lcd.init()
void Waveshare_LCD1602_RGB::init()
{
Wire.begin();
_showfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
begin(_cols, _rows);
}
Thereās really not much in the lcd.init() function. You can see all it really does is initialises the i2C interface. Ok, maybe when the HX711 initialises I2C it passes some special arguments (say for clock frequency or something). I know LCDs are often quite timing sensitive.
And assuming itās the standard Arduino HX711 library: HX711 Arduino Library - Arduino Reference
Itās a little more complex:
void HX711::begin(byte dout, byte pd_sck, byte gain) {
PD_SCK = pd_sck;
DOUT = dout;
pinMode(PD_SCK, OUTPUT);
pinMode(DOUT, DOUT_MODE);
set_gain(gain);
}
You can see itās using the pins you feed it as the Data and Clock lines for the HX711 - but it doesnāt call wire.begin()
Maybe itās called somewhere else. Itās a bit atypical to not call it in a setup function, but itās definitely not a fundamental issue if the commands are intended to be called in a specific order, or if it just has to be set by the person programming. Since itās also called in the LCD library, the fact it isnāt called probably wonāt break anything here.
It is odd itās configuring the pins - wire.begin() does that, but anyway, letās assume the library works and keep moving.
Letās see what that set_gain function isā¦
void HX711::set_gain(byte gain) {
switch (gain) {
case 128: // channel A, gain factor 128
GAIN = 1;
break;
case 64: // channel A, gain factor 64
GAIN = 3;
break;
case 32: // channel B, gain factor 32
GAIN = 2;
break;
}
}
Hmm, nothing really jumps out at me here. Looks fairly simple. Thatās the bottom of this rabbit hole. Letās see what the next HX711 command in your program - set_scale() - does:
void HX711::set_scale(float scale) {
SCALE = scale;
}
Well ok then. Nothing much there either. Just sets a global variable. The next HX711 library function you use is Tare() so lets look at that one. I do a ctrl+F for ātareā, and thereās no Tare() function, but there is a tare()function. Iāll just check the header (.h) file to see what thatās about (since variables and function names are case sensitive). Hmm, not here either. Ok, lets install this library and see what the compiler saysā¦
'error: HX711_LIB_VERSION' was not declared in this scope
Oook. Double check, and yep - itās not declared anywhere. Since Bryce said it compiled without errors, we must be looking at different libraries
- sure enough there are 7 different HX711 libraries in the Arduino library manager.
PS. this is why itās important to provide a direct link to the exact library youāre using when seeking help.
A google for that exact command leads me to here:
Ok, so itās the Rob Tillart HX711 library. Back to square one. Delete that old HX711 library and install the correct one.
Hmm, still no Tare() function in the library. Oh wait. Youāve made your own Tare() function that calls tare().
again. Ok, slightly confusing, but now Iām with it.
Now that Iām confident Iāve got the right library, letās go back and investigate those initialisation functions in this library.
void HX711::begin(uint8_t dataPin, uint8_t clockPin)
{
_dataPin = dataPin;
_clockPin = clockPin;
pinMode(_dataPin, INPUT);
pinMode(_clockPin, OUTPUT);
digitalWrite(_clockPin, LOW);
reset();
}
This one is almost identical to the one in the other library. What does reset do?
void HX711::reset()
{
_offset = 0;
_scale = 1;
_gain = 128;
_lastRead = 0;
_mode = HX711_AVERAGE_MODE;
}
Ok, just sets some global variables to default values. Letās try set_scale().Hmm nothing in the cpp. check the header file:
void set_scale(float scale = 1.0) { _scale = 1.0 / scale; };
Well thatās about the simplest function possible. Canāt be an issue there. Time to look at your Tare() function.
void Tare()
{
//digitalWrite(Led ,HIGH);
Serial.print("TARE UNITS: ");
Serial.println(scale.get_units(10));
Serial.println("Taring");
while(Serial.available());
while(Serial.available()) Serial.read();
scale.tare();
Serial.print("NET UNITS: ");
Serial.println(scale.get_units(10));
//digitalWrite(Led, LOW);
Serial.println("Tared");
}
while(Serial.available()); - Ok, unusual. Good chance it will get stuck in a loop here. Because you never read anything, the serial buffer will never decrease so your program will freeze here if your Arduino receives a serial command while starting up. HOWEVER, because thatās unlikely, and itās only called during setup itās probably not the issue, so Iām going to keep going.
You do need to delete that line though.
while(Serial.available()) Serial.read();- This line is fine because Serial.read() removes a byte from the serial buffer, thus decreasing the value returned by Serial.available() until it reaches 0, at which point the while(condition) evaluates to false, and the program moves on.
Youāre not actually doing anything with the data youāre reading, but if your intention is just to make sure the serial buffer is empty, this is a common way to do it.
scale.tare(); - ok, letās go back to the HX711 library and see what this does.
void tare(uint8_t times = 10) { _offset = read_average(times); };
Ok, another fairlyinnocuous looking function. Letās see what read_average() does.
float HX711::read_average(uint8_t times)
{
if (times < 1) times = 1;
float sum = 0;
for (uint8_t i = 0; i < times; i++)
{
sum += read();
yield();
}
return sum / times;
}
Ok, what it says on the tin. What does read() doā¦
float HX711::read()
{
// this BLOCKING wait takes most time...
while (digitalRead(_dataPin) == HIGH) yield();
union
{
long value = 0;
uint8_t data[4];
} v;
// blocking part ...
noInterrupts();
// Pulse the clock pin 24 times to read the data.
// v.data[2] = shiftIn(_dataPin, _clockPin, MSBFIRST);
// v.data[1] = shiftIn(_dataPin, _clockPin, MSBFIRST);
// v.data[0] = shiftIn(_dataPin, _clockPin, MSBFIRST);
v.data[2] = _shiftIn();
v.data[1] = _shiftIn();
v.data[0] = _shiftIn();
// TABLE 3 page 4 datasheet
// only default verified, so other values not supported yet
uint8_t m = 1; // default gain == 128
if (_gain == 64) m = 3;
if (_gain == 32) m = 2;
while (m > 0)
{
digitalWrite(_clockPin, HIGH);
digitalWrite(_clockPin, LOW);
m--;
}
interrupts();
// yield();
// SIGN extend
if (v.data[2] & 0x80) v.data[3] = 0xFF;
_lastRead = millis();
return 1.0 * v.value;
}
// Pulse the clock pin 24 times to read the data. Ahhhhh
Now I get it. The HX711 is not an I2C device! This is bit banging a protocol!
I first noticed you were using A4 and A5 for your HX711, so I assumed they were both I2C sensors.
Well there goes 90 minutes of my life on a silly assumption.
Again.
Sure enough, double check the datasheet and no mention of I2C or TWI anywhere:
So the problem here is that youāre using pins A4 and A5 for your HX711 which is not an I2C device, while also trying to use those two pins for your LCD - which is an I2C device. In general, you should only ever connect a single device to a pin.
Connecting multiple I2C devices is a special case - itās whatās called a Bus or Bussed protocol. The only reason you can only connect multiple I2C devices on the I2C bus, is because I2C has been carefully designed to handle that. For most electronics, thatās not the case and attaching something that doesnāt respect the manners and protocol of the very polite I2C devices is like putting a bull in a china shop - everything breaks.
Ben Eaterās video on Bus Architecture for his 8 bit breadboard computer explains it very well.
This is a good video on I2C specifically:
As an FYI, on the Uno, A4 and A5 are also directly connected to the I2C pins SDA and SCL, respectively. I think itās a flaw in the design personally - breaking out the same pins twice has lead to a lot of confusion over the years.
So, all you should need to do (after fixing that infinite loop in your Tare() function), is leave your LCD connected to A4 and A5, and move your HX711 to 2 other pins. Any 2 other digital or analog pins should work.