/*
Dual FS300A Flow Meter on Arduino MEGA (ONLY pins 2 and 3)
Sensor: FS300A G3/4
Range : 1–60 L/min
Pulse : ~508 pulses per liter (verify your unit; clones may vary)
What this does:
- Uses ONLY external interrupt pins D2 and D3 on Arduino Mega.
- Counts sensor pulses for 1 second windows, then computes:
* frequency (Hz)
* flow rate (L/min)
* totalized volume (L)
- Works best with RISING edge counting. CHANGE (both edges) is supported via a switch.
Wiring (open-collector Hall output):
- FS300A Vcc → 5V
- FS300A GND → GND
- FS300A signal #1 → D2
- FS300A signal #2 → D3
- We use INPUT_PULLUP so the pin idles HIGH and pulses LOW.
*/
// ---------------- Configuration ----------------
// Datasheet nominal pulses per liter; calibrate if your unit differs.
#define FS300A_PULSES_PER_LITER 508.0f
// Hz → L/min conversion: flow(L/min) = Hz × (60 / PulsesPerLiter)
const float PULSE_TO_LPM = 60.0f / FS300A_PULSES_PER_LITER;
// Edge selection:
// - Leave undefined to count only RISING edges (recommended).
// - Define COUNT_BOTH_EDGES to use CHANGE (both edges); code will divide by 2.
// #define COUNT_BOTH_EDGES
// Pins (MEGA external interrupts): ONLY 2 and 3
const uint8_t FLOW1_PIN = 2; // Sensor channel 1 → D2
const uint8_t FLOW2_PIN = 3; // Sensor channel 2 → D3
// -------------- State (ISR + main) --------------
// Updated in ISRs; must be volatile. 32-bit for headroom.
volatile uint32_t pulse1 = 0; // Pulses collected in the current 1 s window (ch1)
volatile uint32_t pulse2 = 0; // Pulses collected in the current 1 s window (ch2)
// Running totals in liters (floating point).
float totalLiters1 = 0.0f;
float totalLiters2 = 0.0f;
// Timing marker (ms) for 1-second interval
unsigned long tPrev = 0;
// -------------- ISRs --------------
// Keep ISRs short (increment only).
void ISR_Flow1() { pulse1++; }
void ISR_Flow2() { pulse2++; }
// -------------- Setup --------------
void setup() {
Serial.begin(115200);
while (!Serial) { /* wait if native USB; on MEGA this passes immediately */ }
// Open-collector friendly: enable internal pull-ups (idle HIGH, pulse LOW)
pinMode(FLOW1_PIN, INPUT_PULLUP);
pinMode(FLOW2_PIN, INPUT_PULLUP);
#ifdef COUNT_BOTH_EDGES
// Count both edges; we will divide by 2 later
attachInterrupt(digitalPinToInterrupt(FLOW1_PIN), ISR_Flow1, CHANGE);
attachInterrupt(digitalPinToInterrupt(FLOW2_PIN), ISR_Flow2, CHANGE);
#else
// Count a single, clean edge per pulse (recommended)
attachInterrupt(digitalPinToInterrupt(FLOW1_PIN), ISR_Flow1, RISING);
attachInterrupt(digitalPinToInterrupt(FLOW2_PIN), ISR_Flow2, RISING);
#endif
tPrev = millis();
Serial.println(F("FS300A dual-channel flow monitor (MEGA, pins D2 & D3)"));
Serial.println(F("Output: CHx: freq=Hz, flow=L/min, total=L"));
}
// -------------- Main Loop --------------
void loop() {
const unsigned long now = millis();
// Execute once per second
if (now - tPrev >= 1000UL) {
tPrev += 1000UL; // reduces long-term drift
// --- Atomically snapshot and reset counters ---
noInterrupts();
uint32_t c1 = pulse1; pulse1 = 0;
uint32_t c2 = pulse2; pulse2 = 0;
interrupts();
// --- Convert counts to frequency (Hz) ---
#ifdef COUNT_BOTH_EDGES
// CHANGE counts both edges ⇒ divide by 2
float freq1 = c1 * 0.5f;
float freq2 = c2 * 0.5f;
#else
float freq1 = (float)c1;
float freq2 = (float)c2;
#endif
// --- Convert frequency to flow (L/min) ---
float flow1 = freq1 * PULSE_TO_LPM;
float flow2 = freq2 * PULSE_TO_LPM;
// --- Integrate total volume (L) ---
#ifdef COUNT_BOTH_EDGES
// Also halve the counts for volume if using CHANGE
totalLiters1 += (float)c1 * 0.5f / FS300A_PULSES_PER_LITER;
totalLiters2 += (float)c2 * 0.5f / FS300A_PULSES_PER_LITER;
#else
totalLiters1 += (float)c1 / FS300A_PULSES_PER_LITER;
totalLiters2 += (float)c2 / FS300A_PULSES_PER_LITER;
#endif
// --- Print results ---
Serial.print(F("CH1: freq=")); Serial.print(freq1, 2);
Serial.print(F(" Hz, flow=")); Serial.print(flow1, 3);
Serial.print(F(" L/min, total=")); Serial.print(totalLiters1, 4);
Serial.println(F(" L"));
Serial.print(F("CH2: freq=")); Serial.print(freq2, 2);
Serial.print(F(" Hz, flow=")); Serial.print(flow2, 3);
Serial.print(F(" L/min, total=")); Serial.print(totalLiters2, 4);
Serial.println(F(" L"));
}
}