Configuring ModSim Modbus TCP Simulation with S7-1200 MB_CLIENT

David Krause16 min read
S7-1200SiemensTutorial / How-to
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

1. Overview

Modbus TCP simulation in the S7-1200 ecosystem is the standard pre-commissioning step for validating a Modbus client application before connecting to a real field device. A typical engineering workflow uses a Windows-based Modbus server simulator such as ModSim from Win-Tech Software or Modbus Slave from ModbusTools to emulate a remote device, while the S7-1214C DC/DC/DC runs the MB_CLIENT instruction under TIA Portal to read holding registers, read discrete inputs, and write coils.

This reference covers the exact configuration required to:

  • Stand up a ModSim TCP server with 6 coils, 1 discrete input, and 7 floating-point holding registers.
  • Configure the S7-1200 MB_CLIENT instruction in TIA Portal V17 or later.
  • Resolve the two most common field issues:
    1. Optimized vs. non-optimized data block access for coils and discrete inputs.
    2. Byte-order (endianness) differences between Modbus register payloads and bit-packed S7 tags.
  • Run more than one MB_CLIENT connection to the same server IP using different local/remote ports.
Engineering note. The S7-1200 MB_CLIENT instruction ships with the TIA Portal "MODBUS TCP" library (or as part of the standard instructions for firmware V4.0+). It is functionally identical to the MB_CLIENT block available for the S7-1500, but the S7-1200 variant supports a maximum of 8 open Modbus TCP connections per CPU. Always confirm the CPU firmware version before commissioning; older V3.0 firmware requires the legacy MB_C / MB_M / MB_S instructions instead.

2. Prerequisites

Item Specification / Version Notes
S7-1200 CPU S7-1214C DC/DC/DC, FW V4.2 or higher Native Modbus TCP library available from FW V4.0 onward
TIA Portal V17 / V18 / V19 MB_CLIENT in the "Instructions > Communication > MODBUS TCP" folder
ModSim ModSim32 (current build) or ModSim from Win-Tech Software Windows MDI application; free download from win-tech.com
Ethernet cabling Direct or via managed switch CPU PROFINET port on a single subnet
PC IP address Static, e.g. 192.168.0.10 Same subnet as the CPU 192.168.0.1
CPU IP address 192.168.0.1 (default) Configured in TIA Portal project or via device display

3. ModSim TCP Server Configuration

ModSim exposes up to 100 simulated slave devices and supports Modbus RTU, ASCII, and TCP. For the S7-1200 use case we run ModSim in Modbus/TCP server mode, listening on port 502.

  1. Install and start ModSim.
  2. Select Connection → Connect → Modbus/TCP/IP Server.
  3. Set the local TCP port to 502 (default Modbus TCP port).
  4. Set the Device ID (Unit Identifier / Slave Address) to 1 unless the application requires a different slave number.
  5. Configure the data blocks to match the application:
ModSim Block Function Code Quantity Starting Address Engineering Meaning
Coils (0xxxxx) FC 01 / 05 / 15 6 00001 6 digital outputs writable from the S7-1200
Discrete Inputs (1xxxxx) FC 02 1 10001 1 digital input read by the S7-1200
Holding Registers (4xxxxx) FC 03 / 06 / 16 14 (7 × 2 words) 40001 7 IEEE-754 single-precision floats
Address convention. ModSim's display addresses are 1-based per the Modbus specification. The MB_CLIENT instruction in TIA Portal uses 0-based addresses. The mapping is Display = 1 + Protocol, so ModSim address 00001 = protocol address 0, address 10001 = protocol address 0 for discrete inputs, and 40001 = protocol address 0 for holding registers.

4. S7-1200 MB_CLIENT Instruction

The MB_CLIENT instruction handles a single TCP connection to a Modbus server. Place one instance per Modbus server (or per port on a shared server). The instruction sits in Program blocks > System blocks > Program resources.

4.1 Instance DB and Static Parameters

Drop MB_CLIENT into a cyclic OB (typically OB1). TIA Portal creates an instance data block automatically. The relevant input parameters are:

