Complete Modbus Guide

Introduction

Modbus is the world's most widely used industrial communication protocol. Created in 1979, it is used in millions of PLCs, drives, controllers, meters, and industrial sensors. Eziwan natively supports Modbus RTU (over RS-485) and Modbus TCP (over Ethernet).


Modbus RTU over RS-485

RS-485 Wiring: A Complete Guide

RS-485 is a two-wire differential interface (A and B). The voltage difference between A and B encodes the signal, giving it excellent immunity to electromagnetic interference in industrial environments.

⚠️ In-line topology (A↔A, B↔B, common GND). 120 Ω terminating resistors only at both ends of the bus—already integrated on the Eziwan side; must be placed on the last slave. Never place a resistor in the middle of the line.

Eziwan RS-485 Terminal Connection Chart:

Eziwan TerminalRS-485 SignalRecommended Cable Color
A (or D+)Differential positiveWhite or red
B (or D-)Differential negativeBlue or black
GNDReference groundGreen or gray

RS-485 Communication Settings

The settings must be identical on the gateway and all slaves:

ParameterCommon ValuesEziwan Default
Speed (baud rate)1200, 2400, 4800, 9600, 19200, 38400, 57600, 1152009600
ParityN (none), E (even), O (odd)N
Data bits7, 88
Stop bits1, 21
Inter-message delay3.5 character times (Modbus standard)Auto

Most Common Standard Configuration: 9600 8N1 (9,600 baud, 8 data bits, no parity, 1 stop bit)

Maximum Distance and Number of Slaves

Baud rateMaximum distanceMax. slaves (electrical)
9,600 bps1,200 m32 (unit loads)
19,200 bps800 m32
57,600 bps200 m32
115,200 bps50 m32

To exceed 32 slaves or 1,200 m, use an RS-485 repeater.


Modbus TCP

Ethernet Connection

Modbus TCP encapsulates the Modbus protocol in TCP/IP frames. The connection is made directly via an RJ45 Ethernet port.

ParameterValue
TCP Port502 (standard), sometimes 503 or another port depending on the manufacturer
Unit IDSlave address (1 to 247), or 255 for direct access
Recommended timeout500 ms to 2000 ms depending on the network
TCP keep-aliveRecommended for long-duration connections

Network Configuration

The Eziwan gateway must be able to connect to the Modbus TCP controller via the Ethernet network. Check the following:

  1. The gateway and the PLC are on the same subnet (or there is a router between them)
  2. There is no firewall blocking TCP port 502 between the gateway and the PLC
  3. The Modbus TCP PLC is configured to accept connections (PUT/GET enabled on Siemens)

The Four Types of Modbus Registers

The Modbus specification defines four distinct data spaces:

TypeModbus CodeAddressesMaster AccessSizeDescription
Coils0x (1x)00001–09999Read/Write1 bitDigital outputs (relays, coils)
Discrete Inputs1x (2x)10001–19999Read-only1 bitDigital inputs (digital sensors)
Input Registers3x30001–39999Read-only16 bitsMeasured values (analog sensors)
Holding Registers4x40001–49999Read/Write16 bitsParameters and setpoints

Important Note: Modbus addresses start at 1 in "functional" notation (40001 to 49999), but Modbus functions use 0-based addresses (the FC03 request for register 40001 uses the address 0x0000). Eziwan supports both notations.

Standard Modbus Functions

Function CodeNameTarget Registers
FC01Read CoilsCoils (0x)
FC02Read Discrete InputsDiscrete Inputs (1x)
FC03Read Holding RegistersHolding Registers (4x)
FC04Read Input RegistersInput Registers (3x)
FC05Write Single CoilCoils (0x)
FC06Write Single RegisterHolding Registers (4x)
FC15Write Multiple CoilsCoils (0x)
FC16Write Multiple RegistersHolding Registers (4x)

Configuring Mapping in Eziwan

JSON Configuration Interface

The Modbus mapping defines how the PLC's registers are collected and published:

