I'm working on a project where w=I need to attach a loadcell to fuel tank and display the weight of its contents continuously.
But, it seems that my system only shows the proper weight if and only if when there is no weight placed on it on the startup and is placed after the system start ups. If not done that way the results are inverted, as if the system considers the weight of placed object as its ref 0 and if we remove that object later on its weight is shown with negative sign.
For example, if on start up I place an object of 23 gms the system will still show it as 0 and if I remove it later on the system will show it as -23gms. I don't want this to happen as my loadcell is supposed to be connected to the fuel tank all the time and when I start the system it will have load on it already, so I wish to see the exact weight of it upon startup.
My next problem is, after the system gets to homepage I can see the weight displayed at desired place as well as on the top left corner of my LCD which is undesirable. I only want it to the center of my LCD but I have no idea as why the system also prints it on the top left corner of the LCD. After a minute or so the readout in the top left corner goes off by on its own!
I have attached the code as it won't fit in the word limit here. I don't know what mistake I'm making here. Any help and suggestions are heartly appreciated. Thanks in advance and belated wish you a very happy and blessed new year.
Start with a basic sketch that reads the value of teh load cell and displays it in the Serial monitor
Does it do what you expect ?
You could tidy up your code considerably by using an array to hold pin numbers and iterating through them. Your tests for which page you are on are very clumsy.
Why test for the value of SwA in multiple places when you could do it just once before testing the page number and not test the page numbers at all unless necessary ?
The tests for page number would lead themselves to the use of switch/case (based on the page number) which provides the same functionality as if/else but is easier to read and maintain.
The check button functions as written are also clumsy. Note that the value of SwA, for instance, is directly related to the state of the input so the check of the button state is not really needed as you could just set a variable to their state or its inverse
I realise that the above does not address the problem of the code not doing what you want, but if you make it as tidy and easy to read as possible then it will be easier to debug. It is also common to spot bugs during the course of refactoring code as it forces you to look closely at it
UKHeliBob:
Start with a basic sketch that reads the value of teh load cell and displays it in the Serial monitor
Does it do what you expect ?
No it doesn't do what I expect it to do.
This is the code that came with library
/*
-------------------------------------------------------------------------------------
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 = A4; //mcu > HX711 dout pin
const int HX711_sck = A5; //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 = 0; // 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");
}
}
Speaking of making the code tidy, I'll surely do it. But you see few months ago I had to create a temperature controller and I wanted to have a menu system for its parameter settings, I successfully completed that project and the code worked just fine without any key pressed being missed or any other thing. So I decided to keep the structure of the code as it and just change the page contents as needed. In three months I have almost used this code for four different projects. Key thing is I really have grasped the execution flow of this code. But still I'll try to cut out the redundancies.
but while I do that, is there anything which I can do to solve my problem as well?
Sounds like you either mounted to load cell upside-down, or you need to switch the two signal leads where the connect to the A/D board.
Or, you could just deal with it in software. The RELATIVE numbers should be correct, so simply multiple all readings by -1 before doing anything with them.
RayLivingston:
Sounds like you either mounted to load cell upside-down, or you need to switch the two signal leads where the connect to the A/D board.
Or, you could just deal with it in software. The RELATIVE numbers should be correct, so simply multiple all readings by -1 before doing anything with them.
No No, the load cell is placed correctly and the wiring is correct as well. My problem is completely different.
For example, if on start up I place an object of 23 gms the system will still show it as 0 and if I remove it later on the system will show it as -23gms. I don't want this to happen as my loadcell is supposed to be connected to the fuel tank all the time and when I start the system it will have load on it already, so I wish to see the exact weight of it upon startup.
But if I place the same object after the system startup it would show 23 gms which is the proper readout
Count:
No No, the load cell is placed correctly and the wiring is correct as well. My problem is completely different.
For example, if on start up I place an object of 23 gms the system will still show it as 0 and if I remove it later on the system will show it as -23gms. I don't want this to happen as my loadcell is supposed to be connected to the fuel tank all the time and when I start the system it will have load on it already, so I wish to see the exact weight of it upon startup.
But if I place the same object after the system startup it would show 23 gms which is the proper readout
Are you properly zeroing the reading? The load cell, by itself will NOT read 0 with no load. It will ALWAYS have some offset that needs to be zeroed out.
Also, the A/D will drift with temperature. My experience is they take as much as 5-10 minutes to stabilize. Until then, the output will drift, sometimes by a lot. So, if you zero it on power-up, then come back 5-10 minutes later, it will no longer be zeroed.
RayLivingston:
Are you properly zeroing the reading? The load cell, by itself will NOT read 0 with no load. It will ALWAYS have some offset that needs to be zeroed out.
Also, the A/D will drift with temperature. My experience is they take as much as 5-10 minutes to stabilize. Until then, the output will drift, sometimes by a lot. So, if you zero it on power-up, then come back 5-10 minutes later, it will no longer be zeroed.
You seem to be missing a point. or may be I'm not explain it properly. The load cell is zeroed properly. everything works correctly but not the way I want it to be.
If I start the system up and then place the object of 23 gms on it, it will show 23 gms which is correct.
Now, scenario two, if I already place the same object on the loadcell but the system is not turned ON yet. Now I turn ON the system after placing the object on loadcell, the load cell will consider this weight as its reference zero and so when and if I remove that object now, the readout will be -23gms which is wrong in both the cases.
My application needs that the loadcell is constantly under some load, I can't place it after the system is turned on. I'm supposed to place this loadcell below a fuel tank in a truck to measure the weight of fuel. So there always be some load present on the loadcell no matter if the system is on or off, after viewing the later scenario, when my system will start up it will consider the current load on it as its reference zero. Which is undesirable for this application.
The behavior you're objecting to is exactly what you coded:
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 you don't want a tare performed on startup, then don't code it to do one. Instead, why don't you come up with the proper no-load tare and store that in EEPROM along with the calibration?
gfvalvo:
The behavior you're objecting to is exactly what you coded:
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 you don't want a tare performed on startup, then don't code it to do one. Instead, why don't you come up with the proper no-load tare and store that in EEPROM along with the calibration?
Yeap, that seems to be the solution of my problem!!
UKHeliBob:
Both of these cannot be true
What exactly does the basic sketch do ?
The basic sketch first is the calibration sketch. it first asks to tare the load cell, then it asks to place a load on it whose weight is known and enter the weight. And then it asks if I want to store the calibration factor into eeprom. and then it starts showing the weights we place on loadcell
gfvalvo:
The behavior you're objecting to is exactly what you coded:
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 you don't want a tare performed on startup, then don't code it to do one. Instead, why don't you come up with the proper no-load tare and store that in EEPROM along with the calibration?
No-load tare would be not placing anything on loadcell?
this is the calibration sketch that came along with library
/*
-------------------------------------------------------------------------------------
HX711_ADC
Arduino library for HX711 24-Bit Analog-to-Digital Converter for Weight Scales
Olav Kallhovd sept2017
-------------------------------------------------------------------------------------
*/
/*
This example file shows how to calibrate the load cell and optionally store the calibration
value in EEPROM, and also how to change the value manually.
The result value can then later be included in your project sketch or fetched from EEPROM.
To implement calibration in your project sketch the simplified procedure is as follow:
LoadCell.tare();
//place known mass
LoadCell.refreshDataSet();
float newCalibrationValue = LoadCell.getNewCalibration(known_mass);
*/
#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();
long stabilizingtime = 2000; // preciscion right after power-up can be improved by adding a few seconds of stabilizing time
boolean _tare = false; //set this to false if you don't want tare to be performed in the next step
LoadCell.start(stabilizingtime, _tare);
if (LoadCell.getTareTimeoutFlag() || LoadCell.getSignalTimeoutFlag()) {
Serial.println("Timeout, check MCU>HX711 wiring and pin designations");
while (1);
}
else {
LoadCell.setCalFactor(1.0); // user set calibration value (float), initial value 1.0 may be used for this sketch
Serial.println("Startup is complete");
}
while (!LoadCell.update());
calibrate(); //start calibration procedure
}
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
if (Serial.available() > 0) {
float i;
char inByte = Serial.read();
if (inByte == 't') LoadCell.tareNoDelay(); //tare
else if (inByte == 'r') calibrate(); //calibrate
else if (inByte == 'c') changeSavedCalFactor(); //edit calibration value manually
}
// check if last tare operation is complete
if (LoadCell.getTareStatus() == true) {
Serial.println("Tare complete");
}
}
void calibrate() {
Serial.println("***");
Serial.println("Start calibration:");
Serial.println("Place the load cell an a level stable surface.");
Serial.println("Remove any load applied to the load cell.");
Serial.println("Send 't' from serial monitor to set the tare offset.");
boolean _resume = false;
while (_resume == false) {
LoadCell.update();
if (Serial.available() > 0) {
if (Serial.available() > 0) {
float i;
char inByte = Serial.read();
if (inByte == 't') LoadCell.tareNoDelay();
}
}
if (LoadCell.getTareStatus() == true) {
Serial.println("Tare complete");
_resume = true;
}
}
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 known_mass = 0;
_resume = false;
while (_resume == false) {
LoadCell.update();
if (Serial.available() > 0) {
known_mass = Serial.parseFloat();
if (known_mass != 0) {
Serial.print("Known mass is: ");
Serial.println(known_mass);
_resume = true;
}
}
}
LoadCell.refreshDataSet(); //refresh the dataset to be sure that the known mass is measured correct
float newCalibrationValue = LoadCell.getNewCalibration(known_mass); //get the new calibration value
Serial.print("New calibration value has been set to: ");
Serial.print(newCalibrationValue);
Serial.println(", use this as calibration value (calFactor) in your project sketch.");
Serial.print("Save this value to EEPROM adress ");
Serial.print(calVal_eepromAdress);
Serial.println("? y/n");
_resume = false;
while (_resume == false) {
if (Serial.available() > 0) {
char inByte = Serial.read();
if (inByte == 'y') {
#if defined(ESP8266)|| defined(ESP32)
EEPROM.begin(512);
#endif
EEPROM.put(calVal_eepromAdress, newCalibrationValue);
#if defined(ESP8266)|| defined(ESP32)
EEPROM.commit();
#endif
EEPROM.get(calVal_eepromAdress, newCalibrationValue);
Serial.print("Value ");
Serial.print(newCalibrationValue);
Serial.print(" saved to EEPROM address: ");
Serial.println(calVal_eepromAdress);
_resume = true;
}
else if (inByte == 'n') {
Serial.println("Value not saved to EEPROM");
_resume = true;
}
}
}
Serial.println("End calibration");
Serial.println("***");
Serial.println("To re-calibrate, send 'r' from serial monitor.");
Serial.println("For manual edit of the calibration value, send 'c' from serial monitor.");
Serial.println("***");
}
void changeSavedCalFactor() {
float oldCalibrationValue = LoadCell.getCalFactor();
boolean _resume = false;
Serial.println("***");
Serial.print("Current value is: ");
Serial.println(oldCalibrationValue);
Serial.println("Now, send the new value from serial monitor, i.e. 696.0");
float newCalibrationValue;
while (_resume == false) {
if (Serial.available() > 0) {
newCalibrationValue = Serial.parseFloat();
if (newCalibrationValue != 0) {
Serial.print("New calibration value is: ");
Serial.println(newCalibrationValue);
LoadCell.setCalFactor(newCalibrationValue);
_resume = true;
}
}
}
_resume = false;
Serial.print("Save this value to EEPROM adress ");
Serial.print(calVal_eepromAdress);
Serial.println("? y/n");
while (_resume == false) {
if (Serial.available() > 0) {
char inByte = Serial.read();
if (inByte == 'y') {
#if defined(ESP8266)|| defined(ESP32)
EEPROM.begin(512);
#endif
EEPROM.put(calVal_eepromAdress, newCalibrationValue);
#if defined(ESP8266)|| defined(ESP32)
EEPROM.commit();
#endif
EEPROM.get(calVal_eepromAdress, newCalibrationValue);
Serial.print("Value ");
Serial.print(newCalibrationValue);
Serial.print(" saved to EEPROM address: ");
Serial.println(calVal_eepromAdress);
_resume = true;
}
else if (inByte == 'n') {
Serial.println("Value not saved to EEPROM");
_resume = true;
}
}
}
Serial.println("End change calibration value");
Serial.println("***");
}
Count:
No-load tare would be not placing anything on loadcell?
By definition, tare is performed under the condition where you want the scale to read zero.
The way to think of it is that tare is provides the fixed offset to subtract from the raw load cell reading while calibration provides the multiplicative scaling factor.
gfvalvo:
By definition, tare is performed under the condition where you want the scale to read zero.
The way to think of it is that tare is provides the fixed offset to subtract from the raw load cell reading while calibration provides the multiplicative scaling factor.
So Should I just remove the tare code? or I should do something what u said earlier as no-tare load? and how do I do it?
Count:
You seem to be missing a point. or may be I'm not explain it properly. The load cell is zeroed properly. everything works correctly but not the way I want it to be.
If I start the system up and then place the object of 23 gms on it, it will show 23 gms which is correct.
Now, scenario two, if I already place the same object on the loadcell but the system is not turned ON yet. Now I turn ON the system after placing the object on loadcell, the load cell will consider this weight as its reference zero and so when and if I remove that object now, the readout will be -23gms which is wrong in both the cases.
My application needs that the loadcell is constantly under some load, I can't place it after the system is turned on. I'm supposed to place this loadcell below a fuel tank in a truck to measure the weight of fuel. So there always be some load present on the loadcell no matter if the system is on or off, after viewing the later scenario, when my system will start up it will consider the current load on it as its reference zero. Which is undesirable for this application.
Because YOUR software is zeroing the scale on power-up! Whether you realize it or not, that is what is happening.
gfvalvo:
The behavior you're objecting to is exactly what you coded:
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 you don't want a tare performed on startup, then don't code it to do one. Instead, why don't you come up with the proper no-load tare and store that in EEPROM along with the calibration?
I tried commenting those lines but then the scale shows very wrong values.
Will you please provide the following information?
1. Range of external load/weight to be applied on the Load Cell. 2. Specification of the Load Cell or a Link to the Load Cell. 3. Are you using the following ADC Module?
You don't seem to understand the concept of Tare Weight.
If you want to know how much stuff you have in a container, you can weigh the container full of stuff. But then you must subtract the weight of the empty container. What's left is the weight of your stuff.
The weight of the empty container is the Tare Weight.
Right now your code is taking the Tare Weight every time it starts up. This is causing the behavior that you're complaining about.
Count:
I tried commenting those lines but then the scale shows very wrong values.
That's because you've gone from taking the Tare Weight every time your program start to not taking the Tare Weight at all. You see the results.
So, you need to take the Tare Weight once while your tank is empty. You need to save that value in EEPROM just like you did with the calibration value.
Once you've done that, your code should pull the Tare from EEPROM when it starts up and send it to the HX711_ADC library. Check the library's source code for the setTareOffset() function.