Parameter Data Type Value in this Application Description
REQ Bool Edge-triggered flag Start of a new job on rising edge
DISCONNECT Bool 0 0 = hold connection, 1 = close connection
CONNECT_MODE UInt 0 (TCP/IP) Always TCP/IP for Modbus TCP
IP1..IP4 USInt (octet) 192, 168, 0, 10 ModSim PC IPv4 address
IP_PORT UInt 502 ModSim TCP listening port
MB_MODE USInt 0 / 1 / 2 0 = read, 1 = write, 2 = read/write diagnostics
MB_DATA_ADDR UInt 0 / 0 / 0 0-based start address (coil, DI, or HR)
MB_DATA_LEN UInt 6 / 1 / 14 Number of bits or words
MB_DATA_PTR VARIANT Global DB tag Pointer to a global DB (see Section 5)

4.2 Status / Error Codes

The output DONE, BUSY, and ERROR bits indicate the job state. The STATUS word is filled with a hex value on completion. Common values to watch for in a ModSim test environment:

STATUS (hex) Meaning Typical Cause
0x0000 Job completed, no error Successful read/write
0x7000 No job active, connection idle Waiting for REQ
0x7001 First call after REQ, job in progress Normal during execution
0x7002 Additional call, job still in progress Normal during execution
0x80C8 Connection aborted by remote ModSim closed socket, wrong port, or firewall
0x8380 MB_DATA_ADDR / MB_DATA_LEN invalid Address/length out of range, count = 0
0x8382 MB_DATA_PTR is not a global DB or wrong type Pointer to non-DB memory, see Section 5
0x8383 MB_DATA_LEN exceeds 100 words / 800 bits Job too large for one request

5. Optimized vs. Non-Optimized Data Block

This is the single most common source of confusion in the S7-1200 Modbus TCP workflow. The behavior observed in the field — coils and discrete inputs only accessible with an optimized DB — is the documented contract of the MB_CLIENT instruction.

5.1 Why Coils and Discrete Inputs Require an Optimized DB

The TIA Portal documentation for MB_CLIENT states explicitly:

"For the MB_DATA_PTR parameter, the data block used must be a global data block with optimized access. The number of bits addressed must be divisible by 8."

Two reasons drive this:

  1. Bit-packing into bytes. A coil request for <8 bits would need to be combined with neighbouring bits to align on a byte boundary. With a non-optimized DB the offset of any tag is the absolute byte address the engineer specified, which can place a 6-bit coil field in the middle of a byte. The instruction packs the request into a 16-bit Modbus word internally, so it writes back only the relevant 8 bits; the residual bits in the destination byte are read as zero and then the instruction is forced to perform a read-modify-write on the DB — which is not supported against non-optimized symbolic tags in older firmware.
  2. Symbolic consistency check. With optimized access, the compiler knows the symbolic width of every tag and the run-time system can perform the bit-to-byte mapping deterministically. With standard (non-optimized) access, the bit field is interpreted as an absolute address, and the library returns 0x8382 for bit-pointer jobs.

5.2 Recommended DB Layout

Create a single global DB named Modbus_Data with Optimized block access enabled (Properties > Attributes > Optimized block access = checked). The internal layout that consistently works for the application in question:

DATA_BLOCK "Modbus_Data"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
NON_RETAIN
  STRUCT
    // Coils (FC 01 / 05 / 15), 6 bits packed in the first byte
    Coils : BYTE;          // bits 0..5 = coil 0..5
    Reserved1 : BYTE;      // pad to 16-bit alignment
    // Discrete inputs (FC 02), 1 bit
    DiscreteInputs : BYTE; // bit 0 = DI 0
    Reserved2 : BYTE;      // pad to 16-bit alignment
    // Holding registers (FC 03 / 06 / 16), 7 floats = 14 words
    HR_Word_0  : WORD;     // Float 0 low word
    HR_Word_1  : WORD;     // Float 0 high word
    HR_Word_2  : WORD;     // Float 1 low word
    HR_Word_3  : WORD;     // Float 1 high word
    ...
    HR_Word_13 : WORD;     // Float 6 high word
  END_STRUCT;
