Milligram Scale - TARE button programming with HX711 & Nextion display

Good day all,

Going to start this off with the classic "I am new to Arduino", so there is still a lot to learn for me. To thus far I've managed to correct a lot of errors by working through numerous threads on this forum as well as others but I am currently baffled.

I am busy building a milligram scale with the end goal of measuring to 0.005g reliably. For the interface I am using a Nextion display to display the current weight rating. Once the unit is powered on the scale calibrates itself with a predefined calibration value and then tares the scale to zero. See below for the circuit construction.

I have also added a TARE button to the interface to manually zero the scale when required. The problem I am having is as CODE 1 is currently written, the TARE button only works when the button is pressed between the loop iterations, requiring me to continuously press the button until the timing is correct and it finally registers and zeros the scale. Am I correct in my statement about the press event only registering between loops?

CODE 1:
Below is the code I am currently using where the button must be pressed repeatedly until it finally registers:

// LIBRARIES REQUIRED:
#include <HX711_ADC.h>   //INCLUDE HX711_ADC LIBRARY FOR LOAD CELL
#include <EEPROM.h>     //INCLUDE EEPROM LIBRARY TO STORE DATA TO EEPROM
#include <Nextion.h>    //INCLUDE NEXTION LIBRARY TO WRITE DATA FROM ARDUINO > NEXTON

// PINS TO BE USED:
const int HX711_dout = 3; //UNO > HX711 DATA PIN
const int HX711_sck = 2; //UNO > HX711 CLK PIN

bool _tare = false;

//DEFINE OBJECTS TO BE USED ON NEXTION SCREEN
NexText textNumber = NexText(0,2,"textNumber"); // NexText(page number, object number, "object name")
NexButton buttonTare = NexButton(0,1,"buttonTare");
char buffer[10] = {0}; //CREATES A BUFFER TO HOLD THE TEXT

//REGISTER OBJECTS FOR NEXTION DISPLAY
NexTouch *nex_listen_list[] =
{
  &textNumber,
  &buttonTare,
  NULL
};

//HX711 CONSTRUCTOR:
HX711_ADC LoadCell(HX711_dout, HX711_sck);

const int calVal_eepromAdress = 0;
unsigned long t = 0;


void buttonTarePushCallback(void *ptr){

  LoadCell.tareNoDelay();
  
}//END OF TARE BUTTON FUNCTION

void setup() {
  nexInit();
  Serial.begin(9600); 
  delay(10);
 
  LoadCell.begin();
  float calibrationValue; // calibration value (see example file "Calibration.ino")
  calibrationValue = 6533.93; // 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

  unsigned long stabilizingtime = 2000; // 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");
  }
  buttonTare.attachPush(buttonTarePushCallback);

} //END SETUP

void loop() {
  nexLoop(nex_listen_list);

  static boolean newDataReady = 0;
  const int serialPrintInterval = 0; //INCREASE VALUE TO REDUCE SCREEN PRINT INTERVALS
  // 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();
      float i_rounded =((round(i*200)+0.005)/200); //ROUNDS VALUE TO NEAREST 0.005
    //Serial.print("Load_cell output val: "); // FOR DEBUGGING, IF USED COMMENT OUT textNumber.setText(buffer)
    //Serial.println(i_rounded); // FOR DEBUGGING, IF USED COMMENT OUT textNumber.setText(buffer)    
      newDataReady = 0;
      t = millis();
      memset(buffer,i_rounded , sizeof(buffer)); //CLEARS BUFFER
      dtostrf(i_rounded, 8, 3, buffer); // ALLOWS FOR DECIMAL VALUES TO BE DISPLAYED ON THE NEXTION dtostrf(variable, ???, number decimals, buffer)
      textNumber.setText(buffer);
    
    } //END IF (MILLIS()....)
  } //END IF (NEWDATAREADY)
}// END LOOP

I would like to be able to press the TARE button at any time with the scale then zeroing and afterwards continuing with the readings. I've tried incorporating the buttonTarePushCallback into an IF statement in CODE 2 however this does not seem to do anything once the button is pushed. Any idea why the button is not zeroing the scale when pressed?

CODE 2:
The following code has the IF statement incorporated into the void loop():

// LIBRARIES REQUIRED:
#include <HX711_ADC.h>   //INCLUDE HX711_ADC LIBRARY FOR LOAD CELL
#include <EEPROM.h>     //INCLUDE EEPROM LIBRARY TO STORE DATA TO EEPROM
#include <Nextion.h>    //INCLUDE NEXTION LIBRARY TO WRITE DATA FROM ARDUINO > NEXTON

// PINS TO BE USED:
const int HX711_dout = 4; //UNO > HX711 DATA PIN
const int HX711_sck = 5; //UNO > HX711 CLK PIN

bool _tare = false;

