Суммировать значения, сохранить их и распечатать последнее значение

У меня есть массовый расходомер, подключенный к плате Arduino Uno. Мне удалось прочитать объемный расход в л/час, но теперь я изо всех сил пытаюсь реализовать код, который сохраняет значения, чтобы я мог видеть количество использованных литров.

Например, я вижу на своем мониторе это:

0 л/час

0 л/час

И если у меня течет вода,

10 л/час

20 л/час

20 л/час

Затем, когда я останавливаю поток, он возвращается к 0.

0 л/час

Есть ли какие-либо способы суммировать временные интервалы, получить общее количество литров и сохранить его в каждом экземпляре?

Математически это не так сложно (объем = объемный расход в л/час * время), но я не знаю, как это реализовать. Может кто-нибудь помочь с этим? Это может быть в секундах или мс или что-то еще.

Пол

, 👍2


3 ответа


1

Это будет полезно.

показания — это показания вашего расходомера в л/час

float reading;//значение расходомера
long startTime;
float total=0;

void setup() {
  Serial.begin(9600);
  startTime=millis();

}

void loop() {
// читать ваш расходомер для чтения переменной.
 total+=reading*float((millis()-startTime))/3600000.0;
 Serial.println(total);

}
,

Большое спасибо! Я пробовал с этим кодом, и он продолжает давать мне 0. Кроме того, мне нужно было добавить long startTime=millis(); вместо того, чтобы просто объявлять long startTime и затем вызывать его. Ответственна ли функция «чтения» за то, что я получаю 0? Это должно быть связано с сигналом или пин-режимом?, @Physther

чтение - это переменная. Вы должны передать показания расходомера в эту переменную как тип с плавающей запятой. вы должны ввести его перед функцией Serial.println(), как я прокомментировал. если вы можете дать предыдущий код, я смогу дать полный код., @user_fs10

Код можно найти здесь: http://forum.arduino.cc/index.php?topic=8548.0 (это слишком долго, чтобы публиковать его здесь). Спасибо!, @Physther


4

Что вам нужно сделать, так это интегрировать кривую зависимости скорости потока от времени. Вы должны следить за текущей скоростью потока. Также нужно выбрать какую-то единицу измерения времени; это зависит от того, как часто вы замеряете скорость потока. Например, если вы отбираете пробы каждую секунду, вам следует преобразовать скорость потока л/ч в л/с. Это означает, что скорость потока 10 л/ч эквивалентна 10 л/3600 с = 0,002778 л/с. Итак, если вы получаете показание 10 л/ч в течение 10 секунд, 0,002778 л/с * 10 с = 0,02778 л воды прошло через ваш клапан или что-то еще. Накопительная сумма – то, что вам нужно. Вы можете попробовать что-то вроде этого:

#define INTERVAL 1000  // интервал выборки в миллисекундах
#define HR_TO_SEC 2.778E-4  // количество часов в секунду

int curr_rate = 0;  // текущий расход в л/час
unsigned long lastRead = 0;  // когда в последний раз производилась выборка скорости
float totalVolume = 0; 

void loop(){
  if (millis() - lastRead >= INTERVAL){
    lastRead += INTERVAL;
    curr_rate = getFlowRate();   // или любую другую функцию, которую вы вызываете; следует взять << 1 сек
    totalVolume += curr_rate * HR_TO_SEC;  // обновить объем
    Serial.println(totalVolume, 4);
  }
}

Этот прямоугольный метод достаточно точен, в зависимости от вашего приложения. Если вам нужно более точное приближение, погуглите "трапециевидное численное интегрирование" или "метод Симпсона", если вам нужно еще более точное приближение.

,

Методы интегрирования более высокого порядка обеспечивают лучшую точность за счет использования _гладкости_ подынтегральной функции. Здесь, поскольку есть вентиль, поток вряд ли будет плавным. Если вам нужна более высокая точность, вам нужно делать выборку с более короткими интервалами., @Edgar Bonet

Кроме того, я заменил lastRead = millis(); на lastRead += INTERVAL;. В противном случае у вас будет систематическая погрешность, так как средний интервал выборки будет больше, чем «ИНТЕРВАЛ»., @Edgar Bonet

Спасибо вам обоим за помощь. Мне удалось реализовать этот код, и он действительно хранит данные. Я залил через счетчик 1 л воды, а на мониторе 1,2 л. Разница невелика, но я изменю метод интегрирования, и посмотрим, смогу ли я это исправить. Также мне пришлось удалить «unsigned» для «float totalVolume = 0;». В противном случае код выдаст ошибку., @Physther

@Paul Вы можете сделать, как говорит Эдгар Боне, и уменьшить интервал, возможно, до 200 мс. Также не забудьте изменить HR_TO_SEC, чтобы отразить это: конвертируйте интервал в часы. Если это решит вашу проблему, подумайте о том, чтобы принять это., @SoreDakeNoKoto

Хорошо. В эти дни я проведу несколько экспериментов и посмотрю, что из этого получится. Я отпишусь! Спасибо, @Physther


1

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

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

  • подпрограмма обслуживания прерывания подсчитывает количество импульсов, пропорциональна общему объему, прошедшему через счетчик
  • связанный код дифференцирует это чтение, чтобы получить поток
  • теперь вы интегрируете этот поток, чтобы получить общий объем.

Вместо того чтобы выполнять интеграцию поверх дифференциации, вы можете просто преобразуйте необработанное чтение в объем. Тогда вам не придется беспокоиться о любых приближениях, сделанных при дифференцировании или интеграция.

В ветке форума указано:

Частота импульсов (Гц) в горизонтальном тесте = 7,5Q, Q – скорость потока в л/мин.

Записав это в более точной математической форме (т. е. модульная правильность) дает:

f/Гц = 7,5 Ом/(л/мин)

где f — частота, а Q — объемный расход.

Учитывая, что 7,5 Гц⋅мин = 450 импульсов, приведенное выше уравнение можно переписать как

f = 450 импульсов/л × Q

или, если говорить об интегрированных количествах:

объем = (количество импульсов) / (450 импульсов/л)

Вот пример кода, который просто преобразует количество импульсов в объем:

// Постоянная калибровки расходомера.
const float calibration = 1/450.0;  // 450 импульсов на литр

// Как часто печатать измеренный объем.
const uint32_t print_interval = 1000;  // раз в секунду

// Количество подсчитанных импульсов.
volatile uint32_t pulse_count;

// Считаем импульсы внутри ISR.
void count_pulse() { pulse_count++; }

// Возвращаем показания объема, опционально сбрасывая счетчик на ноль.
float totalVolume(bool reset = false)
{
    noInterrupts();
    uint32_t pulse_count_copy = pulse_count;
    if (reset) pulse_count = 0;
    interrupts();
    return pulse_count_copy * calibration;
}

void setup()
{
    pinMode(2, INPUT_PULLUP);
    attachInterrupt(0, count_pulse, RISING);
    Serial.begin(9600);
}

void loop()
{
    static uint32_t last_print;
    if (millis() - last_print >= print_interval) {
        last_print += print_interval;
        Serial.println(totalVolume());
    }
}

Обратите внимание, что вы можете время от времени сбрасывать счетчик. я добавил необязательный параметр для totalVolume() для этой цели. Если ты никогда сбросить счетчик, он переполнится примерно через 9544 м3.

,