2

I am making a 50kg weighing scale using HX711 ADC. My project includes Atmega328 along with 74HC595 for driving 5 7segment displays(multiplexed). I am using the function scale.get_units()to fetch the data and the values are very well displayed on the 7segments. The problem I am facing is the readings on the 5th digit (right most 1's) are unstable. Now, if I use scale.read_average(5), my display scanning gets slow. I was wondering if there is a way to average the readings in a loop like the conventional way. I tried it but with no luck! It keeps showing random added numbers. Any help would be highly appriciated. Below is the code inside the loop. Let me know if full code is needed. Thanx in advance!

if (scale.is_ready()) {
    weight = scale.get_units();
    finalWeight = weight * 1000;
}
for (int i = 0; i < 10 ;i++) {
    sum += finalWeight;
}
average = sum / 10;
if (average < 0) {
    break_number(0);
} else {
    break_number(average);
}
display_number();
delay(1);

1 Answer 1

1

First of all, this code:

for (int i = 0; i < 10 ;i++) {
    sum += finalWeight;
}
average = sum / 10;

does not average multiple readings. Instead, it takes the single reading stored in finalWeight, multiplies it by ten (by means of successive additions), then divides it by ten to get back the same value.

If you want to reduce the noise, you have to take multiple readings and average them. The reading-taking code must thus be inside the loop. A simple option may be like this:

void loop() {
    sum = 0;
    for (int i = 0; i < 10; i++) {
        while (!scale.is_ready()) {}  // wait for the scale to be ready
        sum += scale.get_units();
    }
    weight = sum / 10;  // compute the average
    display(weight);    // and display it
}

Note that I have simplified things a bit by removing the scaling factors. You can take this as simple inspiration and adapt to your specific needs.

The code above has one problem though: as the code is blocking while waiting for the scale to be ready, the display is not refreshed. You could fix this by explicitly refreshing the display within the waiting loop:

void loop() {
    sum = 0;
    for (int i = 0; i < 10; i++) {
        while (!scale.is_ready()) {  // wait...
            display(weight);         // ...while refreshing the display
        }
        sum += scale.get_units();
    }
    weight = sum / 10;
    display(weight);
}

This should work, but I would however suggest instead a third approach: write non-blocking code. This is code that never blocks: instead, if something can be done right now, it does it. If not, it moves along:

void loop() {
    if (scale.is_ready()) {  // if something useful can be done NOW:
        sum += scale.get_units();
        count++;
        if (count >= 10) {
            weight = sum / count;  // update the value to be displayed
            sum = 0;               // reset the averaging variables
            count = 0;
        }
    }

    display(weight);  // unconditionally refresh the display
}

This way, your loop() always runs fast, and you can add code that will not be blocked by the stuff you wrote earlier.

Edit: As suggested by chrisl in a comment, a moving average may better serve your needs. I would try the exponentially-weighted version, as it is lightweight and simpler to implement. You may want to explore this path.

2
  • 1
    In addition: Here a moving average might be a good choice, like in the second answer to this question
    – chrisl
    Jun 21, 2023 at 9:26
  • Thanx a lot!! I will try it.
    – spdif
    Jun 22, 2023 at 3:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.