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 |
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:
- 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.
- Connect pin 2 to DCS "Data A" (also labelled "D+" or "TxD+/RxD+").
- Connect pin 3 to DCS "Data B" ("D-" or "TxD-/RxD-").
- Tie shield to pin 8 at the PLC end; ground the shield at one end only to avoid ground loops.
- Maintain a maximum stub length of < 30 mm if you tap into the middle of an existing bus.
TIA Portal Project Setup and Device Configuration
- Open TIA Portal and create a new project.
- Add the CPU 1214C DC/DC/DC (6ES7 214-1AG40-0XB0) from the hardware catalog.
- 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.
- 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.
- 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 |
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_REGtoDB200. - 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 |
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
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.
Verification, Online Diagnostics, and Status Codes
After downloading the project and placing the CPU in RUN:
- Open Online > Online & Diagnostics on the CM 1241 and confirm Port Status = OK and Transmission Errors = 0.
- Watch
MB_STATE: value 1 = "ready & idle", 2 = "executing a request", 3 = "error". - Pulse
NDR(new data) on every successful write from the master; pulseDR(data read) on every successful master read. - From the DCS side, force a manual poll of register 40001; verify the AI value is returned.
- Force a single-register write to 40015 with the value 16#0007; verify the three command bits in
DB200.CTRL_Wbecome 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
- 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.
- 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.
- 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.
- 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.
- Keep
MB_SLAVEin OB1 with no conditional logic around it - the instruction handles its own state machine and only needs a cyclic call. AddingENgating on slow transitions can cause missed polls. - 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.
- Use
RDREC/WRRECon the CM 1241 only if you need non-standard diagnostics; the STATUS outputs of MB_SLAVE cover 95% of field issues. - 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.