{
"device": {
"name": "Compresseur_Atlas_GA75",
"description": "Compresseur d'air atelier principal",
"protocol": "modbus_rtu",
"connection": {
"port": "/dev/ttyS0",
"baudrate": 9600,
"parity": "N",
"databits": 8,
"stopbits": 1,
"slave_id": 1
}
},
"polling": {
"interval_ms": 5000,
"timeout_ms": 500,
"retry_count": 3,
"retry_delay_ms": 200
},
"registers": [
{
"name": "Pression_Service",
"address": "3x0001",
"count": 1,
"type": "uint16",
"scale_factor": 0.1,
"unit": "bar",
"description": "Pression de service sortie compresseur",
"alarm_low": 6.0,
"alarm_high": 12.0,
"publish_on_change": true
},
{
"name": "Temperature_Huile",
"address": "3x0002",
"count": 1,
"type": "uint16",
"scale_factor": 0.1,
"unit": "°C",
"alarm_high": 95.0
},
{
"name": "Heures_Fonctionnement",
"address": "4x0010",
"count": 2,
"type": "uint32_ab",
"unit": "h",
"description": "Compteur d'heures moteur"
},
{
"name": "Debit_Air",
"address": "3x0005",
"count": 2,
"type": "float32_abcd",
"unit": "m³/h"
},
{
"name": "Alarme_Active",
"address": "1x0001",
"count": 1,
"type": "bool",
"description": "Au moins une alarme active"
},
{
"name": "Code_Alarme",
"address": "4x0020",
"count": 1,
"type": "uint16",
"description": "Code alarme (voir tableau constructeur)"
}
]
}

Complete example: 10 temperature registers, 5 status registers

Here is a typical mapping for a production line with 10 temperature points and 5 machine states:

{
"registers": [
{ "name": "Temp_Zone1", "address": "4x0001", "count": 2, "type": "float32_abcd", "unit": "°C" },
{ "name": "Temp_Zone2", "address": "4x0003", "count": 2, "type": "float32_abcd", "unit": "°C" },
{ "name": "Temp_Zone3", "address": "4x0005", "count": 2, "type": "float32_abcd", "unit": "°C" },
{ "name": "Temp_Zone4", "address": "4x0007", "count": 2, "type": "float32_abcd", "unit": "°C" },
{ "name": "Temp_Zone5", "address": "4x0009", "count": 2, "type": "float32_abcd", "unit": "°C" },
{ "name": "Temp_Zone6", "address": "4x0011", "count": 2, "type": "float32_abcd", "unit": "°C" },
{ "name": "Temp_Zone7", "address": "4x0013", "count": 2, "type": "float32_abcd", "unit": "°C" },
{ "name": "Temp_Zone8", "address": "4x0015", "count": 2, "type": "float32_abcd", "unit": "°C" },
{ "name": "Temp_Zone9", "address": "4x0017", "count": 2, "type": "float32_abcd", "unit": "°C" },
{ "name": "Temp_Zone10", "address": "4x0019", "count": 2, "type": "float32_abcd", "unit": "°C" },
{ "name": "Etat_EnMarche", "address": "1x0001", "count": 1, "type": "bool" },
{ "name": "Etat_EnChauffe", "address": "1x0002", "count": 1, "type": "bool" },
{ "name": "Etat_Production", "address": "1x0003", "count": 1, "type": "bool" },
{ "name": "Etat_Defaut", "address": "1x0004", "count": 1, "type": "bool" },
{ "name": "Etat_ArretUrgence", "address": "1x0005", "count": 1, "type": "bool" }
]
}

Data Types Supported by Eziwan

JSON TypeDescriptionSize (registers)Example Value
uint1616-bit unsigned integer10 to 65535
int1616-bit signed integer1-32768 to 32767
uint32_ab32-bit big-endian integer20 to 4,294,967,295
uint32_ba32-bit integer, little-endian2
float32_abcdIEEE 754 floating-point, ABCD223.456
float32_cdabIEEE 754 floating-point, CDAB (Schneider)2
float32_badcIEEE 754 floating-point, BADC2
float64_abcdefghDouble precision4
boolBoolean (Coil or Discrete Input)1true/false

Debugging Modbus

Modbus Poll Tool (Windows)

Modbus Poll is the go-to tool for testing and debugging Modbus connections:

  1. Download from modbustools.com
  2. Free trial version (30 days)
  3. Configuration: Connection → Connect → Modbus TCP (IP + Port 502) or Serial (COM + baud rate)
  4. Define the registers to read: Setup → Read/Write Definition
Modbus Poll - Read Configuration
─────────────────────────────────────
Slave ID: 1
Function: 03 Read Holding Registers
Address: 0 (= registre 40001)
Quantity: 10
Scan Rate: 1000 ms

Eziwan Logs for Modbus Debugging

In the Eziwan portal → Gateway → Logs → Modbus:

