← Modbus Flow Meter 32-bit Counter Read and Remote Reset
Bioreactor controlM-DuinoModbus RTUAcquisition
Modbus Flow Meter 32-bit Counter Read and Remote Reset — full example
Read 32-bit flow meter totals over Modbus RTU with an M-Duino PLC and expose a remote counter reset as a Modbus TCP coil. Full Arduino code included.
Complete, runnable program for the M-Duino (flow-meter-reading.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 — 32-bit flow meter reading + remote reset
*
* Device: M-Duino (Industrial Shields, Arduino PLC with Ethernet + RS485)
* Based on: bioreactor control project, ModbusTCPSlaveRTUMaster.ino
*
* Bus: Modbus RTU over RS485, 9600 8N1. Two flow meters at addr 5 and 6
* that measure the process water entering/leaving the bioreactors.
*
* Flow meter RTU registers:
* 0x100 accumulated liters (2 x 16-bit regs -> 32-bit integer)
* 0x200 counter reset command (1 = set to zero)
*
* The accumulated value is published as an input register on the TCP side,
* and the reset is exposed as a coil: when the SCADA sets the coil to 1,
* this sketch issues the 0x200 command over RTU and clears the coil again.
*
* Integration: see the "Gateway Modbus TCP <-> RTU" module for the full
* plant map; here the flow acquisition is isolated.
*/
#include
#include
#include
ModbusRTUMaster master(RS485);
ModbusTCPSlave modbus;
const uint8_t FLOW[2] = {5, 6}; // RTU addresses of the two flow meters
const uint16_t REG_ACC = 0x100; // accumulated liters (2 regs)
const uint16_t REG_RESET = 0x200; // reset command
// Memory exposed over TCP
uint16_t inputRegs[12]; // 6,7 = liters flow 1 ; 8,9 = liters flow 2
bool coils[18]; // 16,17 = reset flow 1 / flow 2
uint32_t tPoll = 0;
void setup() {
Serial.begin(115200);
master.begin(9600);
master.setTimeout(300);
modbus.addInputRegisters(0, inputRegs, 12);
modbus.addCoils(0, coils, 18);
modbus.begin();
}
void loop() {
modbus.update(); // serve the SCADA over TCP
if (millis() - tPoll > 500) {
tPoll = millis();
for (uint8_t i = 0; i < 2; ++i) {
// 1. If the SCADA requested a reset (coil 16/17), execute it and clear it
if (coils[16 + i]) {
if (resetCounter(FLOW[i]) == 0) {
coils[16 + i] = false;
Serial.print("Flow meter counter reset: addr ");
Serial.println(FLOW[i]);
}
}
// 2. Read the 32-bit accumulated value into input regs (6/7 and 8/9)
uint32_t liters = readAccumulated(FLOW[i]);
inputRegs[6 + i * 2] = (uint16_t)(liters >> 16);
inputRegs[6 + i * 2 + 1] = (uint16_t)(liters & 0xFFFF);
}
}
}
// Reads 2 x 16-bit registers and combines them into liters (32 bits)
uint32_t readAccumulated(uint8_t addr) {
if (!master.readHoldingRegisters(addr, REG_ACC, 2)) return 0;
if (master.isWaitingResponse()) {
ModbusResponse r = master.available();
if (r && !r.hasError())
return (uint32_t)((r.getRegister(0) << 16) | r.getRegister(1));
}
return 0;
}
// Sets the flow meter counter to zero
uint8_t resetCounter(uint8_t addr) {
if (!master.writeSingleRegister(addr, REG_RESET, 1)) return 1;
if (master.isWaitingResponse()) {
ModbusResponse r = master.available();
if (r && !r.hasError()) return 0;
}
return 1;
}
Download the full project pack — freeThis example + the related ones + bill of materials