Configuring S7-1200 as Modbus RTU Slave for Bidirectional Data

David Krause14 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

Modbus RTU Master/Slave Fundamentals for S7-1200

Modbus is a strictly client/server architecture in master/slave terminology. The S7-1200 acting as a Modbus slave is a passive device: it never initiates a transaction on the RS485 bus. The DCS (master) is the only node permitted to poll the bus, and only the master can read or write registers on the slave. The slave only responds when its station address is queried.

Key constraints:

  • Only one master is allowed per RS485 segment.
  • A slave cannot request data, cannot push data, and cannot speak to another slave.
  • Function codes 03 (Read Holding Registers), 06 (Write Single Register), 16 (Write Multiple Registers), and broadcast write (Function code 10 with station address 0) are supported by MB_SLAVE.
  • Hold registers are the bidirectional data container - the same register address can be read or written depending on what the master requests.

This distinction matters when you wire the CPU 1214C to a third-party DCS: the S7-1200 will expose a contiguous block of holding registers, and the DCS decides per register whether to poll (read) or set (write). The PLC does not have separate "read-only" and "write-only" registers; access direction is decided by the master on every transaction.

Prerequisites: Hardware and Firmware Requirements

Component Article Number Firmware Notes
S7-1200 CPU 1214C DC/DC/DC 6ES7 214-1AG40-0XB0 V4.2 or higher recommended 14 digital inputs / 10 digital outputs / 2 AI onboard
CM 1241 RS485 communication module 6ES7 241-1CH30-0XB0 V2.1 or higher Plug-in submodule, occupies signal board slot
TIA Portal V15.1 or higher (V17 preferred) - Includes MB_SLAVE V3.x instruction library
S7-1200 Programmable controller system manual Siemens online support entry ID: 109751706 - Reference for PtP/Modbus RTU chapter
Note: CM 1241 (RS485) with article number 6ES7 241-1CH30-0XB0 requires CPU firmware V4.0 or higher. CPU 6ES7 214-1AG40-0XB0 is the second-generation "AG40" hardware revision and ships with V4.x firmware; verify with Online > Accessible Nodes before commissioning.

CM 1241 RS485 Wiring and Termination

The CM 1241 RS485 uses a 9-pin sub-D male connector on the front face. The pinout is non-standard compared to legacy PC COM ports:

Pin Signal Description
2 T/R+ Receive/Transmit positive (Data A)
3 T/R- Receive/Transmit negative (Data B)
5 GND Reference ground / shield drain
7 +5V (terminator) Internal 120 ohm bias network, switch on termination slider
8 Shield Cable shield connection point

For RS485 bus termination:

  1. Slide the termination switch on the bottom of the CM 1241 to ON if the PLC is the first or last physical device on the bus segment.
  2. Connect pin 2 to DCS "Data A" (also labelled "D+" or "TxD+/RxD+").
  3. Connect pin 3 to DCS "Data B" ("D-" or "TxD-/RxD-").
  4. Tie shield to pin 8 at the PLC end; ground the shield at one end only to avoid ground loops.
  5. Maintain a maximum stub length of < 30 mm if you tap into the middle of an existing bus.
Warning: Reversing A/B is the most common wiring fault on Modbus RS485 segments and will not produce a hard error - it will simply yield CRC faults. Always measure with a multimeter: Data A is the more positive line when the bus is idle.

TIA Portal Project Setup and Device Configuration

  1. Open TIA Portal and create a new project.
  2. Add the CPU 1214C DC/DC/DC (6ES7 214-1AG40-0XB0) from the hardware catalog.
  3. Open Device View and drag the CM 1241 (RS485) module (6ES7 241-1CH30-0XB0) into the left communication slot of the signal board area. Although the part is a submodule physically mounted on the CPU front, in TIA it is configured as a slot to the left of the CPU.
  4. Right-click the CM 1241 and open Properties > Port Configuration.
    • Set Baud rate: 9600 (default for most DCS systems).
    • Set Parity: Even (Modbus RTU standard).
    • Set Data bits: 8.
    • Set Stop bits: 1.
    • Set Flow control: None.
  5. Assign a unique Modbus slave address in Properties > Modbus (e.g. station 3). The DCS must use the same station number when polling.

MB_COMM_LOAD Instruction Configuration

The MB_COMM_LOAD block initialises the CM 1241 port and is called once on PLC warm restart (OB100) or first scan (OB1 with a one-shot). It does not perform any Modbus transactions itself.

