Simultaneously Counting Hall Sensor Rises and Reading Dallas Temperature Sensors

Hey everyone,

I've encountered a puzzling issue with my Arduino setup that involves Dallas temperature sensors and a flow rate sensor in a water system. In my sketch, I'm trying to retrieve the inlet temperature, outlet temperature, and the amount of water flowing through the system. To achieve this, I've built a system using two Dallas temperature sensors and a flow rate Hall sensor.

Here's where the problem arises: when I comment out the line of code responsible for temperature querying, the displayed flow rate appears to be accurate. However, when that line isn't commented out, the displayed flow rate becomes too high. Moreover, the temperature sensor querying process takes a considerable amount of time, which I suspect is normal with this sensors but might be related to the issue.

enum State {
  STATE_INITIAL,
  STATE_IDLE,
  STATE_RUNNING,
  STATE_ERROR
};

#include <OneWire.h>
#include <DallasTemperature.h>


#define ONE_WIRE_BUS 4 // Temerature sensors wire is plugged into digital pin 4 on the Arduino
OneWire oneWire(ONE_WIRE_BUS);	// Setup a oneWire instance to communicate with any OneWire device
DallasTemperature TempSensors(&oneWire); // Pass oneWire reference to DallasTemperature library

const int nHallSensorPin = 3; // Digital input connected to the Hall sensor (flow meter)

const float fImpulsesPerLiter = 391.0; // Impulses per liter of flow meter

volatile unsigned long nTotalImpulses = 0; // Total impulses counted 

float fTotalVolume;
float fTapTempGaugeValue;
float fInletTempGaugeValue;
float fTotalLiters = 0.0; // Total liters flowed through

float fInletTemp;
float fTapTemp;

State currentState = STATE_INITIAL;

void updateState() {
  switch (currentState) {
    case STATE_INITIAL:
        // ...
        currentState = STATE_IDLE;
      break;
      
    case STATE_IDLE:
        // ...
        currentState = STATE_RUNNING;
      break;
      
    case STATE_RUNNING:
        TempSensors.requestTemperatures();   // Send command to all the sensors for temperature conversion
        fTapTemp = TempSensors.getTempCByIndex(0);
        fInletTemp = TempSensors.getTempCByIndex(1);
        fTotalVolume = nTotalImpulses / fImpulsesPerLiter;
        Serial.println(fTotalVolume);
        //currentState = STATE_INITIAL;
      break;
      
    case STATE_ERROR:
        // ...
      break;
  }
}

void setup() {
  TempSensors.begin();
  Serial.begin(9600);
  pinMode(nHallSensorPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(nHallSensorPin), countPulses, RISING); // Interrupt for rising edges
}

void loop() {
  updateState();
  delay(10);
}

void countPulses() {
  nTotalImpulses++; // Increment the counter for impulses
}

By commenting out theses lines the displayed flow rate is correct:

       // TempSensors.requestTemperatures();   // Send command to all the sensors for temperature conversion
        // fTapTemp = TempSensors.getTempCByIndex(0);
        // fInletTemp = TempSensors.getTempCByIndex(1);

I'm curious if anyone has encountered a similar problem and whether there might be an efficient way to parallelize this code. It seems like there might be a bottleneck caused by the delay in querying the temperature sensors, impacting the accuracy of the flow rate measurement. Does anyone have suggestions or insights on how to optimize this process or parallelize the code effectively?

Any help or guidance would be greatly appreciated!

Thanks in advance!

As is shown in the datasheet and the documentation of the library there are different settings for reading the sensor, different conversion times mainly. The longest and most precise setting takes 750 ms I remember. This can be set.

