How to use the HX711 24 bit ADC for weight scales?

Can you write me a float to uint16 converter for Arduino because HX711 library get the weight value in float?
I found one here but I don’t really understand:

  float poids,total;
  uint8 n;
  index_moyenne %= NB_ECHANTILLON;
  Serial.print("\t moyenne des 10 derniers poids = ");
  Serial.println(total/NB_ECHANTILLON, 2);

Thank you

The following from your earlier post is already converting a float or double to an unsigned 16 bits integer, preserving 2 decimals:

uint16_t weight = scale.get_units() * 100; 

It depends on the HX711 library you’re using what the value means. Looking at a random description of the HX711, it seems you may need to calibrate the scale. The output also depends on the library you’re using. I’d first create a sketch to see the readings for the scale; like when using the bodge library, its example will print the measurements to the Arduino’s console.

Note that the above library indeed gives you a float:

// returns get_value() divided by SCALE, that is the raw value divided by 
// a value obtained via calibration
// times = how many readings to do
float get_units(byte times = 1);

Also note that a 2 byte unsigned integer has a maximum value of 65535, so if your weight exceeds 655.35 then you’ll get overflows with unexpected results. If the scale returns small units (like grams instead of kilograms) then you might not want to divide by 100 when converting the float into an integer. Or you might need to use more bytes, like 24 or 32 bits:

// NOT RECOMMENDED; it's better to use a SIGNED integer; see next posts.
// NOT RECOMMENDED; the ADC is 24 bits, so using 32 bits is really not needed.
uint32_t weight = scale.get_units() * 100;
byte message[8];
// 0x12345678 >> 24 shifts the 0x345678 out of memory, leaving 0x00000012
// 0x00000012 does not fit in a single byte, so 0x12 is stored in message[4]:
message[4] = weight >> 24;
message[5] = weight >> 16;
message[6] = weight >> 8;
message[7] = weight;

To decode 4 bytes in TTN you would not need sign extension (like you would for 2 or 3 bytes, if you’d expect negative values too):

// 0x12 << 24 yields 0x12000000,
// 0x34 << 16 yields     340000, and so on:
var w = bytes[4]<<24 | bytes[5]<<16 | bytes[6]<<8 | bytes[7];

I try it like this now:

// Read sensor values and multiply by 100 to effictively have 2 decimals
uint16_t humidity = dht.readHumidity(false) * 100;

// false: Celsius (default)
// true: Farenheit
int16_t temperature = dht.readTemperature(false) * 100;

float w; 
w = scale.get_units(), 1;
uint16_t weight = w * 100;

// Split both words (16 bits) into 6 bytes of 8
byte message[6];

message[0] = highByte(temperature);
message[1] = lowByte(temperature);
message[2] = highByte(humidity);
message[3] = lowByte(humidity);
message[4] = highByte(weight);
message[5] = lowByte(weight);

LMIC_setTxData2(1, message, sizeof(message), 0);

Are you saying that solved your problem? This should really the same as your previous:

uint16_t weight = scale.get_units() * 100;

(As an aside, I don’t understand what the , 1 does in w = scale.get_units(), 1;)

It hase something to do withe the tare.

I build a wifi scale long time ago… this is whats left of the prototype, maybe in the future, when your code is ready :wink: , convert it to a loRa scale :sunglasses:

ideal would be, just step on it and it sends your weight over LoRaWAN / TTN to a DB and you can see the nice graphics on your phone

and what about a LoRaWAN enabled cat litter box ?

1 Like

Max. 150kg     d = 100g

For this, it would probably suffice to multiply a reading in kilograms by 10, hence preserving 1 decimal, as the accuracy is just 100 gram or 0.1 kg anyway.

But multiplying by 10 would allow an unsigned 16 bits integer to hold a maximum of 6553.5 kg, which is way above the scale’s maximum. So, if the float reading is in kilograms, one could still preserve 2 decimals (multiply by 100, just like in the code above), yielding a maximum of 655.35 kg which is still way above the scale’s maximum. A single 8 bits byte, with a maximum of 255, would be too small to hold the maximum of 149.9 kg with one decimal though.

To detect negative weight values (probably indicating a calibration error), it’s even better to send a 16 bits signed integer (int16_t), which supports -32768 up to 32767, hence a maximum of 327.67 kg with two decimals. Like noted earlier, that needs sign extension when decoding negative values in a payload function.

1 Like

If I turn off the device for a while and turn on some hours later the ttn doesn’t recive data from it until I press the SIMULATE UPLINK button. Why

Without any details for us to go on, I guess your solution is at ABP node stopped working -> Fixed by creating new ABP.. Why? :)

Ok. First I try to set the Frame Counter Width 16 bit instead with 32 bit.


The setting for the frame counter width should match the internals of your node. But it will only get you into trouble if the counter exceeds the first 16 bits (65,536), after which the digital signature of the node’s payload will be invalid if the counter’s width does not match. However, I doubt this is giving you any problems now…