Input Type Required Value Purpose
REQ BOOL TRUE (one-shot) Triggers port initialisation
PORT PORT (HW_IO) CM 1241 HW identifier Identifies physical port
BAUD DINT 9600 9600 / 19200 / 38400 / 57600 / 115200
PARITY UINT 2 0=None, 1=Odd, 2=Even
FLOW_CTRL UINT 0 0=None (RS485 half-duplex does not use RTS)
RTS_ON_DLY UINT 0 Not used for Modbus RTU
RTS_OFF_DLY UINT 0 Not used for Modbus RTU
RESP_TO UINT 1000 Response timeout in ms (master side - not used by slave)
DONE BOOL output Initialisation complete
ERROR BOOL output Error flag
STATUS WORD output Error code if ERROR=TRUE
Clarification on "Mode 4": The MODE parameter is sometimes confused with baud or parity selection. In TIA Portal V15+, MB_COMM_LOAD uses discrete BAUD, PARITY, and FLOW_CTRL inputs and does not require a Mode selector. Earlier STEP 7 Basic V10.5 versions used a combined MODE integer (4 = half-duplex Modbus slave on CM 1241). If you imported legacy code, replace the MODE constant with the explicit parameter form shown above.

MB_SLAVE Instruction Setup for Bidirectional Data

The MB_SLAVE instruction is called from a cyclic OB (typically OB1). It makes a contiguous range of the PLC's data accessible as Modbus holding registers (function codes 03, 06, 16) plus broadcast writes.

Pin reference (TIA Portal V15+ MB_SLAVE V3.1):

Pin Direction Type Description
MODE IN UINT 0 = disabled, 1 = enabled (process requests)
DATA_ADDR IN DWORD Start address in the hold register DB (offset)
DATA_LEN IN UINT Number of words exposed (1..125)
MB_HOLD_REG IN_OUT VARIANT Pointer to a standard-access DB containing the holding registers
NDR OUT BOOL New data written by master (TRUE for one cycle)
DR OUT BOOL Data read by master (TRUE for one cycle)
ERROR OUT BOOL Error flag
STATUS OUT WORD Error code (see troubleshooting matrix)
MB_STATE OUT BYTE 0=not initialised, 1=ready, 2=busy, 3=error

For the application described - 14 words inbound to the DCS and 3 bits inbound from the DCS - the most common mapping is:

  • Allocate a global DB (e.g. DB200 "ModbusHold") with at least 16 WORD entries.
  • Point MB_HOLD_REG to DB200.
  • Set DATA_ADDR = 0 (start at the first word).
  • Set DATA_LEN = 16 (14 measurement words + 1 control word + 1 status word - adjust to match DCS register map).

The first 14 words are written by the PLC program from I/O signals (read by the DCS). Word 15 contains the 3 bits that the DCS writes back to the PLC. Because the same register block is read/write, you do not need a separate MB_MASTER block - the direction of each register is controlled entirely by the master's request.

Modbus Address Mapping Table for the Application