END_DATA_BLOCK

Three separate MB_CLIENT calls reference three different offsets in the same DB:

  • MB_DATA_PTR := "Modbus_Data".Coils, MB_DATA_LEN := 8 (padded to byte boundary)
  • MB_DATA_PTR := "Modbus_Data".DiscreteInputs, MB_DATA_LEN := 8
  • MB_DATA_PTR := "Modbus_Data".HR_Word_0, MB_DATA_LEN := 14
Workaround for non-optimized DBs. If the project mandate forces a non-optimized DB, the only safe way to expose coil and DI access is to call MB_CLIENT once per bit, each with MB_DATA_LEN = 1 and a target that points at an absolute memory bit in a separate, optimized byte container. This is not recommended for production code; switch the DB to optimized access and align the rest of the project accordingly.

6. Modbus Data Types, Endianness, and Byte Swapping

The second field issue is the apparent byte-order difference between holding-register floats and the bit-packed coil/DI area. The explanation is that the two requests use different Modbus function codes and have different contract semantics.

6.1 Function-Code Map

Modsim Object Function Code PDU Unit Byte Order in Modbus PDU S7 Tag Type
Coil FC 01 / 05 / 15 1 bit per coil, packed 8 per byte LSB-first within byte; bytes in network order Bool / Byte
Discrete Input FC 02 1 bit per DI, packed 8 per byte LSB-first within byte; bytes in network order Bool / Byte
Holding Register FC 03 / 06 / 16 16-bit word Big-endian (high byte first) per word Word / Int / Real
Input Register FC 04 16-bit word Big-endian per word Word / Int / Real

6.2 Why the Float "Looks Big-Endian" and Coils "Look Little-Endian"

Both observations are correct and the two are not contradictory — they describe different data granularities:

  1. Holding registers (FC 03). The Modbus specification requires a 16-bit register, and the wire format places the high byte first (big-endian at the byte level). For a 32-bit IEEE-754 float occupying two consecutive registers, the standard network byte order is: high-word high-byte, high-word low-byte, low-word high-byte, low-word low-byte. When this stream is loaded into a Siemens REAL tag by MB_CLIENT, the library concatenates the two 16-bit words and presents the value to the S7-1200 in the format the CPU expects.
  2. Coils / discrete inputs (FC 01, FC 02). The unit on the wire is a bit. Modbus packs up to 8 bits per byte in the response payload, and within each byte the LSB of the byte carries coil 0 (or DI 0), the next bit carries coil 1, and so on. There is no "endianness" in the float sense; this is a bit-position convention. When the S7-1200 unpacks the response into the optimized DB, the bit at Coils.%X0 is the first bit of the first byte — which is what the application sees as "little-endian at the bit level".

6.3 Practical Example

For the value 23.5 (IEEE-754 single = 0x41BC0000) at HR address 0/1:

Element Bytes on Wire Notes
HR 0 high byte 0x41 Big-endian word 0 high
HR 0 low byte 0xBC Big-endian word 0 low
HR 1 high byte 0x00 Big-endian word 1 high
HR 1 low byte 0x00 Big-endian word 1 low

For coil 0 = TRUE, coil 1 = FALSE, coil 2 = TRUE, coil 3..5 = FALSE at coil address 0:

Bit Position 7 6 5 4 3 2 1 0
Coil index 7 6 5 4 3 2 1 0
Value 0 0 0 0 0 1 0 1
Byte (hex) 0x05

The CPU tag "Modbus_Data".Coils.%X0 reads TRUE, %X1 reads FALSE, %X2 reads TRUE, matching the wire format.

6.4 If You Need Different Bit Order

ModSim exposes a Sim swap dialog (under the Sim menu) that lets the test engineer mirror coil bytes or register words for regression testing when a real field device has a non-standard layout. This does not change Modbus semantics; it changes only how ModSim displays and stores the values locally. On the S7-1200 side, if a target bit must be inverted, do it in user logic rather than in the wire mapping:

// Mirror coils 0..5 from LSB to MSB for a legacy field device
FOR i := 0 TO 5 DO
  "ProcessData".CoilOut[i] := "Modbus_Data".Coils.%X(5 - i);
