1. Overview: Modbus RTU on S7-1500
Modbus RTU (Remote Terminal Unit) is a serial master/slave protocol used extensively in power conversion equipment, UPS systems, inverters, and protection relays. The S7-1500 CPU family (S7-15xx) supports Modbus RTU through the MB_CLIENT instruction when a serial communication module such as the CM PtP RS422/485 (e.g., 6ES7540-1AB00-0AA0) or a communications processor (e.g., CP 340/341/440/441) is installed in the backplane.
This article documents a working configuration for reading measurement registers (current, alarms, status) and writing multi-register command sequences to a power unit, addressing the most common commissioning error: incorrect MB_MODE selection and address offset handling. The reference target is the Siemens S7-1500 family running TIA Portal V14 SP1 through V20, communicating with a third-party Modbus RTU slave that exposes holding registers in the 4xxxx range.
For the architectural background of Modbus RTU on S7-1500 point-to-point links, refer to the Siemens TIA Portal V20 Modbus RTU configuration overview.
2. Prerequisites
| Component | Specification |
|---|---|
| CPU | S7-1500 (any variant with PN/DP and PtP-capable backplane slot) |
| PtP module | CM PtP RS422/485 BA (6ES7540-1AB00-0AA0) or CM PtP RS232 (6ES7540-1AD00-0AA0) |
| Programming environment | TIA Portal V14 SP1 minimum; V15-V20 for MB_MODE=103 native addressing |
| Library | Modbus_Comm_Load (V2.x or V3.x) and Modbus_Master / MB_CLIENT (V3.x or V4.x) |
| Slave device | Power unit with Modbus RTU slave, default slave ID, 19200 8N1 typical |
| Wiring | RS485 two-wire (D+/D-) shielded twisted pair, 120 Ω termination at both ends if bus length exceeds 10 m |
MB_DB configuration.3. The MB_CLIENT Instruction: Parameter Reference
The MB_CLIENT (formerly Modbus_Master in V13) instruction is a single-instance block that sends one Modbus request per rising edge of REQ. All Modbus PDU types are exposed through the MB_MODE parameter.
| Input | Data type | Purpose |
|---|---|---|
| REQ | BOOL | Rising edge triggers transmission |
| DISCONNECT | BOOL | TRUE drops the connection after the current job |
| MB_MODE | USINT | Modbus function code and addressing mode (see Section 4) |
| MB_DATA_ADDR | UINT | Starting register address (mode-dependent interpretation) |
| MB_DATA_LEN | UINT | Number of registers/words to transfer (1-125 read, 1-123 write) |
| MB_DATA_PTR | VARIANT | Pointer to a data block or tag of matching length |
| CONNECT | BOOL | Rising edge establishes the connection on first use |
| DONE | BOOL | TRUE on successful completion (one PLC cycle) |
| BUSY | BOOL | TRUE while request is in progress |
| ERROR | BOOL | TRUE on transmission or slave exception |
| STATUS | WORD | Hex error/status code (see Section 7) |
4. MB_MODE Selection: The Address Offset Trap
This is the most common commissioning error when reading holding registers. MB_MODE in TIA Portal V14+ is split into two families:
| MB_MODE | Function | Address convention | Example for register 2200 |
|---|---|---|---|
| 0 | FC 03 - Read Holding Registers | 0-based (register 0 maps to address 0) | MB_DATA_ADDR = 2200 |
| 1 | FC 03 - Read Holding Registers | 1-based classic Modicon (register 1 maps to address 0, register 2200 maps to 42199) | MB_DATA_ADDR = 42199 |
| 103 | FC 03 - Read Holding Registers (extended) | Native register number (register 2200 maps to 2200) | MB_DATA_ADDR = 2200 |
| 100 | FC 04 - Read Input Registers | 0-based | MB_DATA_ADDR = 2200 |
| 101 | FC 04 - Read Input Registers | 1-based Modicon | MB_DATA_ADDR = 42199 |
| 104 | FC 04 - Read Input Registers (extended) | Native | MB_DATA_ADDR = 2200 |
| 2 | FC 06 - Write Single Register | 0-based | MB_DATA_ADDR = 8000 |
| 5 | FC 06 - Write Single Register | 1-based | MB_DATA_ADDR = 48000 |
| 105 | FC 06 - Write Single Register (extended) | Native | MB_DATA_ADDR = 8000 |
| 15 | FC 16 - Write Multiple Registers | 1-based | MB_DATA_ADDR = 48000 |
| 115 | FC 16 - Write Multiple Registers (extended) | Native | MB_DATA_ADDR = 8000 |
The original problem report shows MB_MODE = 1 with MB_DATA_ADDR = 2200. With mode 1, the slave will attempt to read holding register 2200 in Modicon convention, which translates to Modbus PDU address 2199. The power unit's actual register 2200 (in user documentation) lives at PDU address 2199, so the correct MB_DATA_ADDR for MB_MODE = 1 is 42199 (offset 40000 + 2199) or simply 42199 if interpreted as 4xxxx addressing.
The cleanest solution on TIA Portal V14 SP1 and later is to use the extended addressing modes (100-115), which accept the register number as written in the slave's documentation. For register 2200 use MB_MODE = 103 with MB_DATA_ADDR = 2200. This eliminates the offset mental load entirely.
5. Reading UINT16: Current Demand on Phase 1 (Register 2200)
The power unit's register map declares register 2200 as a 16-bit unsigned integer reporting the current demand on phase 1, scaled in 0.1 A per LSB. The following TIA Portal code implements the read cycle at a 1-second cadence using a 1-Hz clock bit.
5.1 Data Block Layout
DATA_BLOCK "DB_Modbus_Phase1"
STRUCT
CurrentRaw : UINT; // Raw register value (0-65535)
CurrentA : REAL; // Scaled value in amperes (CurrentRaw * 0.1)
Status : WORD; // MB_CLIENT STATUS word
ErrorFlag : BOOL; // MB_CLIENT ERROR
DoneFlag : BOOL; // MB_CLIENT DONE
BusyFlag : BOOL; // MB_CLIENT BUSY
END_STRUCT;
END_DATA_BLOCK
5.2 Cyclic OB1 Read Call
// 1-Hz clock from timer or system clock bit (e.g., "Clock_1Hz")
"MB_Client_DB"(REQ := "Clock_1Hz" AND NOT "MB_Client_DB".BUSY,
DISCONNECT := FALSE,
MB_MODE := 103, // FC 03, extended addressing
MB_DATA_ADDR := 2200, // Native register 2200
MB_DATA_LEN := 1, // 1 register
MB_DATA_PTR := "DB_Modbus_Phase1".CurrentRaw,
CONNECT := FALSE, // Connect only once via init OB
DONE => "DB_Modbus_Phase1".DoneFlag,
BUSY => "DB_Modbus_Phase1".BusyFlag,
ERROR => "DB_Modbus_Phase1".ErrorFlag,
STATUS => "DB_Modbus_Phase1".Status);
5.3 Scaling Logic (Cyclic)
// Convert raw 0.1-A LSB to engineering units
IF "DB_Modbus_Phase1".DoneFlag THEN
"DB_Modbus_Phase1".CurrentA := INT_TO_REAL("DB_Modbus_Phase1".CurrentRaw) * 0.1;
END_IF;
If you must remain on TIA V13 or use the classic MB_MODE 1 family, change MB_MODE := 1 and MB_DATA_ADDR := 42199 (or 42001-40000+2200 = 42200 if the slave uses 1-based user addressing). Always cross-check with the slave vendor's Modbus Register Map PDF — vendor A's "register 2200" is sometimes PDU address 2200 (0-based) and sometimes PDU address 2199 (1-based).
6. Writing a 6-Register Command Sequence (Alarm Reset 8000-8005)
The alarm reset on the referenced power unit requires writing six consecutive holding registers in a single FC 16 (Write Multiple Registers) transaction. The data layout per the source specification is:
| Register | Value (decimal) | Value (hex) | Meaning |
|---|---|---|---|
| 8000 | 41096 | 0xA088 | Command code (reset alarms) |
| 8001 | 10 | 0x000A | Sub-command or parameter |
| 8002 | 8193 or 8449 | 0x2001 or 0x2101 | IO channel selector (1 or 2) |
| 8003 | 1 | 0x0001 | Enable flag |
| 8004 | 13107 ('3') | 0x3333 | Password high word (ASCII '33') |
| 8005 | 13107 ('3') | 0x3333 | Password low word (ASCII '33') |
6.1 Build the Payload in a Separate DB
DATA_BLOCK "DB_Reset_Cmd"
STRUCT
Word0_Cmd : UINT := 41096; // 0xA088
Word1_Sub : UINT := 10; // 0x000A
Word2_IO : UINT := 8193; // IO 1; change to 8449 for IO 2
Word3_Enable : UINT := 1; // 0x0001
Word4_PwdHi : UINT := 16#3333; // ASCII '33' upper
Word5_PwdLo : UINT := 16#3333; // ASCII '33' lower
Trigger : BOOL; // Rising edge triggers write
Done : BOOL;
Busy : BOOL;
Error : BOOL;
Status : WORD;
END_STRUCT;
END_DATA_BLOCK
6.2 FC 16 Write Call with Extended Addressing
// One-shot write triggered by HMI button or alarm-clear logic
"MB_Client_DB"(REQ := "DB_Reset_Cmd".Trigger AND NOT "DB_Reset_Cmd".Busy,
DISCONNECT := FALSE,
MB_MODE := 115, // FC 16, extended addressing
MB_DATA_ADDR := 8000, // Native starting register
MB_DATA_LEN := 6, // Six consecutive registers
MB_DATA_PTR := "DB_Reset_Cmd".Word0_Cmd,
CONNECT := FALSE,
DONE => "DB_Reset_Cmd".Done,
BUSY => "DB_Reset_Cmd".Busy,
ERROR => "DB_Reset_Cmd".Error,
STATUS => "DB_Reset_Cmd".Status);
// Reset trigger after completion (one-cycle pulse)
IF "DB_Reset_Cmd".Done OR "DB_Reset_Cmd".Error THEN
"DB_Reset_Cmd".Trigger := FALSE;
END_IF;
6.3 If You Are Stuck on TIA V13
Use MB_MODE := 15 (classic FC 16, 1-based) and set MB_DATA_ADDR := 48000 (40000 + 8000). The data pointer still references the same six-word structure. Verify the result by reading the alarm status word back on a subsequent cycle to confirm the slave accepted the command.
DONE flag and re-issue on ERROR if the slave permits retry.7. STATUS Word Decoding and Error Diagnosis
When ERROR is TRUE, the STATUS output contains either a Modbus exception code (returned by the slave) or a Siemens protocol-stack error (generated locally). Distinguishing the two is critical for correct diagnosis.
| STATUS (hex) | Source | Meaning | Corrective action |
|---|---|---|---|
| 0x0001 | Stack | Illegal function code (unsupported FC) | Verify the slave supports FC 03/06/16; check MB_MODE mapping |
| 0x0002 | Stack | Illegal data address (PDU address out of range) | Check address offset; verify the register exists in the slave map |
| 0x0003 | Stack | Illegal data value | Inspect payload for out-of-range words (e.g., reserved bit patterns) |
| 0x0006 | Stack | Slave device busy | Increase retry delay; verify the slave is not in a local-mode lockout |
| 0x0007 | Stack | Negative acknowledge (write protect, password fail) | Confirm password bytes in 8004-8005; check write-enable jumper on slave |
| 0x0080 | Stack | CRC or framing error on receive | Check cabling, termination, baud rate, parity (8N1 vs 8E1) |
| 0x0081 | Stack | Timeout — no response within response timeout | Check slave address, bus biasing resistors, supply voltage |
| 0x0082 | Stack | Inter-character timeout gap violated (RTU framing) | Confirm 8N1 and that the slave enforces the 3.5-character silent gap |
| 0x0083 | Stack | Frame length error (response shorter than expected) | Verify MB_DATA_LEN matches the slave's register width (UINT vs ULONG) |
| 0xC091 | Local | MB_DATA_PTR points to a DB that is not downloaded | Recompile and download the referenced DB |
| 0xC092 | Local | MB_DATA_PTR is NIL or uninitialized | Verify the DB exists; reload the instance DB |
| 0xC0B0 | Local | Connection not established (CONNECT never pulsed) | Send a one-shot pulse to the CONNECT input on startup |
| 0xC0B1 | Local | MB_MODE value not supported in this library version | Upgrade library to V3.0+ or change to a legacy mode |
| 0x80C8 | Local | Library version mismatch (MB_CLIENT vs MB_COMM_LOAD) | Use matched library versions; clear the reference DB and reinsert |
For a deeper discussion of the specific error originally observed in the source — MB_MODE = 1 with MB_DATA_ADDR = 2200 producing an immediate error — see the Siemens support entry 83130159 on Modbus addressing modes. The document 100633819 further details the offset behavior of the MB_CLIENT instruction across TIA Portal versions.
8. TIA Portal Version Compatibility Matrix
| TIA Portal version | Library | Recommended for this application | |
|---|---|---|---|
| V13 SP1 / V13 SP2 | Modbus_Comm_Load V2.0 / Modbus_Master V2.0 | 0-15 only | Use MB_MODE 1 + offset 42199 / MB_MODE 15 + offset 48000 |
| V14 SP1 / V14 SP2 | Modbus_Comm_Load V3.0 / Modbus_Master V3.0 | 0-115 | Use MB_MODE 103 / 115 (extended) |
| V15 / V15.1 / V16 | Modbus_Comm_Load V4.0 / Modbus_Master V4.0 | 0-115 | Same as V14; F-library bug fixes |
| V17 / V18 / V19 / V20 | Modbus_Comm_Load V5.0+ / Modbus_Master V5.0+ | 0-115 | Same; full CPU 1505/1518 redundancy support |
Modbus_Master name but the mode mapping is unchanged. If you replace the F-block with the newer MB_CLIENT, the mode numbers will not shift — only the addressing convention remains your responsibility.9. Hardware Configuration of the CM PtP
- In the device view of the S7-1500 station, drag the CM PtP RS422/485 module into the configured slot.
- Open the module properties and select RS485 as the interface mode (not RS422 — the power unit is two-wire).
- Set the protocol to Modbus master (RTU) — this auto-fills the
MB_COMM_LOADparameters with 8 data bits, no parity, 1 stop bit, and the user-selected baud rate. - Assign a hardware identifier (e.g.,
HW_ID = 269) — this is the value used by theHW_IDinput ofMB_COMM_LOAD. - Wire
D+to terminalT/R+andD-to terminalT/R-. Activate the internal 120 Ω termination on the module DIP switch if the slave is the last node on the bus and no external terminator is fitted.
10. MB_COMM_LOAD Configuration (One-Shot in OB100)
// OB100 — startup; pulse CONNECT once after CPU restart
"MB_Comm_Load_DB"(REQ := TRUE,
PORT := "CM_PtP".Configuration,
BAUD := 19200,
PARITY := 0, // 0=none, 1=odd, 2=even
FLOW_CTRL := 0, // 0=none (RS485 half-duplex)
RTS_ON_DLY := 0,
RTS_OFF_DLY := 0,
RESP_TO := 1000, // 1000 ms response timeout
DONE => "StartFlag_DB".MbCommLoadDone,
ERROR => "StartFlag_DB".MbCommLoadError,
STATUS => "StartFlag_DB".MbCommLoadStatus);
11. Verification and Commissioning Checklist
| Step | Test | Pass criterion |
|---|---|---|
| 1 | Connect a Modbus RTU sniffer (e.g., on a laptop with a USB-RS485 adapter) in parallel to the bus | Sniffer captures the exact bytes the PLC is sending |
| 2 | Power up the slave, verify it answers poll requests even before the PLC is connected | Sniffer shows valid response frames |
| 3 | Start the PLC program, watch MB_COMM_LOAD.DONE |
DONE pulses TRUE on the first scan |
| 4 | Trigger a single read of register 2200, observe STATUS
|
STATUS = 0 and CurrentRaw updates each cycle |
| 5 | Apply a known load on phase 1 (e.g., 12.3 A) and compare to the scaled reading | Reading matches 12.3 A ±0.1 A (one LSB) |
| 6 | Trigger the 6-register write to 8000-8005 with the password | STATUS = 0, slave acknowledges, alarm flags clear on the next read cycle |
| 7 | Disconnect the cable mid-transaction and observe error handling | ERROR pulses TRUE, STATUS = 0x0081 (timeout), BUSY clears, no CPU stop |
| 8 | Hot-swap the slave (cycle power) and confirm automatic reconnection | First read after reconnection succeeds within two cycles |
12. Troubleshooting Matrix
| Symptom | Most likely cause | First check |
|---|---|---|
| ERROR pulses on every read, STATUS = 0xC0B0 | CONNECT never pulsed | Add a one-shot on first OB100 cycle |
| ERROR with STATUS = 0x0002 | Address out of range (mode/offset mismatch) | Switch to MB_MODE = 103 and use native register numbers |
| ERROR with STATUS = 0x0007 | Password bytes in 8004-8005 are wrong or out of order | Swap high/low word; verify ASCII '33' = 0x33 per byte |
| ERROR with STATUS = 0x0081 | Slave address mismatch or wrong baud | Verify slave ID matches MB_DB.MB_ADDR; check parity and baud in MB_COMM_LOAD |
| ERROR with STATUS = 0x0080 | Electrical noise or missing termination | Add 120 Ω at both ends; shield grounded at PLC end only |
| ERROR with STATUS = 0xC0B1 | MB_MODE not supported in this library version | Upgrade Modbus library to V3.0+ or fall back to mode 1/15 |
| Reads work, writes return 0x0003 | Reserved bits in the command word set to 1 | Mask the command to the exact value the slave manual specifies (e.g., 0xA088 not 0xA088|0x0100) |
| Intermittent timeouts during heavy HMI traffic | CPU scan time exceeds inter-frame gap | Reduce OB1 priority, raise the cyclic interrupt OB for the read call |
13. Performance and Timing Notes
At 19200 baud, a single FC 03 read of one register is approximately 12-15 ms round trip on a clean bus. A six-register FC 16 write is approximately 20-25 ms. Polling a single 1-Hz register consumes negligible CPU time. If you scale up to 50+ registers, switch to a higher baud (38400 or 115200) and consider using a single FC 03 read with MB_DATA_LEN = 50 instead of 50 single-register reads — this cuts the overhead per register from ~5 ms to ~0.4 ms.
14. FAQ
What is the correct MB_MODE for reading holding register 2200 on TIA Portal V14?
Use MB_MODE = 103 with MB_DATA_ADDR = 2200. Mode 103 is the extended FC 03 (Read Holding Registers) that accepts the native register number as written in the slave documentation, removing the need for the 40000 offset that mode 1 requires.
Why does my read fail immediately with MB_MODE=1 and MB_DATA_ADDR=2200?
Mode 1 uses 1-based Modicon addressing, so register 2200 in user documentation maps to PDU address 2199. The correct value is MB_DATA_ADDR = 42199 (offset 40000 + 2199). The STATUS word will typically return 0x0002 (illegal data address) until the offset is corrected.
How do I write six consecutive registers (8000-8005) in one transaction?
Use MB_MODE = 115 (extended FC 16) with MB_DATA_ADDR = 8000 and MB_DATA_LEN = 6. Point MB_DATA_PTR to a DB containing six consecutive UINT words matching the data layout the slave expects. On TIA V13 use MB_MODE = 15 and MB_DATA_ADDR = 48000.
What is the difference between MB_CLIENT and Modbus_Master?
They are functionally identical. Starting with TIA Portal V14, the block was renamed to MB_CLIENT to align with the new MB_SERVER instruction. The input/output parameter set is unchanged. Projects compiled under V13 retain the legacy Modbus_Master name in the program blocks view.
How do I diagnose a STATUS word value of 0xC0B0?
This means the Modbus connection has not been established. Pulse the CONNECT input of MB_CLIENT with a rising edge in the startup OB (OB100) before the first read or write request. The MB_COMM_LOAD block must also report DONE = TRUE with STATUS = 0 for the connection to be active.
Can I use MB_CLIENT on the S7-1500 CPU's onboard RS485 port?
The S7-1500 CPU does not have an onboard serial port. You must add a CM PtP (6ES7540-1AB00-0AA0) or a CP (340/341/440/441) module. The hardware identifier of that module is passed to the HW_ID input of MB_COMM_LOAD.