Why is my Flow sensor picking up disturbance from a connected motor

Hello all,

I'm quite a newbie to Arduino and electronics, but have some background in coding. I'm building a automatic water pump to circulate liquid with a flow sensor and automatic cutoff when the liquid flow stops for 5 seconds (e.g. clogging etc). This topic seems to be quite popular, however I didn't find any answer to the problem I'm encountering.

I have an Arduino Uno that gets flow measurement from this Hall effect sensor:
"Ccylez YF-S401 DC5-24V Water Flow Sensor" (https://www.amazon.de/-/en/gp/product/B08D3NZSS5/ref=ppx_yo_dt_b_asin_title_o03_s03?ie=UTF8&psc=1)

It displays the flow rate on an LCD display. I also have a 6-12V pump controlled by the Arduino via a L293D chip: "Elecrow DIY61289P - 6-12V R385 DC Diaphragm Pumps"
There is a potentiometer that defines the voltage supplied to the pump by the L293D.
There is also a simple LED and reset/restart button that can be used to restart the flow sensor and motor.
My setup seems to work perfectly when powered via the Arduino USB (5V):
-Flow sensor reads values via the interrupt pin 2,
-potentiometer defines the speed of the pump, (except of course only up to 5V speed),
-screen displays everything correctly and
-if the flow stops for 5sec, the motor is cut off until the restart button is pressed.

BUT:

If I try to power the Arduino with an external 12V DC supply in order to get the full speed range for the pump, the flow sensor starts showing quite high and random ghost readings for flow. In this case I'm supplying the 12V from the Vin on the Arduino into the L293D that should pass it on as regulated by the potentiometer.
I mean there is no actual flow through the sensor but it claims to have some. This occurs if the voltage going to the motor defined with the potentiometer rises above approx 5V.

I'm completely lost here, but I'm quite sure it's not a code issue because everything works beautifully with the 5V input. I'm guessing it's electronics or wiring or something such.

Thank you for all ideas already in advance! :slight_smile:

Here is my code:

[code]
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal_I2C lcd(0x27, 20, 4);

//define sensor
const int sensorInterrupt = 0;  // interrupt 0
const int sensorPin       = 2; //Digital Pin 2
const int alarmPin = 13; // Digital Pin 13 for alarming the user
unsigned int SetPoint = 400; //400 milileter


//define control data
int adcValue; // Define a variable to save the ADC value
int targetValue; // target value for output
int noFlowCount = 0; // time in seconds without flow
boolean noFlow = false;

//define the restarting button
const int resetButtonPin = 4;     // the number of the pushbutton pin
int buttonState;         // variable for reading the pushbutton status


//define motor (pump) control with L293D
int in1Pin = 10; // Define L293D channel 1 pin
int in2Pin = 9; // Define L293D channel 2 pin
int enable1Pin = 11; // Define L293D enable 1 pin
int motorSpd; // Define a variable to save the motor rotation speed
int motorV = 0; //Define a variable to announce the voltage going to the motor


/*The hall-effect flow sensor outputs pulses per second per litre/minute of flow.*/
float calibrationFactor = 90; //You can change according to your datasheet

volatile byte pulseCount = 0;

float flowRate = 0.0;
unsigned int flowMilliLitres = 0;
unsigned long totalMilliLitres = 0;
unsigned long oldTime = 0;


void setup()
{

  // Initialize a serial connection for reporting values to the host
  Serial.begin(9600);

  //initialize motor control pins
  pinMode(in1Pin, OUTPUT);
  pinMode(in2Pin, OUTPUT);
  pinMode(enable1Pin, OUTPUT);

  pinMode(alarmPin, OUTPUT);
  digitalWrite(alarmPin, LOW); //shut the alarm led
  // initialize the pushbutton pin as an input:
  pinMode(resetButtonPin, INPUT);


  //initialize flow sensor
  pinMode(sensorPin, INPUT_PULLUP); //TRYING THE PULLUP VERSION!!!!!
  digitalWrite(sensorPin, HIGH);

  // analogWrite(motorPin, targetValue);

  /*The Hall-effect sensor is connected to pin 2 which uses interrupt 0. Configured to trigger on a FALLING state change (transition from HIGH
    (state to LOW state)*/
  attachInterrupt(sensorInterrupt, pulseCounter, FALLING); //you can use Rising or Falling


  // initialize the lcd-screen
  lcd.init();
  lcd.backlight(); // Turn on backlight
  lcd.print("Julius"); // Print a message to the LCD
  lcd.setCursor(0, 3); // set the cursor to column 0, line 1
  lcd.print("Flow pump 1.1"); // Print a message to the LCD
  delay(2000);
  lcd.clear();

}

void loop()
{

  // read the state of the resetbutton value:
  buttonState = digitalRead(resetButtonPin);
  //Serial.print("Button state: ");
  //Serial.println(buttonState);
  if (buttonState == LOW) { // check if the pushbutton is pressed. If it is, the buttonState is LOW, by default the buttonState is HIGH:
    // turn LED off:
    digitalWrite(alarmPin, LOW);
    noFlowCount = 0;
    noFlow = 0;

  }

  //detect potentiometer, so desired speed for motor
  targetValue = analogRead(A0);
  motorSpd = map(targetValue, 0, 1023, 0, 255);
  motorV = map(targetValue, 0, 1023, 0, 13);


  if (noFlowCount > 5) // test if there is liquid for pumping and light the alarm led
  {
    noFlow = true;
    //analogWrite(enable1Pin, 0);
    digitalWrite(alarmPin, HIGH);

    //shut down the motor
    motorSpd = 0;
    motorV = 0;

    // for debugging purposes
    // Print the time that the pump has been withouth fluid
    Serial.print("Out of liquid!\t");
    Serial.print("No flow time: ");
    Serial.print(noFlowCount);
    Serial.println(" sec");

  }

  // LCD Print the voltage of the motor, after calibration will be changed to the desired flow rate.
  lcd.setCursor(0, 3); // set the cursor to column 0, line 1
  lcd.print("Motor V: ");
  lcd.print(motorV);

  // drive motor
  digitalWrite(in1Pin, LOW);
  digitalWrite(in2Pin, HIGH);
  analogWrite(enable1Pin, motorSpd); //transfer the correct voltage to the motor


  if ((millis() - oldTime) > 1000)   // Only process counters once per second
  {
    // Disable the interrupt while calculating flow rate and sending the value to the host
    detachInterrupt(sensorInterrupt);

    // Because this loop may not complete in exactly 1 second intervals we calculate the number of milliseconds that have passed since the last execution and use that to scale the output. We also apply the calibrationFactor to scale the output based on the number of pulses per second per units of measure (litres/minute in this case) coming from the sensor.
    flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;

    // Note the time this processing pass was executed. Note that because we've
    // disabled interrupts the millis() function won't actually be incrementing right
    // at this point, but it will still return the value it was set to just before
    // interrupts went away.
    oldTime = millis();

    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in this 1 second interval, then multiply by 1000 to
    // convert to millilitres.
    flowMilliLitres = (flowRate / 60) * 1000;

    // Add the millilitres passed in this second to the cumulative total
    totalMilliLitres += flowMilliLitres;

    unsigned int frac;

    if (flowMilliLitres == 0)
    {
      noFlowCount++;
    }
    else {
      noFlowCount = 0;
    }

    // Print debugging information on the serial monitor.
    // Print the flow rate for this second in litres / minute
    Serial.print("Flow rate: ");
    Serial.print(flowMilliLitres, DEC);  // Print the integer part of the variable
    Serial.print("mL/Second");
    Serial.print("\t");

    // Print the cumulative total of litres flowed since starting
    Serial.print("Output Liquid Quantity: ");
    Serial.print(totalMilliLitres, DEC);
    Serial.print("mL");
    Serial.print("\t");

    // Print the voltage going to the motor
    Serial.print("Motor V: ");
    Serial.print(motorV);  // Print the integer part of the variable
    Serial.print("\t");

    // Print the time without flow
    Serial.print("No flow: ");
    Serial.print(noFlowCount);
    Serial.println(" sec");

    // Display the relevant flow and motor speed information on the LCD screen.
    // LCD Print the flow rate for this second in litres / minute

    if (noFlow) {
      //alert the user
      lcd.clear();
      lcd.print("Julius Flowpump 1.1"); // Print a message to the LCD
      lcd.setCursor(0, 1); // set the cursor to column 0, line 1
      lcd.print("Out of Liquid! ");
      lcd.print(noFlowCount);
      lcd.print(" s");

    } else {

      lcd.clear();
      lcd.print("Julius Flowpump 1.1"); // Print a message to the LCD
      lcd.setCursor(0, 1); // set the cursor to column 0, line 1
      lcd.print("Flow: ");
      lcd.print(flowMilliLitres, DEC);  // Print the integer part of the variable
      lcd.print(" mL/s");
      lcd.setCursor(0, 2); // set the cursor to column 0, line 1
      lcd.print("Total flow: ");
      lcd.print(totalMilliLitres, DEC);  // Print the integer part of the variable
      lcd.print(" mL/s");

    }


    // Reset the pulse counter so we can start incrementing again
    pulseCount = 0;

    // Enable the interrupt again now that we've finished sending output
    attachInterrupt(sensorInterrupt, pulseCounter, FALLING);

  }

}


//Interrupt Service Routine

void pulseCounter()
{
  // Increment the pulse counter
  pulseCount++;
}


[/code]

Here is my schematic: Sorry I'm not a pro, but tried to get everything there as it is on my breadboard. (Pls don't mind the LCD not connected to it's serial controller there, that is not the issue.)

Don't try to run the Arduino from 12V, for several reasons (one being that it is severely contaminated by motor electrical noise).

Get a 5V step down converter and apply the 5V to the Arduino 5V pin. Use that to power the sensor and display as well.

1 Like

Thank you for this information! I'll try it and report back if it does. :slight_smile:

Why a Zener diode across the motor terminals and why no small value disk ceramic capacitor?

Tutorial on reducing motor noise: Pololu - 9. Dealing with Motor Noise

1 Like

I don't see any decoupling capacitors on the IC's or for that matter across the variable resistor.

These are important as any IC is prone to noise problems, regardless of a motor being attached.

Now we come to the motor, given I have no idea why you have connected this in such a fashion, have a look here for common connection types. L293D data sheet, product information and support | TI.com

As far as the Voltage levels are concerned, you could use one of these https://www.amazon.co.uk/DollaTek-three-terminal-regulator-instead-5-5-32V/dp/B081JMJZG6/ref=sr_1_3?keywords=5v+regulator&qid=1666736073&qu=eyJxc2MiOiI0LjE5IiwicXNhIjoiMy44NyIsInFzcCI6IjMuNTQifQ%3D%3D&sr=8-3

12V to 5V regulator can throw out some heat and is not great for battery operations, where power drain is at a premium.

As far as the program is concerned you are using millis() without assigning its value to a variable. You may think it is fine, but even running one line of code in C is a delay before the next time it is read.
I will read more later

1 Like

It's to remove kickback voltage from the motor when it's shut off. I've read that it would be a way to handle it. I could replace it with a capacitor (0.1uF ?), can you pls point to me why it is better? Sorry, I'm quite new to electronics.

It seems I'm not familiar enough with using capacitors and they were not in the tutorial I based this on, but I'll look into this. Also possibly changing the Zener diode to a capacitor as @Paul_KD7HB suggested.

I connected it in the same fashion as the motor tutorial in the FreeNove Arduino starter kit. It's there connected as such (potentiometer and L293D wise).

Thank you for the suggestion on the regulator. I'll definitely try that after I get it to work with the 12-5V reg i have now.

This interrupt handling code and millis() -use is from a tutorial for a flow meter system. It's quite possible it's not optimal for performance, so I'll try using a variable here.

@jremington Thank you for the link to the motor noise tutorial, I'll check it out.

The zener is there as what you call a free wheeling diode.
A motor becomes a generator once power is removed. With a pmw wave controlling the motor, this results in spikes of power in the opposite direction on every mark to space change. The purpose of the diode is to short out this reverse current which is generated from the removal of power to the motor on every change. Or in this case when you are activating out 1
Adding a capacitor across the motor may help in achieving this, but it is not really needed, the diode being more important.

I have not seen that project, but will look into that.

My worry with the layout was with the program that pulls out 2 high, and the fact that it is actually connected through the IC to12V (through the output drive) and controlling the speed by taking out 1 low-high.

I can only think it has been done in this way to isolate the motor from any noise to the supply Voltage

Designing with Motors is a skill in itself, which many fail to understand properly when they are learning.

I do not see where you are getting the 5V power from on that schematic, however pins 4,5,12,13 should all be connected together for correct grounding.

1 Like

How close is the motor to the hall sensor?

Thank you for the Zener diode explanation. That was my vague understanding of it's purpose, but I understand it more now. :slight_smile: Also I now understand the difference in purpose to the capacitor. I'm thinking of keeping the zener then, but would try adding some capacitors for extra noise canceling as they seem to do that.

Unfortunately I cannot give a sure reason for that. :smiley: This layout of the motor tutorial works well (seems to) with a 5V motor, so when drawing the 5V from the Arduino 5v pin. It's my idea to try to apply it to a 12V motor, so it's quite possible I will have to change the design because of that to be something else. I will look into that motor tutorial for insight.

I will definitely connect these pins together.

I'm sorry it seems I had drawn wrongly in the schematic about the 5v coming into pin 16 of L239D. It's going to Pin 9 (not 16) from the Arduino 5v pin and is like that on my breadboard, just wrong in the schematic. I'll just edited it regarding that immediately, thank you so much for noticing this!

@Idahowalker

Currently it's approx 30cm away, but I'd like to have them closer to each other.

The motor may generate fields that may be picked up by the hall, something to keep in mind.

Use a standard silicon diode that can carry the current being generated by the motor. The capacitor on the motor terminals is there to short out the spikes generated by the arcing between the brushes and the motor armature.

1 Like

Right! Now I understand your previous message better. Thank you! :slight_smile:

I see you are getting the 5V from the 328P which has ~50mA limit.

Not a way I would do it, but given the notes say a maximum of between 6V - 20V on Vin and they use an LDO to derive the 5V supply, then there should not be any problems providing you decouple the lines.
I tended to use a 10uF tant capacitor with a 100n ceramic across it for all IC supplies as close to the power pin as possible.

As far as the diode is concerned, this has to be a zener diode of the correct Voltage across the motor, given you are driving the motor with the outputs from the bridge. Each output can deliver 600mA of current for the L293D, so that is the maximum current for the motor.

Placing a normal diode, with its 0.7V forward drop, other than the 4.7V 1W zener would create a virtual short across the outputs of the L293 D . Which may destroy the chip.

Hello again.
I have now updated the schematic and tested with adding capacitors. If you think I should add more of them, then I'd like to ask for concrete suggestions on positioning them as I still don't understand the fine points with them.

The noise from the motor is now gone and the sensor seems to measure correctly. I had an issue where the Arduino would boot after the motor had stopped due to the no-flow condition and subsequently the reset button was pressed. For 2-3 times it worked by resuming giving the designated voltage to the motor, but then it started reseting the Arduino every time it hit the no-flow condition.
This was quite confusing, but got solved (at least seems to) by upping the Vin to the Arduino from the converter to 6V instead of a tight 5V. Also I routed the Voltage for all components directly from the converter instead of from the Arduino 5V pin.

The code I've kept the same for now as i wanted to first solve the electronic issues.
Please comment again and thank you so much for the help!
New Schematic:

You need to be more careful when drawing schematics.
Make sure you read the data sheet for the components you are going to use and follow the guidelines given.

This is not a simple regulator, but a switching regulator that needs external components and a feedback component after an output clamped zener and filter stage.

The DC 12V switch will just short to ground as you have drawn it and the Zener across the motor is the wrong way around.

Since the motor is only supposed to run in one direction, it should not be in the H bridge configuration.
If voltage is reversed (that is what an H bridge is for) your zener, capacitor, H bridge and or power supply may burn.
With motors electrolytic capacitors are not good.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.