Overview
The S7-1500 CPU family communicates natively over PROFINET and standard TCP/IP but does not include a Modbus TCP server/client in the system firmware of every CPU variant. To integrate a Modbus TCP/IP device (instrument, drive, third-party controller, legacy SCADA) into a S7-1500 project, Siemens provides two function blocks in the global library Communication > Others > MODBUS TCP:
- MB_CLIENT (FB 1084) — S7-1500 acts as a Modbus TCP client and polls a remote server.
- MB_SERVER (FB 1085) — S7-1500 acts as a Modbus TCP server and answers requests from a remote client.
Both blocks use ISO-on-TCP / TCP connections (connection type 16#0B = 0x0B for TCP) and operate exclusively through the PN interface of the CPU. They replace the older S7-300/S7-400 FB 5 / FB 7 approach. The official reference application note "Modbus/TCP with instructions MB_CLIENT and MB_SERVER" is published as entry 102020340 on the Siemens Industry Online Support portal.
Architecture and Topology
Three reference topologies are typical:
- S7-1500 client → third-party server (instrument, drive, Eurotherm nanodac, panel meter, Energy meter). The CPU opens one TCP connection per remote server and issues cyclic read/write requests.
- External client → S7-1500 server (SCADA, HMI, Modicon M340, third-party gateway). Up to n clients can connect simultaneously; each requires its own MB_SERVER instance and a separate connection ID.
- S7-1500 client ↔ S7-1500/S7-1200 server for back-to-back data exchange. S7-1500 typically uses MB_CLIENT, S7-1200/1500 exposes a Modbus server through MB_SERVER (S7-1200 uses the same FB numbers as 1500: FB 1084/1085 in the TIA "ModbusTCP" library).
Each MB_CLIENT requires a unique connection ID and a unique instance DB. Each MB_SERVER instance can serve multiple clients on the same listen port, but the CPU maintains one internal data pool (the Modbus mapping area) shared by all connections.
Prerequisites
- TIA Portal V15.1, V16, V17, V18, or V19 with installed "SIMATIC ModbusTCP" library. The library ships with STEP 7 and can be opened from Options > Manage Library or by drag-and-drop from the project tree under Libraries > Global Libraries > Communication > MODBUS TCP.
- S7-1500 CPU with PROFINET interface (e.g. CPU 1511-1 PN, 1513-1 PN, 1515-2 PN, 1516-3 PN/DP, 1518-4 PN/DP). All standard PN CPUs from firmware V1.5 onward are supported; some compact CPUs (CPU 1511C, 1512C) also support Modbus TCP through the integrated PN port.
- Firmware: CPU firmware ≥ V1.8 recommended for V17/V18 libraries. TIA Portal will warn if a library version is newer than the CPU's firmware supports.
- IP plan: S7-1500 CPU in subnet with the Modbus server, e.g. 192.168.0.10/24 (client) → 192.168.0.20/24 (server). Keep the client and server on the same subnet or route via Layer-3 with permissive firewall rules on port 502.
- Number of connections: the S7-1500 CPU has a maximum number of open communication resources (system resource 1 = PG/OP/HMI; 2..n = open user connections). S7-1500 supports 64–256 user connections depending on CPU type. MB_CLIENT and MB_SERVER each consume one connection resource per remote partner.
Installing the Modbus TCP Library
- Open the TIA Portal project.
- In the project tree, expand Libraries > Global Libraries.
- Open the library Communication > MODBUS TCP (TIA V17/18: folder ModbusTCP containing types MB_CLIENT, MB_SERVER, MB_RED_CLIENT, and the Modbus_Comm_DB global DB).
- Drag MB_CLIENT (FB 1084), MB_SERVER (FB 1085), and the included Modbus_Comm_DB into the Program blocks folder of the S7-1500 CPU.
- If the library version is newer than your CPU firmware, TIA Portal flags the FB as "library newer than CPU supports". Either upgrade the CPU firmware, or open the library in a matching TIA version and use an older FB revision (V1.0/V1.2/V2.0 are backward compatible for the same FB number).
Hardware Configuration: PROFINET Interface
- In Devices & Networks, select the S7-1500 CPU and open Properties > PROFINET interface [X1].
- Assign the IP address, subnet mask, and (if required) router address. Example: IP 192.168.0.10, mask 255.255.255.0.
- Under Time-of-day synchronization you can leave defaults. Ensure Use router is disabled unless Modbus server is on a different subnet.
- No additional IO device or Modbus partner needs to be configured — MB_CLIENT/MB_SERVER use free TCP connections, not PROFINET IO ARs.
Configuring the Connection (LADDR / Connection_ID)
MB_CLIENT and MB_SERVER manage their own connection through the system resource LADDR (referenced indirectly). You do not create an explicit TSEND_C / TRCV_C connection. Instead, the block derives the connection from CONNECT input (a TCON_IP_V4 struct) and the unique ID.
| Input | Data type | Description | Typical value |
|---|---|---|---|
REQ |
BOOL | Start a single Modbus transaction when rising edge | Pulse from a clock generator or call condition |
DISCONNECT |
BOOL | Close the TCP connection on a rising edge | Fault reset or maintenance flag |
CONNECT |
TCON_IP_V4 | Remote server IP, remote port, local port, connection type | See struct below |
MB_MODE |
USINT | 0 = read, 1 = write | 0 for read holding registers |
MB_DATA_ADDR |
UINT | Modbus starting address | 40001 (HR 1), 30001 (IR 1), 10001 (DI 1), 1 (Coil 1) |
MB_DATA_LEN |
UINT | Number of elements to read/write | 1..125 for registers, 1..2000 for coils |
MB_DATA_PTR |
VARIANT | Pointer to a DB / tag in the data area | P#DB100.DBX0.0 BYTE 100 |
DONE |
BOOL | Last request completed without error | Use as a one-shot |
BUSY |
BOOL | Request in progress (do not retrigger) | Hold for re-trigger logic |
ERROR |
BOOL | Last request failed | Combine with STATUS evaluation |
STATUS |
WORD | Detailed status / error code | See error table |
CONNECT_ID |
CONN_OUC | Unique connection ID for this instance | 1, 2, 3, ... |
Default TCON_IP_V4 parameters for a TCP connection (binary constants):
-
InterfaceId= 16#0000_0001 (PN interface X1, port 1) -
ID= 16#0000_0001 (must match the CONNECT_ID you configure) -
ConnectionType= 16#0B (TCP) -
ActiveEstablished= TRUE (MB_CLIENT is always the active opener) -
RemoteAddress= IP4 address of server, e.g.192.168.0.20(in Siemens syntax:RemoteAddress[1]=192, [2]=168, [3]=0, [4]=20) -
RemotePort= 502 (Modbus TCP server port) -
LocalPort= 0 (use ephemeral port — set to 0 unless a firewall requires a specific port)
MB_CLIENT: Reading Holding Registers (Function Code 3)
To read 10 holding registers starting at Modbus address 40001 from a server at 192.168.0.20:
- Create a global DB, e.g. DB100 "ModbusData", with an array of 20 bytes:
tags: ARRAY[0..19] OF BYTE; - Insert a new FB/FC or use OB1 to call MB_CLIENT. In TIA Portal: Add new block > FB > SCL.
- Declare the following IN/OUT variables:
VAR
REQ_Pulse : BOOL; // one-shot trigger, e.g. clock 0.5s
BusyFlag : BOOL;
DoneFlag : BOOL;
ErrorFlag : BOOL;
StatusWord : WORD;
MB_Mode : USINT := 0; // 0 = read
MB_DataAddr : UINT := 40001;
MB_DataLen : UINT := 10;
Connect : TCON_IP_V4;
ConnectId : CONN_OUC := 1;
END_VAR
- Fill the
Connectstruct in OB1 startup or in an INIT block:
// Static IP parameters for the remote server
Connect.InterfaceId := 16#0000_0001; // CPU PN port
Connect.ID := ConnectId; // 1
Connect.ConnectionType := 16#000B; // TCP
Connect.ActiveEstablished := TRUE; // client side
Connect.RemoteAddress[1] := 192;
Connect.RemoteAddress[2] := 168;
Connect.RemoteAddress[3] := 0;
Connect.RemoteAddress[4] := 20;
Connect.RemotePort := 502;
Connect.LocalPort := 0; // OS-assigned
- Call the block in cyclic OB1 (or OB30/OB35 if you want deterministic polling):
// Retrigger only when previous request is complete
IF NOT "MB_Client_1".Busy THEN
"MB_Client_1".REQ := REQ_Pulse;
END_IF;
"MB_Client_1"(
REQ := REQ_Pulse,
DISCONNECT := FALSE,
CONNECT := Connect,
MB_MODE := MB_Mode,
MB_DATA_ADDR := MB_DataAddr,
MB_DATA_LEN := MB_DataLen,
MB_DATA_PTR := P#DB100.DBX0.0 BYTE 20,
CONNECT_ID := ConnectId,
DONE => DoneFlag,
BUSY => BusyFlag,
ERROR => ErrorFlag,
STATUS => StatusWord
);
Each call with REQ rising edge issues one read. For cyclic polling, generate a 1-second pulse on REQ_Pulse using a clock bit (e.g. Clock_1Hz in OB35 with cyclic interrupt 1000 ms) and gate it with NOT BUSY to avoid overlapping requests.
MB_CLIENT: Writing a Single Coil (Function Code 5)
To set coil 1 (Modbus address 0, write single coil):
// In a dedicated FC "WriteSingleCoil"
MB_Mode := 1; // 1 = write
MB_DataAddr := 0; // coil 0 (0-based)
MB_DataLen := 1; // 1 element
// For coils, MB_DATA_PTR must point to a BOOL or BYTE buffer
MB_DataPtr := P#DB101.DBX0.0 BOOL; // DB101.Byte0 bit 0 = coil state
For Function Code 15 (write multiple coils), set MB_DATA_LEN up to 2000 and use a BYTE array of length ⌈len/8⌉.
MB_SERVER: Exposing S7-1500 Data as Modbus
Insert MB_SERVER (FB 1085) in OB1 and assign its instance DB. Configure the static control bits and offsets:
| Input | Meaning | Default |
|---|---|---|
HR_Start_Offset |
Holding register base in Modbus address space | 0 |
DR_Start_Offset |
Discrete input base | 0 |
CR_Start_Offset |
Coil base | 0 |
IR_Start_Offset |
Input register base | 0 |
HR_Length / DR_Length / CR_Length / IR_Length
|
Length of the area (0 = disabled) | 0..2000 / 0..2000 / 0..2000 / 0..2000 |
UNIT_ID |
Modbus unit identifier (1..247; 255 = ignore) | 255 |
CONNECT |
Passive listen — LocalPort = 502, RemotePort = 0 | Same TCON_IP_V4 |
The server-side connection is opened passively — the S7-1500 listens for incoming connections on the local port. ActiveEstablished = FALSE, LocalPort = 502.
Error Codes and STATUS Diagnostics
The STATUS output returns extended diagnostic information. Common values (Siemens W#16# format):
| STATUS | Meaning | Action |
|---|---|---|
| 16#0000 | No error | — |
| 16#7000 | No request active | Normal idle state |
| 16#7001 | First call with REQ, busy | Wait for DONE / ERROR |
| 16#7002 | Subsequent call, busy | Wait |
| 16#80C7 | Connection not established / partner not reachable | Check IP, subnet, port, firewall, CPU PN cable |
| 16#80C8 | Connection aborted by remote | Server closed; check server health |
| 16#8181 | Wrong data length or data pointer | Check MB_DATA_LEN vs MB_DATA_PTR size |
| 16#8182 | Data pointer invalid (area length mismatch) | Re-check variant pointer |
| 16#8183 | Connection ID already in use | Use unique CONNECT_ID per instance |
| 16#8184 | Connection type not TCP | Set ConnectionType = 16#0B |
| 16#8185 | ActiveEstablished flag inconsistent | Set TRUE for client, FALSE for server |
| 16#8186 | CONNECT_ID out of range | Use 1..64 (CPU-dependent) |
| 16#8187 | Local/remote port zero not allowed | Server: LocalPort = 502; Client: RemotePort = 502 |
| 16#8188 | Data type and function code mismatch | e.g. INT for register, BOOL for coil |
| 16#8381 | Modbus exception code 0x01 (illegal function) | Server does not support this FC |
| 16#8382 | Modbus exception 0x02 (illegal data address) | Address outside server map |
| 16#8383 | Modbus exception 0x03 (illegal data value) | Length exceeds server map |
| 16#8384 | Modbus exception 0x04 (server device failure) | Server-side fault; check server status |
| 16#8388 | Modbus exception 0x08 (memory parity error) | Server memory fault |
| 16#80A1 | Internal resource exhaustion | Reduce number of open connections |
For full lists, refer to the FB 1084 / FB 1085 online help inside TIA Portal and the Siemens FAQ 94766380.
Wiring Multiple Servers (Multi-Client, Multi-Connection)
For a star topology with three instruments (M1, M2, M3), use three MB_CLIENT instances, three instance DBs, three unique CONNECT_ID values (1, 2, 3), and three Connect structs. Poll them sequentially with a state machine to avoid overlapping REQ pulses on a single CPU scan.
CASE State OF
0: // idle, send M1 request
MB_DataAddr := 40001;
MB_DataLen := 10;
Connect.RemoteAddress[4] := 20; // 192.168.0.20
REQ := TRUE; State := 1;
1: // wait for done / error
IF DONE THEN REQ := FALSE; State := 2; END_IF;
IF ERROR THEN REQ := FALSE; LogError(); State := 2; END_IF;
2: // ... move to M2, etc.
END_CASE;
Commissioning and Verification
- Download the project to the S7-1500 CPU and put the CPU in RUN.
- Open Online & Diagnostics > Connection diagnostics on the PN interface. Confirm the TCP connection to 192.168.0.20:502 is shown as established.
- In the Watch table, force REQ = TRUE for one scan and observe BUSY rise, then DONE rise with STATUS = 0. The MB_DATA_PTR area should show fresh values.
- From a PC, run a Modbus TCP master simulator (e.g. Modbus Poll, qModMaster, or Wireshark with the modbus dissector) against the S7-1500 MB_SERVER and verify the holding register area.
- Use Wireshark on the network with filter
tcp.port==502 && ip.addr==192.168.0.20to capture MBAP + PDU frames. Expected transaction ID, protocol ID 0x0000, length 6+n, unit ID, function code, then register data.
Troubleshooting Matrix
| Symptom | STATUS | Likely cause | Action |
|---|---|---|---|
| BUSY never clears | 16#7002 / 16#80C7 | Server unreachable | Ping remote; check PROFINET port LEDs; verify firewall |
| ERROR rises on every request | 16#8181 | MB_DATA_LEN > available bytes in MB_DATA_PTR | Resize target DB or reduce length |
| Values zero / not updating | 16#0000 / DONE=TRUE | Endian mismatch or wrong offset | Verify register order: HR 40001 is address 0; HR 40010 is address 9 |
| Intermittent drops | 16#80C8 | Watchdog / TCP keep-alive | Reduce polling rate, add DISCONNECT/RECONNECT logic |
| Only first transaction works | 16#8183 | Two blocks share a CONNECT_ID | Use unique IDs |
| STATUS = 0, but data wrong | 16#0000 | Function code mismatch (FC 3 vs FC 4) | Use FC 4 (Input Registers) for read-only words; FC 3 (Holding) for R/W |
| Modbus exception from server | 16#8381..0x84 | Server has no data at that address | Check server Modbus map register list |
Performance and Timing
Typical cycle for one MB_CLIENT transaction on an S7-1516-3 PN/DP (firmware V2.9):
- Connect establishment (first poll): 20–80 ms
- Reuse existing connection: 3–10 ms per transaction
- 10 holding registers: ~4 ms
- 125 holding registers (max): ~10 ms
For high-rate polling, use OB35 (cyclic interrupt) at 10–50 ms and add a watchdog timeout (e.g. error raised if no DONE within 2 OB35 cycles).
FAQ
Which function blocks do I need for Modbus TCP on an S7-1500?
Use MB_CLIENT (FB 1084) when the S7-1500 is the client polling a remote Modbus server, and MB_SERVER (FB 1085) when the S7-1500 exposes a Modbus server to a remote client. Both are found in the global library Communication > MODBUS TCP in TIA Portal V15.1 and later.
Why does MB_CLIENT return STATUS 16#80C7 and never complete?
This means the TCP connection cannot be established. Verify the remote server IP, that port 502 is open and not blocked by a firewall, that the S7-1500 PROFINET interface has a valid IP in the same subnet, and that ConnectionType = 16#0B with ActiveEstablished = TRUE.
How do I read Modbus holding register 40001..40010 into the S7-1500?
Set MB_MODE = 0, MB_DATA_ADDR = 40001 (or 0 in some libraries that use zero-based addressing — check your FB version), MB_DATA_LEN = 10, and point MB_DATA_PTR to a DB area large enough (≥ 20 bytes for 10 INT registers). Trigger with a one-shot REQ pulse and gate it with NOT BUSY.
Can MB_SERVER handle multiple simultaneous Modbus clients?
Yes, but each TCP connection consumes one open user connection resource on the S7-1500 CPU. The Modbus mapping data (coils, holding registers) is shared across all clients. For a typical CPU 1515-2 PN, you can have dozens of clients up to the connection-resource limit (64–128 open connections depending on CPU).
Do I still need TSEND_C / TRCV_C for Modbus TCP?
No. MB_CLIENT and MB_SERVER handle the TCP open/close, send, and receive internally. Manually combining TSEND_C with a Modbus parser is the legacy approach from S7-300 / S7-400 days and is not recommended for S7-1500.