END_FOR;

7. Multiple MB_CLIENT Connections to One Server

The MB_CLIENT help text states: "For each 'MB_CLIENT' connection, a unique server IP address must be specified." This wording is misleading. The actual contract is that each instance must open a unique TCP connection, identified by the 5-tuple of (server IP, server port, client IP, client port, protocol). Modbus TCP servers typically accept many TCP connections per IP, distinguished by the remote port of the client (which is assigned dynamically by the S7-1200 Ethernet stack).

7.1 Three Connections to One ModSim Server

To run three MB_CLIENT instances against the same ModSim IP (192.168.0.10) on different Modbus function sets, simply place three MB_CLIENT blocks with three separate instance DBs. Each gets a different IP_PORT if ModSim is configured for multiple listening ports (ModSim allows up to four TCP server instances per window through the Connection → Connect menu):

Instance DB Server IP Server Port MB_MODE Length Function
MB_Client_Coils 192.168.0.10 502 1 (write) 6 bits FC 15 force coils
MB_Client_DI 192.168.0.10 502 0 (read) 8 bits FC 02 read DI
MB_Client_HR 192.168.0.10 502 0 (read) 14 words FC 03 read HR

All three can be issued from the same ModSim window on the same port 502 because the S7-1200 opens three distinct TCP sockets (different local ports). ModSim sees them as three independent masters and dispatches PDUs to the corresponding data block based on function code.

Connection resource budget. Each active MB_CLIENT connection consumes one of the S7-1200's open Modbus TCP communication resources. The default maximum is 8, configurable in Device configuration > Properties > Communication > Modbus TCP connection resources. Three connections for the test setup shown here leaves 5 free; the field install of 6 VFDs on MB_CLIENT would saturate the CPU. For larger fleets, use an S7-1500 or an external CP 1243-1 / CP 1542SP-1.

7.2 Alternative: Multiple Ports on One Server

Some PC applications (ModSim, Modbus Slave, ModRSsim2) can bind to several ports. The configuration file for ModRSsim2, for example, lets you expose the same data on port 502 and 1502. Splitting work across ports makes Wireshark traces easier to read when multiple masters talk to one server.

