Добавление еще одного датчика расхода в скетч

Добавление еще одного датчика расхода в скетч

У меня есть скетч потока воды, который я использую для своего потребления пресной воды. Я хотел бы приспособить его к использованию для потребления дизельного топлива. Разница в том, что с дизельным двигателем топливный насос всасывает больше топлива, чем сжигает из топливного бака, и просто возвращает избыток в топливный бак. т. е. есть 2 шланга от топливного бака, один к двигателю, а один обратно к баку. Разница между тем, что шло в мотор, и тем, что шло обратно в бак, заключается в том, сколько топлива сжигал мотор.

Таким образом, мой план состоит в том, чтобы иметь 2 датчика потока (Yf-s201) и вычесть выход одного из другого и распечатать разницу.

Есть скетч, который уже работает, чтобы напечатать L/m и total L. Для одного датчика на выводе D2. Я определил другой датчик на выводе D3.

byte sensorInterrupt = 0;  // 0 = digital pin 2
byte sensorPin       = 2;

byte sensorInterrupt2 = 1;  //11 = digital pin 3
byte sensorPin2       = 3;

Мой первый блок-печатать их по отдельности. как и они оба просто добавляют к единому итогу.

Я пытался просто скопировать биты кода и добавить "2", но у меня действительно нет никаких знаний программирования, поэтому я просто колю в темноте. Я не понимаю, как вызвать значение, вычисленное кодом.

Вот весь скетч:

/*
Датчик расхода жидкости-DIYhacking.com Арвинд Санджев

Измерьте расход жидкости/воды с помощью этого кода. 
Подключите Vcc и Gnd датчика к arduino, а
сигнальную линию-к цифровому контакту arduino 2.
 
 */
// include the library code:
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,20,4); 


byte statusLed    = 13;

byte sensorInterrupt = 0;  // 0 = digital pin 2
byte sensorPin       = 2;

byte sensorInterrupt2 = 1;  // 1 = digital pin 3
byte sensorPin2       = 3;

// Датчик расхода с эффектом Холла выдает примерно 4,5 импульса в секунду.
// расход / литр/минута.
float calibrationFactor = 7.55;  //biger more / min

volatile byte pulseCount;  

float flowRate;
unsigned int flowMilliLitres;
unsigned long totalMilliLitres;

unsigned long oldTime;

void setup()
{
  
  // Инициализировать последовательное соединение для передачи значений хосту
  Serial.begin(9600);
lcd.init();
lcd.backlight();
     lcd.begin(16, 2);
   lcd.clear();
   lcd.setCursor(0,0);
   lcd.print("S.V. SAVANNAH");
   lcd.setCursor(0,1);
   lcd.print("DAY TANK FLOW METER");
   
  // Настройка светодиодной линии состояния в качестве выходного
  pinMode(statusLed, OUTPUT);
  digitalWrite(statusLed, HIGH);  // У нас есть подключенный светодиод active-low
  
  pinMode(sensorPin, INPUT);
  digitalWrite(sensorPin, HIGH);

  pulseCount        = 0;
  flowRate          = 0.0;
  flowMilliLitres   = 0;
  totalMilliLitres  = 0;
  oldTime           = 0;

  // Датчик эффекта Холла подключен к контакту 2, который использует прерывание 0.
  // Сконфигурирован для срабатывания при изменении ПАДАЮЩЕГО состояния (переход от ВЫСОКОГО
  // состояние к НИЗКОМУ состоянию)
  attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
}

/**
 * Main program loop
 */