2026-06-04 14:32:00.123 [[INFO] Modbus RTU: FC03 request, slave=1, address=0, count=10
2026-06-04 14:32:00.145 [[INFO] Modbus RTU: Response received in 22 ms, 10 registers
2026-06-04 14:32:00.145 [DATA] Reg[0001]=0x4529 (23.4°C FLOAT32), Reg[0003]=0x42C6 (99.2 rpm)
2026-06-04 14:32:01.123 [[WARN] Modbus RTU: timeout after 500 ms, slave=2 (attempt 1/3)
2026-06-04 14:32:01.623 [[WARN] Modbus RTU: timeout after 500 ms, slave=2 (attempt 2/3)
2026-06-04 14:32:02.123 [[ERROR] Modbus RTU: Slave 2 unreachable after 3 attempts

Enable the DEBUG log level to obtain the raw hexadecimal frames:

2026-06-04 14:32:00.100 [DEBUG] TX: 01 03 00 00 00 0A C5 CD
│ │ ├──────┤ ├──────┤ └── CRC16
│ │ addr=0 count=10
│ FC03
slave=1
2026-06-04 14:32:00.122 [DEBUG] RX: 01 03 14 45 29 ... (20 octets + 2 CRC)

Troubleshooting

Problem 1: Modbus RTU Timeout

Symptoms: timeout messages, no response from the slave.

Causes and Solutions:

CauseDiagnosisSolution
Incorrect slave IDManually test slave IDs 1 through 10Check equipment documentation
Incorrect baud rateTest 9600, 19200, and 57600 one at a time
A/B wiring reversedMeasure voltage between A and B: +1.5V to 5V = correctReverse the A and B wires
Missing termination resistorMeasure R between A and B with power off: ~60Ω if 2 resistorsAdd a 120Ω resistor at the end of the bus
Cable too longCalculate total lengthReduce baud rate or add a repeater
RS-485 power supply missingMeasure slave power supply voltageCheck slave 24VDC

Problem 2: CRC Errors

Symptoms: CRC error in the Eziwan logs; incorrect data.

Causes:

  • Electromagnetic interference on the RS-485 cable (route the cable away from power cables)
  • Unshielded cable (use a shielded cable; connect the shield to ground on the gateway side only)
  • Poor cable quality (use RS-485-specified cable, 120Ω impedance)
  • Transmission speed too high for the cable length (reduce the baud rate)

Problem 3: Slave ID Conflict

Symptoms: One slave responds instead of another; data is mixed up.

Cause: Two slaves have the same slave ID on the same RS-485 bus.

Solution:

  1. Disconnect all slaves from the bus except one
  2. Scan the bus using Modbus Poll to find that slave's ID
  3. Change the ID if there is a conflict (via the device's configuration interface)
  4. Reconnect the slaves one by one

Problem 4: Unreadable Registry (Exception Code 02)

Symptom: Illegal Data Address (Exception Code 02).

Cause: The requested address does not exist in the PLC or is not accessible via Modbus.

Solutions:

  • Check the manufacturer's documentation for supported addresses
  • Some devices expose only a limited range of registers
  • For Siemens devices, verify that the memory area is within the data block exposed via PUT/GET

Rapid Diagnosis Checklist

□ 24 VDC power supply voltage present at the Eziwan power terminals
□ The Eziwan RS-485 LED flashes during transmission (TX)
□ A/B wiring: A = positive, B = negative (non-inverted)
□ 120Ω resistors at both ends of the bus only
□ Correct slave ID (check the device display or documentation)
□ Same baud rate on the gateway and the device
□ Identical parity on the gateway and device (N, E, or O)
□ Correct IP address and port 502 for Modbus TCP
□ PUT/GET enabled on S7-1500/1200 if necessary
□ No firewall blocking port 502 on the OT local network

Frequently Asked Questions

Modbus RTU or Modbus TCP: Which One Should You Use?

RTU if your devices are connected via an RS-485 serial bus (sensors, meters, older PLCs); TCP if the devices are already connected via Ethernet. The Eziwan gateway supports both protocols simultaneously and acts as an RTU ↔ TCP bridge.

Which Modbus functions are used for monitoring?

Primarily FC03 (reading holding registers) and FC04 (input registers) for data collection; FC06/FC16 for writing setpoints. Exception codes (02 illegal address, 0B target unreachable) guide troubleshooting.

How do you read a 32-bit value or a floating-point number?

On two consecutive registers, specifying the word order (big/little endian, word swap) in the gateway mapping. A single device may use a mix of conventions: check the manufacturer's documentation register by register.

Can Modbus be transmitted over the Internet?

Never in the clear: the protocol uses neither authentication nor encryption. The gateway confines Modbus traffic to the local network and transmits the data to the cloud through an encrypted VPN tunnel.