How Modbus TCP Works in SCADA Systems Explained
In SCADA systems,
Modbus TCP works by using Ethernet to connect the SCADA master (client) with field devices (servers) over a network. It sends requests and receives data like sensor readings or control commands using a simple, standardized message format over TCP/IP.Syntax
The basic syntax of a Modbus TCP message includes a Transaction Identifier, Protocol Identifier, Length, Unit Identifier, Function Code, and Data fields.
Each part has a role:
- Transaction Identifier: Matches requests and responses.
- Protocol Identifier: Always 0 for Modbus.
- Length: Number of bytes following.
- Unit Identifier: Identifies remote device (usually 1).
- Function Code: Defines action (read/write).
- Data: Contains addresses and values.
text
Transaction ID (2 bytes) | Protocol ID (2 bytes) | Length (2 bytes) | Unit ID (1 byte) | Function Code (1 byte) | Data (N bytes)
Example
This example shows a SCADA master reading holding registers from a Modbus TCP device at IP 192.168.1.10 on port 502.
The function code 03 requests to read holding registers starting at address 0x0000, reading 2 registers.
python
import socket # Modbus TCP request to read 2 holding registers starting at address 0 request = bytes([ 0x00, 0x01, # Transaction ID 0x00, 0x00, # Protocol ID 0x00, 0x06, # Length 0x01, # Unit ID 0x03, # Function Code (Read Holding Registers) 0x00, 0x00, # Starting Address Hi, Lo 0x00, 0x02 # Quantity of Registers Hi, Lo ]) with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect(('192.168.1.10', 502)) s.sendall(request) response = s.recv(1024) print('Response:', response.hex())
Output
Response: 000100000705010304000a000b
Common Pitfalls
- Wrong port: Modbus TCP uses port 502; using another port causes connection failure.
- Incorrect function code: Using unsupported codes leads to error responses.
- Addressing errors: Starting address or quantity out of range causes exceptions.
- Ignoring TCP framing: Modbus TCP requires proper header fields; missing them breaks communication.
python
## Wrong way: Missing Transaction ID and Protocol ID wrong_request = bytes([ 0x01, # Unit ID 0x03, # Function Code 0x00, 0x00, # Starting Address 0x00, 0x02 # Quantity ]) ## Right way: Include full Modbus TCP header right_request = bytes([ 0x00, 0x01, # Transaction ID 0x00, 0x00, # Protocol ID 0x00, 0x06, # Length 0x01, # Unit ID 0x03, # Function Code 0x00, 0x00, # Starting Address 0x00, 0x02 # Quantity ])
Quick Reference
| Field | Description | Typical Value/Notes |
|---|---|---|
| Transaction Identifier | Matches request and response | 0x0001 (increments) |
| Protocol Identifier | Protocol type | 0x0000 (Modbus) |
| Length | Number of bytes after this field | Usually 6 |
| Unit Identifier | Slave device ID | 1 (default) |
| Function Code | Action to perform | 0x03 (Read Holding Registers) |
| Data | Addresses and values | Varies by function |
Key Takeaways
Modbus TCP uses Ethernet and TCP/IP to connect SCADA masters with devices using a simple message format.
Each Modbus TCP message has a header with transaction, protocol, length, and unit identifiers before function and data fields.
Common errors include wrong port, missing header fields, and incorrect function codes.
Reading registers involves sending a request with function code 03 and receiving data in the response.
Always use port 502 and follow the Modbus TCP framing to ensure reliable communication.