void loop()
{
   
   if((millis() - oldTime) > 1000)    // Only process counters once per second
  { 
    // Отключите прерывание при вычислении скорости потока и отправке значения в хосте
    detachInterrupt(sensorInterrupt);
        
    // Поскольку этот цикл может не завершиться ровно за 1 секунду, мы вычисляем
    // количество миллисекунд, прошедших с момента последнего выполнения и использования
    // это для масштабирования выходного сигнала. Мы также применяем калибровочный фактор для масштабирования выходного сигнала
    // исходя из количества импульсов в секунду на единицу измерения (л/мин в
    // в данном случае), исходящее от датчика.
    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;
    
    // Обратите внимание на время выполнения этого прохода обработки. Обратите внимание, что, поскольку мы
    // отключенные прерывания функция millis() на самом деле не будет увеличиваться правильно
    // в этот момент, но он все равно вернет то значение, которое было установлено непосредственно перед этим
    // прерывания исчезли.
    oldTime = millis();
    
    // Разделите расход в литрах в минуту на 60, чтобы определить, сколько литров осталось.
    // прошел через датчик в этом 1-секундном интервале, затем умножьте на 1000, чтобы
    // преобразовать в миллилитры.
    flowMilliLitres = (flowRate / 60) * 1000;
    
    // Добавьте миллилитры, переданные за эту секунду, к общему итогу
    totalMilliLitres += flowMilliLitres;
      
    unsigned int frac;
    
    // Вывести скорость потока за эту секунду в литрах / минуту
    Serial.print("Flow rate: ");
    Serial.print(int(flowRate));  // Print the integer part of the variable
    Serial.print("L/min");
    Serial.print("\t");       // Print tab space

    // Вывести совокупное общее количество литров, вытекших с момента запуска
    Serial.print("Output Liquid Quantity: ");        
    Serial.print(totalMilliLitres);
    Serial.println("mL"); 
    Serial.print("\t");       // Пространство вкладок печати
  Serial.print(totalMilliLitres/1000);
  Serial.print("L");



   
      lcd.clear();
      lcd.setCursor(4,0);
      lcd.print(int(flowRate));  // Вывод целочисленной части переменной
      lcd.print("L/min ");

    // Вывести совокупное общее количество литров, вытекших с момента запуска
    lcd.setCursor(2,1);
    lcd.print("Total ");        
  lcd.print(totalMilliLitres/1000.00);
  lcd.print("L");

    // Сброс счетчика импульсов, чтобы мы могли снова начать инкрементацию
    pulseCount = 0;
    
    // Снова включите прерывание теперь, когда мы закончили посылать выходные данные
    attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
  }
}

/*
Insterrupt Service Routine
 */