You can also set the library to not wait for the conversion to complete, but jump back to your code immediately. You have to come back to the sensor later (you know how long it's going to take) and then read the temperature from it.

The code snippet you posted is unfortunately utterly useless to give any suggestions on how to improve it, because as always with snippets the problem is in the part you left out.

the flow is managed through interrupts so it should work but the loop is indeed stuck for a long time reading the sensors

you need to "prime the pump" and launch an asynchronous sampling of the sensors in the setup and then in the loop check if the sensor is ready for reading, in which case you read the T° and then relaunch an asynchronous sampling

You appear to be on the wrong tram altogether for measuring flow rate. There are many examples for doing this, all much the same, and I bet you don't have good reason for departing from them.
The one I use was derived from here
Jaycar Water Flow Gauge | Freetronics

I have tested the posted code individually to make sure that nothing is missing. I have just tested it again. It shows exactly the behavior I described.

Thanks for the tip! I have modified the code as follows.

enum State {
  STATE_INITIAL,
  STATE_IDLE,
  STATE_RUNNING,
  STATE_ERROR
};

#include <OneWire.h>
#include <DallasTemperature.h>


#define ONE_WIRE_BUS 4 // Temerature sensors wire is plugged into digital pin 4 on the Arduino
OneWire oneWire(ONE_WIRE_BUS);	// Setup a oneWire instance to communicate with any OneWire device
DallasTemperature TempSensors(&oneWire); // Pass oneWire reference to DallasTemperature library

const int nHallSensorPin = 3; // Digital input connected to the Hall sensor (flow meter)

const float fImpulsesPerLiter = 391.0; // Impulses per liter of flow meter

volatile unsigned long nTotalImpulses = 0; // Total impulses counted 
volatile unsigned long lastTime = 0;
int conversiontime = 750;


float fTotalVolume;
float fTapTempGaugeValue;
float fInletTempGaugeValue;
float fTotalLiters = 0.0; // Total liters flowed through


float fInletTemp;
float fTapTemp;

State currentState = STATE_INITIAL;

void updateState() {
  switch (currentState) {
    case STATE_INITIAL:
        // ...
        currentState = STATE_IDLE;
      break;
      
    case STATE_IDLE:
        // ...
        currentState = STATE_RUNNING;
      break;
      
    case STATE_RUNNING:
      if ( millis() - lastTime > conversiontime)
      {
        fTapTemp = TempSensors.getTempCByIndex(0);
        fInletTemp = TempSensors.getTempCByIndex(1);
        TempSensors.requestTemperatures();
        lastTime = millis();
        Serial.println("Reading Temps");
   
      }
        fTotalVolume = nTotalImpulses / fImpulsesPerLiter;
        Serial.println(fTotalVolume);
        //currentState = STATE_INITIAL;
      break;
      
    case STATE_ERROR:
        // ...
      break;
  }
}

void setup() {
  TempSensors.begin();
  lastTime = millis();
  TempSensors.setWaitForConversion(false);
  TempSensors.requestTemperatures();

  Serial.begin(9600);
  pinMode(nHallSensorPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(nHallSensorPin), countPulses, RISING); // Interrupt for rising edges
}

void loop() {
  updateState();
  delay(100);
}

void countPulses() {
  nTotalImpulses++; // Increment the counter for impulses
}

Indeed, the waiting times are no longer present. Unfortunately, the problem with the incorrectly measured total quantity remains.

this should be in a critical section

does your flow rate Hall sensor requires a pullup or pull-down? are you sure RISING is the correct trigger ?

Thank you very much! I have looked at the linked code. Of course, this code contains much more than just measuring the total flow amount, but I am of the opinion that the determination of the total flow amount is implemented in my code in exactly the same way as in your example.

My sketch is only about the quantity. Not the speed. Since English is not my native language, I may have expressed myself incorrectly in my initial post.

not really. see this part

  pinMode(sensorPin, INPUT);
  digitalWrite(sensorPin, HIGH);
  attachInterrupt(sensorInterrupt, pulseCounter, FALLING);

that's what I was referring to earlier, the sensor is connected to a pin set as INPUT_PULLUP and triggers on a the falling edge.

you have

➜ so your pin might be floating and you trigger on RISING edge

I have also noticed that the sketch also shows a drift in the total flow rate. I have just tested and found out that the quantity drifts by 0.24 liters / 10 minutes. This does not happen if I comment out the 3 lines regarding the temperature output

Okay, I'll check that out. According to the manufacturer of the flow meter, I don't need either a pull-up or a pull-down resistor.

I tested it by switching to trigger on falling edge. This does not change the incorrectly measured quantity nor the drift. I have not changed pull up / pull down, as this is not needed according to the manufacturer. In addition, the hardware setup also works when there is no temperature request.

OK it's possible that there is relevant hardware inside your sensor and that you get a clear signal LOW or HIGH out and no bouncing.

Do you have a link to the sensor you use?

what's your Arduino? UNO R3?

Arduino Uno (Rev 1)

https://www.engolit.de/produkte/durchfluss-messturbine-mit-funktionsanzeige/

https://www.engolit.de/produkte/durchfluss-messturbine-mit-funktionsanzeige/

First generation? is it still working ???

regarding your sensor

Im Oberteil der Durchfluss-Messturbinen befindet sich die Funktionsanzeige, die je nach Typ der Durchfluss-Messturbine mit 1 oder 2 Leuchtdioden ausgestattet sind. Die rote Leuchte zeigt ein Impulsaufkommen an. Die grüne Leuchtdiode zeigt an, ob sich in der Leitung eine Flüssigkeit befindet

➜ do you have the leds ? does the red one shows a pulsing signal when you get a liquid flowing?

Yes still works fine! :slight_smile:

I have the DM-04 version without the green LED because I don't have an empty cut-off (I hope this is the right translation for "Leerabschaltung").

The red LED flashes as it should. As I said, the setup works without any problems if I leave out "requestTemperatures" and "getTemp".

Even the async method of reading one ds18b20 blocks for about 25 ms. Could be related to your problem.

This might be it! After implementing the async method the error got smaller but didn’t resolve completely.

Does anyone have an idea how to get around this?

Probably use an analog temperature sensor like an LM34 that you can convert faster.

Hardware changes would be the worst case! The whole machine is fully built. The temperature sensors are already glued into fittings and sealed.
I really hope that there is a software solution.