← ESP32 PLC Flow Measurement with a Pulse Flow Meter
Hydraulic moving floor (BLE app)ESP32 PLC 38RGPIOAcquisition
ESP32 PLC Flow Measurement with a Pulse Flow Meter — full example
Measure oil flow in L/min from a magnetic pulse sensor on an ESP32 PLC 38R. Interrupt timing, K-factor math, presence detection and full Arduino code.
Complete, runnable program for the ESP32 PLC 38R (pulse-flow-meter-38r.ino): wiring header, requirements and integration notes included.
Download the full project pack — freeThis example + the related ones + bill of materials
Read-only preview.
/*
* COMPLETE EXAMPLE — Flow rate from magnetic/inductive sensor pulses
*
* Hardware: ESP32 PLC 38R (Industrial Shields)
* Based on: hydraulic moving floor project, main.cpp (flow measurement)
*
* Wiring:
* I0_0 Inductive detector of the flow meter (1 pulse per turbine turn)
* I0_1 Flow meter presence signal (HIGH = sensor connected)
*
* Logic:
* - Each detector pulse is timed by interrupt (micros()).
* - The period between pulses is converted to L/min using the flow
* meter K factor (pulses per liter).
* - If no pulses arrive within FLOW_TIMEOUT_MS, flow is considered 0.
* - If the presence signal drops, the sensor is flagged as disconnected
* (validity flag, same pattern as the 4-20 mA sensors in this catalog).
*
* Integration with other catalog modules:
* - The flow rate can be notified over BLE in the [F]liters_min frame
* (see ejemplos/piso-movil/ble-mobile-app-control-38r.ino).
* - The accumulated volume can be persisted in NVS
* (see ejemplos/piso-movil/nvs-persistent-counters-38r.ino).
*/
#define PIN_PULSES I0_0 // inductive detector
#define PIN_PRESENCE I0_1 // flow meter presence
#define PULSES_PER_LITER 45.0 // flow meter K factor (adjust)
#define FLOW_TIMEOUT_MS 3000 // no pulses in 3 s -> flow 0
// Variables shared with the ISR: always volatile
volatile uint32_t lastPulseUs = 0; // instant of the last pulse
volatile uint32_t periodUs = 0; // period between the 2 last pulses
volatile uint32_t totalPulses = 0; // accumulated total for volume
float flowLmin = 0.0; // computed flow rate in L/min
float volumeL = 0.0; // accumulated volume in liters
bool sensorOk = false;
// ISR: timing only, no Serial and no heavy float math here
void IRAM_ATTR pulseIsr() {
uint32_t now = micros();
if (lastPulseUs != 0) {
periodUs = now - lastPulseUs;
}
lastPulseUs = now;
totalPulses++;
}
void setup() {
Serial.begin(115200);
pinMode(PIN_PULSES, INPUT);
pinMode(PIN_PRESENCE, INPUT);
attachInterrupt(digitalPinToInterrupt(PIN_PULSES), pulseIsr, RISING);
Serial.println("Pulse flow meter ready (ESP32 PLC 38R)");
}
void loop() {
// 1. Presence: if the signal drops, the flow meter is disconnected
sensorOk = (digitalRead(PIN_PRESENCE) == HIGH);
// 2. Atomic copy of the ISR variables
noInterrupts();
uint32_t period = periodUs;
uint32_t last = lastPulseUs;
uint32_t pulses = totalPulses;
interrupts();
// 3. Flow rate: if too much time has passed since the last pulse, flow is 0
bool hasFlow = (last != 0) &&
(micros() - last) < (FLOW_TIMEOUT_MS * 1000UL);
if (sensorOk && hasFlow && period > 0) {
// pulses/s = 1e6 / periodUs ; L/min = (pulses/s / K) * 60
float pulsesPerSecond = 1000000.0 / (float)period;
flowLmin = (pulsesPerSecond / PULSES_PER_LITER) * 60.0;
} else {
flowLmin = 0.0;
}
// 4. Accumulated volume from the total pulse count
volumeL = (float)pulses / PULSES_PER_LITER;
// 5. Report every second (in the real project this travels over BLE: [F]value)
static uint32_t tLast = 0;
if (millis() - tLast > 1000) {
tLast = millis();
if (!sensorOk) {
Serial.println("[F]ERROR flow meter disconnected");
} else {
Serial.print("[F]");
Serial.print(flowLmin, 1);
Serial.print(" L/min volume=");
Serial.print(volumeL, 2);
Serial.println(" L");
}
}
delay(20);
}
Download the full project pack — freeThis example + the related ones + bill of materials