The DCS sees the slave as a contiguous block of holding registers starting at Modbus address 40001 (or 40000 depending on the DCS vendor's 1-based vs 0-based convention):

Modbus Register (4xxxx) DB200 Offset (bytes) Direction Signal
40001 0 PLC → DCS (Read) Process value 1
40002 2 PLC → DCS (Read) Process value 2
40003 4 PLC → DCS (Read) Process value 3
... ... PLC → DCS (Read) ...
40014 26 PLC → DCS (Read) Process value 14
40015 28 DCS → PLC (Write) Control word (bit 0..2 = the 3 commands)
40016 30 PLC → DCS (Read) Status / heartbeat
Important: Confirm with the DCS engineers which Modbus addressing convention they use. Some vendors (Schneider, some Honeywell DCS) treat holding registers as 1-based (40001 = first register). Others (some ABB 800xA drivers) treat them as 0-based. A one-register offset mismatch appears as a "valid response with garbage values" rather than a hard fault.

LAD/FBD Program Example with Hold Register DB

Data block definition (DB200 "ModbusHold") in TIA Portal:

DATA_BLOCK "ModbusHold"
{ S7_Optimized_Access := 'FALSE' }
STRUCT
    PV_01 : WORD;    // DBW0  -> 40001
    PV_02 : WORD;    // DBW2  -> 40002
    PV_03 : WORD;    // DBW4  -> 40003
    PV_04 : WORD;    // DBW6  -> 40004
    PV_05 : WORD;    // DBW8  -> 40005
    PV_06 : WORD;    // DBW10 -> 40006
    PV_07 : WORD;    // DBW12 -> 40007
    PV_08 : WORD;    // DBW14 -> 40008
    PV_09 : WORD;    // DBW16 -> 40009
    PV_10 : WORD;    // DBW18 -> 40010
    PV_11 : WORD;    // DBW20 -> 40011
    PV_12 : WORD;    -> DBW22 -> 40012
    PV_13 : WORD;    // DBW24 -> 40013
    PV_14 : WORD;    // DBW26 -> 40014
    CTRL_W : WORD;   // DBW28 -> 40015 (DCS writes here)
    STATUS  : WORD;   // DBW30 -> 40016
END_STRUCT;
END_DATA_BLOCK
The block must be non-optimized (standard access) so that MB_SLAVE can address it by absolute byte offset. Optimized symbolic access is not supported by MB_SLAVE/MASTER.

OB100 - initialise port (called once on restart):

// OB100 - Warm restart
      CALL "MB_COMM_LOAD"
        REQ       := TRUE                // one-shot
        PORT      := "CM1241_1_ID"       // HW identifier from device config
        BAUD      := 9600
        PARITY    := 2                   // even
        FLOW_CTRL := 0
        RESP_TO   := 1000
        DONE      => "mb_load_done"
        ERROR     => "mb_load_err"
        STATUS    => "mb_load_status";

OB1 - cyclic slave execution:

// OB1 - Main
      CALL "MB_SLAVE"
        MODE       := 1
        DATA_ADDR  := 0                  // start at offset 0 of DB200
        DATA_LEN   := 16                 // expose 16 holding registers
        MB_HOLD_REG:= "DB200".PV_01      // pointer to first word
        NDR        => "mb_ndr"           // pulses when DCS writes
        DR         => "mb_dr"            // pulses when DCS reads
        ERROR      => "mb_err"
        STATUS     => "mb_status"
        MB_STATE   => "mb_state";

// Map process I/O into PV_01..PV_14
      "DB200".PV_01 := "IW64";            // AI0 scaled value
      "DB200".PV_02 := "IW66";            // AI1
      ... (repeat for all 14 process values) ...

// Decode the 3 DCS command bits from CTRL_W
      "DCS_CMD_1"  := "DB200".CTRL_W.%X0; // bit 0 of word 15
      "DCS_CMD_2"  := "DB200".CTRL_W.%X1; // bit 1
      "DCS_CMD_3"  := "DB200".CTRL_W.%X2; // bit 2

// Heartbeat / status
      "DB200".STATUS := "Heartbeat_Counter";

Direction of Data Flow: Read vs Write Clarification

Many engineers expect the S7-1200 to distinguish between "read registers" and "write registers" via two separate blocks. It does not. MB_SLAVE exposes a single buffer that supports all three standard Modbus data functions:

  • Function code 03 - Read Holding Registers (master polls, slave returns register contents).
  • Function code 06 - Write Single Register (master writes one word, slave echoes it back).
  • Function code 16 - Write Multiple Registers (master writes up to 123 contiguous words, slave returns ack).

The 14 "read-only" process values from the DCS perspective are simply registers that the DCS chooses never to write. The 3 bits the DCS sends back are simply a register that the DCS chooses to write via FC06 or FC16. There is no slave-side logic that prevents the master from writing register 40001 - it is allowed by Modbus protocol.

Safety caveat: If the DCS engineers inadvertently write to registers 40001..40014 (intended as read-only), the PLC program will overwrite them on the next scan with the AI values, masking the write but potentially confusing the operator. Document the register map in the project folder and have both teams sign off on it before energising the bus.

Verification, Online Diagnostics, and Status Codes

After downloading the project and placing the CPU in RUN:

  1. Open Online > Online & Diagnostics on the CM 1241 and confirm Port Status = OK and Transmission Errors = 0.
  2. Watch MB_STATE: value 1 = "ready & idle", 2 = "executing a request", 3 = "error".
  3. Pulse NDR (new data) on every successful write from the master; pulse DR (data read) on every successful master read.
  4. From the DCS side, force a manual poll of register 40001; verify the AI value is returned.
  5. Force a single-register write to 40015 with the value 16#0007; verify the three command bits in DB200.CTRL_W become TRUE in the watch table.

MB_SLAVE STATUS Word Decoding (common values)

STATUS (hex) Meaning Remedy
0000 No error -
16#8180 Wrong MB_HOLD_REG pointer or block optimised Set DB attribute "Optimised block access" = FALSE
16#8181 Wrong data type for MB_HOLD_REG Pointer must reference a WORD array or WORD field
16#8182 DATA_ADDR out of range Offset must be inside the target DB
16#8183 DATA_LEN out of range 1..125 words; reduce if master requests more
16#8184 Pointer + DATA_LEN exceeds DB size Increase DB length or lower DATA_LEN
16#8185 Pointer not aligned to WORD boundary Start at even byte offset only
16#818C MB_COMM_LOAD not yet executed Trigger MB_COMM_LOAD in OB100 before MB_SLAVE runs
16#80A0 Parity error detected on received frame Check baud, parity, wiring; check A/B polarity
16#80A1 Framing error Wrong baud rate or stop bits
16#80A2 Overrun error DCS polling too fast for PLC scan time; add delay
16#80A3 CRC error from master Electrical noise on bus; add bias resistors, check shield

Troubleshooting Matrix for Common Faults

Symptom Likely Cause Diagnostic Fix
DCS reports "no response" / timeout A/B swapped, no termination, wrong station Measure voltage on idle bus: Data A is more positive (~ +0.2..+0.6 V relative to B) Swap A/B, enable terminator switch, verify station number matches in both projects
DCS reads 0xFFFF for every register MB_COMM_LOAD not executed, MB_STATE stuck at 0 Online watch table on MB_COMM_LOAD DONE bit Place MB_COMM_LOAD call in OB100 with REQ=TRUE on first cycle
Reads work, writes return exception 02 (illegal address) DATA_LEN too short to expose register 40015 Watch MB_STATE during master write Increase DATA_LEN to cover all registers the master writes
Reads work, writes return exception 04 (slave failure) DB is optimised or pointer wrong Check DB properties and STATUS word Disable optimised access; re-link MB_HOLD_REG pin
Occasional CRC errors under load Missing termination, ground loop, long stub Increment MB_SLAVE error counter over time Enable terminator, single-point shield ground, shorten stubs
DCS reads wrong register values Off-by-one addressing (40001 vs 40000) Force known value in DB and read at both addresses Apply offset to DCS register configuration
PLC ignores master write MODE input stuck at 0 Watch MB_SLAVE MODE pin Hard-code MODE := 1 or wire from a startup tag

Best Practices and Field-Commissioning Tips

  1. Always start with a single register loop-back test: have the DCS write 16#1234 to register 40015 and verify the same value appears in the PLC's watch table before commissioning the full register map.
  2. Document the Modbus address map (register number, direction, scaling, engineering unit) in a shared CSV and put it under version control. This is the single most important piece of project documentation for any Modbus interface.
  3. Add a "heartbeat" register (e.g. STATUS = a free-running counter) that the DCS can poll to detect a frozen slave. Increment it once per PLC scan; if the DCS sees the same value twice in a row, raise an alarm.
  4. For RS485 buses longer than 30 m or with more than three devices, bias the bus with external 680 ohm pull-up on Data A to +5 V and 680 ohm pull-down on Data B to GND at the master. The CM 1241 has internal bias only when termination is enabled.
  5. Keep MB_SLAVE in OB1 with no conditional logic around it - the instruction handles its own state machine and only needs a cyclic call. Adding EN gating on slow transitions can cause missed polls.
  6. Disable unused Modbus function codes if the master is misbehaving. The instruction supports FC01/02/03/04/05/06/15/16, but you cannot filter at the slave - instead, restrict the master's address range.
  7. Use RDREC/WRREC on the CM 1241 only if you need non-standard diagnostics; the STATUS outputs of MB_SLAVE cover 95% of field issues.
  8. When migrating to a CPU 1215C or 1217C, the same CM 1241 article and the same MB_SLAVE V3.1 instruction are forward-compatible. No code changes are required.

Does MB_SLAVE support both Modbus RTU and Modbus ASCII?

Yes. The protocol selection is made on the MB_COMM_LOAD block, not on MB_SLAVE. Set PARITY = 0 for Modbus RTU with no parity (8N1), PARITY = 2 for the common Modbus RTU 8E1 variant, or PARITY = 1 for odd parity ASCII. The slave itself does not care which framing is in use.

Can the S7-1200 expose both input registers (3xxxx) and holding registers (4xxxx)?

Only holding registers (4xxxx). MB_SLAVE responds to function codes 03, 06, 16 (holding registers), plus FC05/15 for coils emulation via the same buffer if you point it to a bit-mapped DB. Function codes 04 (input registers) are not supported; if the DCS master only polls FC04, you must convince it to use FC03.

How many holding registers can MB_SLAVE expose in a single call?

1 to 125 words. Set DATA_LEN = 125 and size the hold-register DB accordingly if the DCS will read/write the maximum Modbus RTU payload of 123 words plus a few spares.

What happens if the DCS sends a broadcast (station address 0) write?

MB_SLAVE supports broadcast write requests (Function code 16 with station address 0) as long as the address range falls inside the configured DATA_ADDR..DATA_ADDR + DATA_LEN - 1 window. No slave response is transmitted, which is standard Modbus RTU behaviour.

Why does my DB need to be non-optimised?

MB_SLAVE addresses the buffer by absolute byte offset (DATA_ADDR). Optimised (symbolic-only) DBs rearrange variables in memory and do not expose predictable offsets. Set the DB attribute "Optimised block access" = FALSE in TIA Portal before wiring MB_HOLD_REG to it.

Can two Modbus masters poll the same S7-1200 slave?

No. The Modbus RTU standard forbids multiple masters on the same bus segment. The CM 1241 will respond to whichever master wins arbitration first, and the second master's poll will time out. Use a Modbus gateway or dual CM 1241 modules (on different ports) if dual-master access is required.

Back to blog