//DEFINE OBJECTS TO BE USED ON NEXTION SCREEN
NexText textNumber = NexText(0,2,"textNumber"); // NexText(page number, object number, "object name")
NexButton buttonTare = NexButton(0,1,"buttonTare");
char buffer[10] = {0}; //CREATES A BUFFER TO HOLD THE TEXT

//REGISTER OBJECTS FOR NEXTION DISPLAY
NexTouch *nex_listen_list[] =
{
  &textNumber,
  &buttonTare,
  NULL
};

//HX711 CONSTRUCTOR:
HX711_ADC LoadCell(HX711_dout, HX711_sck);

const int calVal_eepromAdress = 0;
unsigned long t = 0;


void buttonTarePushCallback(void *ptr){

  
  
}//END OF TARE BUTTON FUNCTION

void setup() {
  nexInit();
  Serial.begin(9600); 
  delay(10);
 
  LoadCell.begin();
  float calibrationValue; // calibration value (see example file "Calibration.ino")
  calibrationValue = 6533.93; // 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

  unsigned long stabilizingtime = 2000; // 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");
  }



} //END SETUP

void loop() {
  nexLoop(nex_listen_list);

  if (buttonTarePushCallback){
  LoadCell.tareNoDelay();

  static boolean newDataReady = 0;
  const int serialPrintInterval = 0; //INCREASE VALUE TO REDUCE SCREEN PRINT INTERVALS
  // 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();
      float i_rounded =((round(i*200)+0.005)/200); //ROUNDS VALUE TO NEAREST 0.005
    //Serial.print("Load_cell output val: "); // FOR DEBUGGING, IF USED COMMENT OUT textNumber.setText(buffer)
    //Serial.println(i_rounded); // FOR DEBUGGING, IF USED COMMENT OUT textNumber.setText(buffer)    
      newDataReady = 0;
      t = millis();
      memset(buffer,i_rounded , sizeof(buffer)); //CLEARS BUFFER
      dtostrf(i_rounded, 8, 3, buffer); // ALLOWS FOR DECIMAL VALUES TO BE DISPLAYED ON THE NEXTION dtostrf(variable, ???, number decimals, buffer)
      textNumber.setText(buffer);
}
    
    } //END IF (MILLIS()....)
  } //END IF (NEWDATAREADY)
}// END LOOP

*My code is a modified version of example "Read_1x_load_cell" within the HX711_ADC library.

Kind Regards,
Stefaans5111

I suspect that your tare issue is caused by the fact that you only change the display if there is new data as defined by LoadCell.update(). Does setting tare count as new data in that context?

stefaans5111:
I am busy building a milligram scale with the end goal of measuring to 0.005g reliably.

I'm not sure how realistic that is given the components at hand. What's the delta-V across the load cell for a 0.005g change in weight? Have you considered Load Cell Creep and temperature-related effects?

The setup() is only done once at startup, usually it is for configuration and initialization.
If you want your push button for tare to act immediately, you must connect the input to an interrupt one and attach an ISR to it that perform this operation

abdelhmimas:
If you want your push button for tare to act immediately, you must connect the input to an interrupt one and attach an ISR to it that perform this operation

Bad advice. Ignore. There's no good reason to use an interrupt for that, polling is more than adequate. Especially since the HX711 conversion and data transfer operations you'd need to do to perform a tare will take much more time than you should be spending in an ISR.

gfvalvo:
Bad advice. Ignore. There's no good reason to use an interrupt for that, polling is more than adequate. Especially since the HX711 conversion and data transfer operations you'd need to do to perform a tare will take much more time than you should be spending in an ISR.

Polling continuously an input that is used only to tare is a waste of time and poor coding practice.

wildbill:
I suspect that your tare issue is caused by the fact that you only change the display if there is new data as defined by LoadCell.update(). Does setting tare count as new data in that context?

From my understanding it would count as new data. Once the scale is tared the readings would be taking the offset values from the tare relative to the true zero into consideration.

gfvalvo:
I'm not sure how realistic that is given the components at hand. What's the delta-V across the load cell for a 0.005g change in weight? Have you considered Load Cell Creep and temperature-related effects?

With my current components a reliable measurement of 0.005g is unrealistic. I am busy sourcing better quality load cells as the one I am using has been removed from a "cheap" scale rated for 0.01g accuracy.

With regard to the load cell creep & temperature effects, I had issues with the creep where it would drift with around 0.1g per minute. This seemed to be due to unused pins on the HX711 module. Once I connected the HX711 E+ > MCU 5V and the HX711 E- > MCU Ground the drift was reduced to around 0.1g over 6 hours with the environment temperature remaining relatively constant.
With regards to other temperature related effects I have noticed that when there is a substantial increase / decrease in the environment conditions (temperature, humidity) the scale needs to be calibrated again to get a new "calibration factor" for the load cell otherwise it displays incorrect data.

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