The YF-S201 is a ½-inch inline water flow meter: a small turbine with a magnet inside and a Hall sensor that sends one pulse per magnet pass. Counting pulses gives flow rate and total volume. It suits pump monitors, measuring how many litres go into the overhead tank, or a dispenser that stops at 1 litre.
On the Uno the yellow signal wire goes to D2, because counting must happen in an interrupt — at full flow there are over 200 pulses a second. The sensor runs from 5V, and its output switches to 5 V, the Uno’s own logic level.
The sketch counts pulses in an interrupt and once a second prints the flow in litres per minute and the running total. Calibrate it with a bucket once, and it stays within a few percent.
Wiring
| Arduino Uno R3 | YF-S201 water flow sensor (½″) | Wire | Notes |
|---|---|---|---|
| 5V | VCC | red | Red wire. |
| GND | GND | black | Black wire. |
| D2 | SIG | yellow | Yellow wire. D2 = INT0, so no pulse is missed even while the sketch prints. |
5–18 V (use 5 V) part, 5 V board. Powered from 5 V, the pulse output can swing close to 5 V. On ESP32 and Pico feed SIG through a 10 kΩ / 20 kΩ divider (or a 1 kΩ / 2 kΩ one). On Uno connect it directly.
Board quirks
- Pulses come at up to about 225 per second at full flow. Polling with
digitalRead()misses many; the sketch counts them in an interrupt on D2, one of only two interrupt pins on the Uno (D2, D3). - The often-quoted 7.5 Hz per L/min (450 pulses per litre) is only typical. Run exactly 10 litres into a bucket, note the total pulses, and set
PULSES_PER_LITREto pulses ÷ 10. - Below about 1 L/min the rotor barely turns, so slow drips aren’t counted. It suits a tap, a pump outlet or the pipe filling an overhead tank, not leak detection.
- The housing is for water up to about 1.75 MPa and 80 °C. The electronics are sealed but the connector isn’t — keep it dry and above the pipe.
pulsesis a 4-byte variable changed inside an interrupt, so the sketch copies it with interrupts briefly off. Reading it directly can give a corrupt number on an 8-bit Uno.
Code
// YF-S201 water flow sensor on an Arduino Uno R3.
// Red (VCC) → 5V, black (GND) → GND, yellow (SIG) → D2 (external interrupt INT0).
// About 7.5 pulses per second for every litre per minute, ~450 pulses per litre.
const uint8_t FLOW_PIN = 2;
const float PULSES_PER_LITRE = 450.0; // calibrate with a bucket - see the guide
volatile unsigned long pulses = 0;
unsigned long lastPulses = 0;
unsigned long lastCalc = 0;
void onPulse() { pulses++; }
void setup() {
pinMode(FLOW_PIN, INPUT_PULLUP); // the Hall output is open-collector on many sensors
attachInterrupt(digitalPinToInterrupt(FLOW_PIN), onPulse, FALLING);
Serial.begin(9600);
Serial.println(F("YF-S201 on D2 - open the tap"));
}
void loop() {
if (millis() - lastCalc < 1000) return;
lastCalc = millis();
noInterrupts();
unsigned long total = pulses; // copy safely: a 4-byte value can change mid-read
interrupts();
unsigned long perSecond = total - lastPulses;
lastPulses = total;
float lpm = perSecond * 60.0 / PULSES_PER_LITRE;
Serial.print(F("Flow "));
Serial.print(lpm, 2);
Serial.print(F(" L/min Total "));
Serial.print(total / PULSES_PER_LITRE, 2);
Serial.println(F(" L"));
}// YF-S201 water flow sensor on an Arduino Uno R3.
// Red (VCC) → 5V, black (GND) → GND, yellow (SIG) → D2 (external interrupt INT0).
// About 7.5 pulses per second for every litre per minute, ~450 pulses per litre.
const uint8_t FLOW_PIN = 2;
const float PULSES_PER_LITRE = 450.0; // calibrate with a bucket - see the guide
volatile unsigned long pulses = 0;
unsigned long lastPulses = 0;
unsigned long lastCalc = 0;
void onPulse() { pulses++; }
void setup() {
pinMode(FLOW_PIN, INPUT_PULLUP); // the Hall output is open-collector on many sensors
attachInterrupt(digitalPinToInterrupt(FLOW_PIN), onPulse, FALLING);
Serial.begin(9600);
Serial.println(F("YF-S201 on D2 - open the tap"));
}
void loop() {
if (millis() - lastCalc < 1000) return;
lastCalc = millis();
noInterrupts();
unsigned long total = pulses; // copy safely: a 4-byte value can change mid-read
interrupts();
unsigned long perSecond = total - lastPulses;
lastPulses = total;
float lpm = perSecond * 60.0 / PULSES_PER_LITRE;
Serial.print(F("Flow "));
Serial.print(lpm, 2);
Serial.print(F(" L/min Total "));
Serial.print(total / PULSES_PER_LITRE, 2);
Serial.println(F(" L"));
}Expected serial output
YF-S201 on D2 - open the tap
Flow 0.00 L/min Total 0.00 L
Flow 8.40 L/min Total 0.14 L
Flow 8.53 L/min Total 0.28 LYF-S201 on D2 - open the tap Flow 0.00 L/min Total 0.00 L Flow 8.40 L/min Total 0.14 L Flow 8.53 L/min Total 0.28 L
Common errors
Always 0 L/min with water flowing
SIG not on D2, or the flow arrow on the sensor body points against the flow. Spin the rotor by blowing through it and watch the count.
Flow jumps around
Air bubbles or a pump’s pulsing flow. Average over 5 s instead of 1 s.
Total is 10–20 % off
Calibrate PULSES_PER_LITRE with a bucket of known volume, at the flow rate you normally use.