An Arduino water meter with a YF-S201 flow sensor
Beginner
Or see every lesson.
- 455parts on the bench
- 43boards running now
- 1.00xreal time, on every board
The YF-S201 is the black plastic flow sensor with a half-inch thread at each end and three wires. Inside is a little paddle wheel with a magnet, and a Hall sensor that pulses every time the magnet goes past. The faster the water flows, the faster the pulses come. Count them and you have a water meter.
The circuit above is an Uno with a YF-S201 on pin 2 and a 16x2 I2C LCD. The flow slider starts at 6 liters a minute, and the screen and serial monitor show the flow and the total so far. It runs in your browser on the sketch below.
What you need
- An Arduino Uno
- A YF-S201 water flow sensor
- A 16x2 LCD with an I2C backpack (optional; the serial monitor shows the same)
- A half-size breadboard and jumper wires
Wiring
| Part and pin | Goes to | Note |
|---|---|---|
| Sensor yellow (SIG) | Pin 2 | An interrupt pin on the Uno |
| Sensor red (VCC) | 5 V | Not 12 V when SIG goes straight to the Uno |
| Sensor black (GND) | GND | |
| LCD SDA and SCL | A4 and A5 | Backpack address 0x27 |
| LCD VCC and GND | 5 V and GND |
From pulses to liters
The seller’s listings give one formula: the pulses a second equal 7.5 times the flow in liters a minute. Work it through and 450 pulses make one liter. Every YF-S201 sketch is built on those two numbers.
At 30 liters a minute, the top of the sensor’s range, that is 225 pulses a second. A loop() with delays in it will miss some, so the sketch counts them with an interrupt instead: attachInterrupt() runs a tiny function on every falling edge of pin 2, and that function adds one to a counter.
The yellow wire comes from an open-collector output with its own pull-up resistor to the red wire, so the pulses swing between 0 V and whatever the sensor is powered from. That is why it must run from 5 V when its signal goes straight into an Uno. The sketch still sets INPUT_PULLUP, which does no harm.
The sketch, step by step
Once a second, loop() copies the counter with interrupts paused for a moment, so it never reads a number that is changing. The pulses in that second, times 4 and divided by 3, give the flow in tenths of a liter a minute. All the pulses so far, times 20 and divided by 9, give the total in milliliters. The math is in whole numbers to keep it small and fast on the Uno.
At 6 liters a minute the serial monitor prints "flow 6.0 L/min" and the total grows by 100 ml every second, which is 6 liters a minute exactly. Drag the slider to 15 and the lines move to "flow 15.0 L/min".
const int SENSOR = 2; // the yellow wire
volatile unsigned long pulses = 0;
unsigned long counted = 0; // pulses already turned into flow
unsigned long lastSecond = 0;
void onPulse() {
pulses++;
}
void setup() {
Serial.begin(9600);
pinMode(SENSOR, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(SENSOR), onPulse, FALLING);
}
void loop() {
if (millis() - lastSecond < 1000) return;
lastSecond += 1000;
noInterrupts();
unsigned long all = pulses;
interrupts();
unsigned long thisSecond = all - counted;
counted = all;
unsigned long tenths = thisSecond * 4 / 3;
unsigned long ml = all * 20 / 9;
Serial.print("flow ");
Serial.print(tenths / 10);
Serial.print('.');
Serial.print(tenths % 10);
Serial.print(" L/min, total ");
Serial.print(ml);
Serial.println(" ml");
}How accurate is it?
A real YF-S201 is good to about 10 percent, and it changes with the water pressure and the way it is mounted. The wheel also stops turning below about 1 liter a minute. To calibrate yours, run water through it into a measuring jug, count the pulses for a known volume, and use your number instead of 450.
The simulated sensor’s pulses are exact, so the math here comes out perfect. That is useful for getting the code right, and it is a reason to calibrate the real one.
Try it in the editor
Add a relay that shuts a valve after 2 liters, for a plant waterer or a fill-to-the-line jug. Or add a buzzer that warns when the flow has run for more than five minutes, for a leak alarm.
Common mistakes
Counting pulses with digitalRead() in loop(). At high flow you miss pulses. Use an interrupt on pin 2 or 3.
Forgetting volatile. The counter is changed inside the interrupt, so it must be declared volatile, or the compiler may never see it change.
Powering it from 12 V with SIG wired straight to the Uno. The sensor’s pull-up goes to its own supply, so the pulses reach 12 V. Run it from 5 V.
Mounting it the wrong way. The arrow on the body shows the direction the water must flow.
Questions
How do I connect a YF-S201 to an Arduino?
Red to 5 V, black to GND and yellow to pin 2. Count the falling edges on pin 2 with attachInterrupt(), and divide by 450 for liters.
What is the YF-S201 calibration factor?
7.5: the pulses a second equal 7.5 times the flow in liters a minute, so 450 pulses make a liter. Real sensors vary, so measure yours with a jug for better than 10 percent.
Which pins can count flow pulses on an Uno?
Pins 2 and 3, the two external interrupt pins. On a Mega there are six, and on an ESP32 almost any pin can take an interrupt.
What does Mokxi not model on the flow sensor?
The real sensor’s 10 percent error, the low flow where the wheel stops, the water pressure, and a wheel that keeps spinning for a moment after the tap closes.
Build this for real
Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.