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
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.
-
1In addition: Here a moving average might be a good choice, like in the second answer to this questionchrisl– chrisl2023年06月21日 09:26:34 +00:00Commented Jun 21, 2023 at 9:26
-
Thanx a lot!! I will try it.spdif– spdif2023年06月22日 03:31:20 +00:00Commented Jun 22, 2023 at 3:31