Сглаживание показаний hx711 с помощью atmega328

Я делаю весы на 50 кг, используя АЦП HX711. Мой проект включает Atmega328 вместе с 74HC595 для управления 5 7-сегментными дисплеями (мультиплексорными). Я использую функцию scale.get_units() для получения данных, и значения очень хорошо отображаются в 7 сегментах. Проблема, с которой я столкнулся, заключается в том, что показания 5-й цифры (самые правые единицы) нестабильны. Теперь, если я использую scale.read_average(5), сканирование дисплея замедляется. Мне было интересно, есть ли способ усреднить показания в цикле, как это делается обычным способом. Я попробовал, но безуспешно! Он продолжает показывать случайные добавленные числа. Любая помощь будет высоко оценена. Ниже приведен код внутри цикла. Дайте мне знать, если нужен полный код. Заранее спасибо!

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);

, 👍2


1 ответ


1

Прежде всего, этот код:

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

не усредняет несколько показаний. Вместо этого требуется одно чтение хранится в finalWeight, умножает его на десять (посредством последовательных сложения), а затем делит его на десять, чтобы получить то же значение.

Если вы хотите уменьшить шум, вам придется снять несколько показаний и усредните их. Таким образом, код чтения должен находиться внутри цикла. А простой вариант может быть таким:

void loop() {
    sum = 0;
    for (int i = 0; i < 10; i++) {
        while (!scale.is_ready()) {}  // ждем, пока весы будут готовы
        sum += scale.get_units();
    }
    weight = sum / 10;  // вычисляем среднее значение
    display(weight);    // и отображаем его
}

Обратите внимание, что я немного упростил задачу, убрав масштабирование. факторы. Вы можете воспринимать это как простое вдохновение и адаптироваться к своим конкретные потребности.

Однако у приведенного выше кода есть одна проблема: поскольку код блокируется во время ждем готовности весов, дисплей не обновляется. Ты можно исправить это, явно обновив дисплей во время ожидания цикл:

void loop() {
    sum = 0;
    for (int i = 0; i < 10; i++) {
        while (!scale.is_ready()) {  // подождем...
            display(weight);         // ...при обновлении дисплея
        }
        sum += scale.get_units();
    }
    weight = sum / 10;
    display(weight);
}

Это должно сработать, но вместо этого я бы предложил третий подход: написать неблокирующий код. Это код, который никогда не блокируется: вместо этого, если что-то можно сделать прямо сейчас, оно это делает. Если нет, он движется дальше:

void loop() {
    if (scale.is_ready()) {  // можно ли сделать что-то полезное СЕЙЧАС:
        sum += scale.get_units();
        count++;
        if (count >= 10) {
            weight = sum / count;  // обновляем отображаемое значение
            sum = 0;               // сбрасываем переменные усреднения
            count = 0;
        }
    }

    display(weight);  // безусловно обновляем дисплей
}

Таким образом, ваш loop() всегда работает быстро, и вы можете добавить код, который будет не быть заблокированным тем, что вы написали ранее.

Обновлено. Как предположил Крисл в комментарии, скользящее среднее может лучше удовлетворить ваши потребности. Я бы попробовал экспоненциально взвешенную версию, поскольку он легче и проще в реализации. Возможно, вы захотите изучить этот путь.

,

Кроме того: здесь хорошим выбором может быть скользящее среднее, как во втором ответе на [этот вопрос](https://stackoverflow.com/questions/67208086/how-can-i-calculate-a-moving-average- в ардуино), @chrisl

Большое спасибо!! Я попробую., @spdif