void pulseCounter()
{
  // Инкремент счетчика импульсов
  pulseCount++;
}'''

 

, 👍1


2 ответа


1

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

Сначала рассмотрим предпосылки, которые необходимы для двух датчиков потока. Вы уже определили контакты датчиков потока. Вы также определяете количество соответствующих прерываний. На самом деле вам не нужно этого делать. Вы можете легко получить номер прерывания через функцию digitalPinToInterrupt(pin). Таким образом, мы остаемся с определением контакт. Я бы предложил использовать более четкие имена:

int flow_out_pin = 2;
int flow_in_pin = 3;

flow_out означает выход из резервуара, flow_in возвращается в резервуар.

Затем в setup() нам нужно инициировать контакты. У вас есть это

pinMode(sensorPin, INPUT);
digitalWrite(sensorPin, HIGH);

Это может быть затем сделано короче в одной строке на датчик:

pinMode(flow_out_pin, INPUT_PULLUP);
pinMode(flow_in_pin, INPUT_PULLUP);

Теперь прикрепляем прерывания к штифтам:

attachInterrupt(digitalPinToInterrupt(flow_out_pin), flowOutPulseCounter, FALLING);
attachInterrupt(digitalPinToInterrupt(flow_in_pin), flowInPulseCounter, FALLING);

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

void flowOutPulseCounter()
{
    flowOutPulseCount++;
}
void flowInPulseCounter()
{
    flowInPulseCount++;
}

Переменные count, конечно, должны быть определены (глобально в верхней части скетча):

volatile byte flowOutPulseCount = 0;
volatile byte flowInPulseCount = 0;

Теперь мы оставили код в loop(), Который вычисляет скорость потока, уровень заполнения и т. Д. И Отображает их. Во-первых: При обработке данных прерываний в основном коде вы хотите полностью свести к минимуму время, проведенное с отключенными прерываниями (так как за это время вы можете пропустить импульсы и тем самым ввести ошибки). Обычно вы просто копируете данные в локальные переменные, снова включаете прерывания и выполняете расчет с локальными переменными. Что-то вроде этого (внутри оператора millis() if):

// Отсоединение прерываний
detachInterrupt(digitalPinToInterrupt(flow_out_pin));
detachInterrupt(digitalPinToInterrupt(flow_in_pin));

// copy pulse count variables
byte local_flow_out_count = flowOutPulseCount;
byte local_flow_in_count  = flowInPulseCount;

// сброс переменных счетчика импульсов
flowOutPulseCount = 0;
flowInPulseCount = 0;

// Reattach interrupts
attachInterrupt(digitalPinToInterrupt(flow_out_pin), flowOutPulseCounter, FALLING);
attachInterrupt(digitalPinToInterrupt(flow_in_pin), flowInPulseCounter, FALLING);

// Выполните вычисления с использованием указанных выше локальных переменных и отобразите результаты
...

Для расчетов вы затем рассчитаете расход и общий поток от каждого отсчета импульсов. Затем вы можете рассчитать общий чистый расход и уровень заполнения.

Примечание: Вы можете изменить тип переменной для счетчиков на unsigned int, чтобы получить большую маржу, прежде чем они переполнятся, так как это будет означать неправильные результаты, и вам не повредит использовать его.

,

Спасибо за отличный ответ. Я проработал ваши предложения и добрался до: счетчик импульсов потока пустот() { Счетчик импульсов потока++; } счетчик импульсов потока пустот() { flowInPulseCount++; } Но я получаю "определение функции здесь запрещено до ошибки" {"маркер"". Что я на самом деле даже отдаленно не понимаю., @SV Savannah

Это означает, что либо вы поместили эти функции в другую функцию, что неверно, либо у вас несоответствующие фигурные скобки в коде над этими функциями, @chrisl


0

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

Переменная pulseCount имеет размер всего 8 бит. Он переполнится, если скорость потока превысит 33,7 л/мин. Если существует вероятность того, что фактический поток превышает эту скорость, то, как указано в ответе крисла, вам следует использовать 16-битный счетчик. Если, с другой стороны, вы уверены , что это значение не может быть превышено, то вы можете сохранить 8-битный счетчик и извлечь выгоду из того факта, что доступ к 8-битным значениям является атомарным. Это означает, что вам никогда не нужно отключать прерывания:

// В глобальном масштабе:
byte oldPulseCount;

// Внутри цикла(), один раз в секунду:
byte newPulseCount = pulseCount; // атомарное чтение
byte pulseCountDifference = newPulseCount - oldPulseCount;
oldPulseCount = newPulseCount; // сохранить текущее значение

затем вы вычисляете скорость потока из pulseCountDifference. Обратите внимание, что переполнения pulseCount безвредны, так как разница newPulseCount - oldPulseCount переносит значение по модулю 256 в правильное значение. Обратите внимание также, что pulseCount никогда не сбрасывается, так как это может привести к неправильному подсчету всякий раз, когда прерывание срабатывает после считывания pulseCount, но до его сброса.

// Обратите внимание на время выполнения этого прохода обработки. Обратите внимание, что потому что
// мы отключили прерывания, функция millis() на самом деле не будет
// увеличиваться прямо в этот момент, но она все равно вернет значение
// он был установлен как раз перед тем, как исчезли прерывания.
oldTime = millis();

Это замечание неверно. Оператор detachInterrupt(sensorInterrupt) отключает только внешнее прерывание. Он не отключает прерывания глобально и, в частности, не отключает прерывание таймера, которое увеличивает millis(). Поэтому нет никакой гарантии, что различные вызовы millis() вернут одно и то же значение в течение одной итерации. Вместо этого millis() следует вызывать только один раз, и его значение запоминается:

void loop()
{
    unsigned long now = millis();  // save this value
    if (now - oldTime >= 1000) {
        // ...
        oldTime = now;
    }
}

Обратите внимание, что я использую >=> для проверки задержки: с оператором >> период составляет не менее 1001 мс.

flowMilliLitres = (flowRate / 60) * 1000;

Это неверно. Так и должно быть

flowMilliLitres = (flowRate / 60) * (now - oldTime);

по той же причине, по которой сейчас - oldTime используется при вычислении расхода. Можно отметить, что это может быть упрощено до

flowMilliLitres = (1e3/calibrationFactor/60) * pulseCountDifference;

как факторы теперь - старое время отменяются.

,