8. Step-by-Step Commissioning Procedure

  1. Verify CPU firmware. In TIA Portal, Online → Accessible devices, read the order number and firmware. Confirm V4.0 or higher.
  2. Bring ModSim online. Start ModSim, configure three blocks (6 coils, 1 DI, 7 floats) and Connection → Connect → Modbus/TCP/IP Server. Confirm "Listening on 0.0.0.0:502" in the status bar.
  3. Compile and download the TIA project. Include the Modbus TCP library if not part of the standard distribution.
  4. Watch the status word. First job returns 0x7001 (in progress), then 0x0000 on success. If the status is 0x80C8, the TCP connection failed — check the PC firewall and IP reachability with ping 192.168.0.10 from the CPU's Web server or an HMI diagnostic page.
  5. Force a coil in ModSim (coil 0 = TRUE) and verify the S7-1200 tag Modbus_Data.Coils.%X0 updates on the next read cycle.
  6. Write a float to HR 0 in the S7-1200 (e.g. Modbus_Data.HR_Word_0 := 16#41BC and HR_Word_1 := 16#0000 for 23.5) and confirm the value appears in ModSim's holding register display.
  7. Watch the byte order in ModSim: with the value 23.5, ModSim should display 0x41BC, 0x0000 as two consecutive 16-bit registers.
  8. Cycle the connection by toggling DISCONNECT = 1, then = 0. The status should return to 0x0000 within a few scans.

9. Verification Checklist

Check Expected Result Pass/Fail Criteria
TCP connect STATUS = 0x0000 within 1 s Any 0x80Cx is a failure
Read HR Float value visible in ModSim and on HMI tag Round-trip accuracy ± 1 ULP
Write coils ModSim coil display reflects S7 tag Bits 0..5 only; bits 6..7 always 0
Read DI S7 tag updates on read cycle No glitch during poll
Multi-client Three instance DBs all in 0x0000 No 0x80C8 between them
Disconnect/Reconnect Status cycles 0x0000 → 0x7000 → 0x0000 No CPU STOP

10. Troubleshooting Matrix

Symptom Likely Root Cause Remedy
Coils/DI read returns all zero; HR read works DB not optimized; bit count not divisible by 8 Set S7_Optimized_Access := 'TRUE'; pad length to 8
STATUS = 0x8382 on every call Pointer does not reference a global DB tag Use a global DB; remove POINTER TO indirection
STATUS = 0x80C8 immediately ModSim not started, wrong port, firewall Start ModSim; allow port 502 in Windows Firewall
Float read back is corrupted (NaN, sign-flipped) Word-swap mismatch on legacy device Use Sim → Swap in ModSim; verify against manual
Coil bit reversed in S7 tag Bit position within byte Reference coils via %X index, not by absolute address
Only one of three MB_CLIENTs works Connection resource limit reached Reduce active connections; verify CPU max in Device configuration
STATUS = 0x8383 Request length > 100 words / 800 bits Split into multiple jobs
ModSim rejects connection after first run ModSim single-client mode Use File → New Window to add another ModSim instance

11. Field-Proven Caveats

  • ModSim32 vs ModSim. Win-Tech's ModSim is the free MDI application. ModSim32 is a more recent build with extended support for multi-port TCP/IP servers and binary register views. For complex test benches prefer ModSim32.
  • Watchdog on long polls. If the S7-1200 is busy or the project is large, the MB_CLIENT may time out (default ~5 s). Increase the TIME_OUT parameter and shorten the cycle to keep below the timeout.
  • Port 502 requires admin on Windows. Only the first application to bind port 502 succeeds; subsequent applications must use a different port. If the S7-1200 shows 0x80C4, the local port for that instance is already in use.
  • Endianness of "REAL" tags. The S7-1200 stores REAL in standard IEEE-754 single-precision, big-endian at the byte level. The Modbus wire format is also big-endian per register. The combined layout is big-endian at the byte level but big-endian at the word level too, which is why many engineers observe "big-endian on the wire". The library handles the mapping automatically; do not insert manual SWAP operations on the S7 side.
  • ModSim documentation link. For additional point types and connection modes refer to the Win-Tech ModSim product page and the Advantech IAG FAQ on ModSim usage for the canonical Configuration → Connect → Modbus/TCP sequence.

12. FAQ

Why do coils and discrete inputs only work with an optimized data block in MB_CLIENT?

The MB_CLIENT instruction explicitly requires a global data block with optimized access for bit fields. Non-optimized DBs return STATUS 0x8382 because the library cannot guarantee byte alignment of symbolic bit tags. Enable S7_Optimized_Access := 'TRUE' on the global DB and pad the request length to a multiple of 8.

Are Modbus holding-register floats big-endian or little-endian?

Modbus is big-endian at the byte and word level. Each 16-bit register transmits its high byte first, and a 32-bit float uses two consecutive registers in the same big-endian order. The S7-1200 REAL tag matches this layout directly through MB_CLIENT, so no byte swap is required.

Can I run more than one MB_CLIENT to the same ModSim IP?

Yes. Each MB_CLIENT opens its own TCP socket and ModSim accepts multiple connections on the same port (502). The help text "unique server IP" is misleading; the real constraint is unique TCP connections, not unique IPs. The S7-1200 supports up to 8 concurrent Modbus TCP connections by default.

What STATUS value indicates the TCP connection has failed?

STATUS = 0x80C8 means the connection was aborted by the remote side or never established. Verify ModSim is started, port 502 is allowed in the Windows Firewall, and the PC IP is reachable from the S7-1200 with ping. The full Siemens status code reference is in the S7-1200 System Manual, Chapter on Modbus TCP.

Which simulator should I use for a multi-slave test bench?

For simple single-server tests, ModSim from Win-Tech Software is sufficient. For larger benches with multiple slaves, Modbus Slave from ModbusTools can simulate up to 100 slaves in 100 windows, which is the standard choice for production-line regression testing.

Back to blog