Home / Modbus Holding Register Simulator

Modbus Holding Register Simulator - Complete Testing Guide

Updated March 23, 2026 · 10 min read · For PLC programmers, SCADA engineers, and industrial automation testers

Holding registers (address range 40001-49999) are the workhorse of Modbus communication. They store process variables, setpoints, configuration parameters—anything that needs to be both read and written by master devices. If you're testing a PLC, SCADA system, or industrial IoT gateway, you'll spend most of your time working with holding registers.

This guide explains how holding registers work, when to use function codes FC03 and FC16, and how to test them effectively using a simulator.

What Are Modbus Holding Registers?

Holding registers are 16-bit read/write registers used to store numerical data in Modbus devices. Each register holds a value from 0 to 65,535 (unsigned) or -32,768 to +32,767 (signed).

Addressing Convention

Holding registers use addresses 40001-49999 in the Modbus specification. However, internally, they're 0-indexed. Address 40001 corresponds to internal address 0, 40002 to address 1, and so on. This causes endless confusion. Always check your device's documentation for its addressing convention.

What's Stored in Holding Registers?

Function Codes for Holding Registers

Function CodeNameDescriptionUse Case
FC03Read Holding RegistersRead 1-125 consecutive registersPoll sensor values, read configuration
FC06Write Single RegisterWrite one 16-bit value to one registerUpdate a single setpoint
FC16Write Multiple RegistersWrite 1-123 consecutive registersBulk configuration, recipe download
FC23Read/Write Multiple RegistersRead and write in one transactionAtomic read-modify-write operations

Most applications use FC03 (Read) and FC16 (Write Multiple). FC06 is less common because FC16 can write a single register too. FC23 is rare—only newer devices support it.

How FC03 (Read Holding Registers) Works

FC03 is the most commonly used Modbus function code. A master sends a request specifying:

The slave responds with the requested register values as 16-bit integers.

Example: Reading Temperature from Register 40001

Request (Master → Slave):
Function Code: 0x03 (FC03)
Starting Address: 0x0000 (register 40001, 0-indexed)
Quantity: 0x0001 (read 1 register)

Response (Slave → Master):
Function Code: 0x03
Byte Count: 0x02 (2 bytes = 1 register)
Register Value: 0x00E2 (226 decimal = 22.6°C if scaled by 10)

If the device stores temperature as an integer (22.6°C → 226), you apply the scaling factor after reading.

Reading Multiple Registers

To read 10 consecutive temperature sensors stored in registers 40001-40010:

Function Code: 0x03
Starting Address: 0x0000
Quantity: 0x000A (10 registers)

Response: 20 bytes (10 registers × 2 bytes each)

This returns all 10 values in one transaction, reducing network overhead compared to 10 individual FC03 requests.

How FC16 (Write Multiple Registers) Works

FC16 writes 1-123 consecutive holding registers in a single transaction. The master specifies:

Example: Writing Setpoint to Register 40050

Request (Master → Slave):
Function Code: 0x10 (FC16)
Starting Address: 0x0031 (register 40050, 0-indexed as 49)
Quantity: 0x0001 (write 1 register)
Byte Count: 0x02
Register Value: 0x01F4 (500 decimal = 50.0°C setpoint if scaled by 10)

Response (Slave → Master):
Function Code: 0x10
Starting Address: 0x0031
Quantity: 0x0001 (confirms 1 register written)

Bulk Configuration Example

Writing 5 registers at once (configuration block for a VFD):

Starting Address: 0x0064 (register 40101)
Quantity: 0x0005 (5 registers)
Values: [1500, 3000, 100, 50, 0] → Motor speed limits, accel/decel rates

FC16 is atomic—all registers are written together. If any register fails, the entire operation fails (though not all devices implement this correctly).

Data Types in Holding Registers

Holding registers store 16-bit integers, but real-world data often requires other formats:

16-bit Signed/Unsigned Integer

Native format. Unsigned: 0-65,535. Signed: -32,768 to +32,767.

32-bit Integer (2 Registers)

Two consecutive registers combine to form a 32-bit value. Example: Registers 40001-40002 store a large counter value (0 to 4,294,967,295).

Endianness matters: Big-endian (high word first) vs little-endian (low word first). Modbus standard is big-endian, but some devices use little-endian. Always check.

32-bit Float (2 Registers)

IEEE 754 floating-point values require 2 registers. Example: Precise temperature reading 23.456°C stored as float.

Byte order variations: ABCD (big-endian), DCBA (little-endian), BADC, CDAB. You must match the device's byte order or data looks like garbage.

ASCII Strings

Text data (device name, serial number) can be stored as ASCII characters—2 characters per register. Example: "MOTOR-A" uses 4 registers.

Common Testing Scenarios

1. PLC Register Map Validation

You've programmed a PLC with a register map:

Use a holding register simulator in master mode to:

  1. Read registers 40001-40003 (FC03) and verify values match sensor readings
  2. Write register 40010 (FC16) with a new setpoint and verify the PLC updates its control logic
  3. Monitor the request log to ensure no exception codes (0x02 Illegal Data Address, 0x03 Illegal Data Value)

2. SCADA Polling Simulation

Your SCADA polls 20 holding registers every second from 30 devices. Before deployment, verify the network can handle this load.

Set up a holding register simulator in slave mode with 20 registers mapped. Configure the SCADA to poll it. Monitor:

3. 32-bit Float Endianness Testing

You're integrating a flow meter that reports flow rate as a 32-bit float in registers 40005-40006. The documentation says "Modbus TCP big-endian" but values read as 1.4e+38 (clearly wrong).

Test with a simulator:

  1. Configure a slave with a known float value (e.g., 123.456) in registers 40005-40006
  2. Read with a master and try all 4 byte orders: ABCD, DCBA, BADC, CDAB
  3. Whichever byte order displays 123.456 correctly is what the device uses

4. Multi-Master Conflict Detection

Two SCADA systems write to the same holding register setpoint. You need to detect conflicts.

Run a slave simulator with a register that logs all write operations with timestamps. Review the log to see if two masters write different values within milliseconds of each other.

Setting Up a Holding Register Simulator

Slave Mode Configuration

To simulate a device with holding registers:

ModbusSimulator Slave Setup:
1. Launch in Slave Mode
2. Protocol: Modbus TCP (or RTU/ASCII if testing serial)
3. Port: 502 (TCP) or COM port (RTU/ASCII)
4. Unit ID: 1
5. Configure Register Map:
- Register 40001: Value 2250 (temperature 22.5°C)
- Register 40002: Value 1850 (temperature 18.5°C)
- Register 40003: Value 500 (flow rate 50.0 L/min)
- Register 40010: Value 2000 (setpoint 20.0°C)
6. Start Server → Listening on port 502

Now a master can connect and read/write these registers.

Master Mode Testing

To test a real PLC or another simulator:

ModbusSimulator Master Setup:
1. Launch in Master Mode
2. Connection: TCP → IP 192.168.1.100, Port 502, Unit ID 1
3. Read Configuration:
- Function Code: FC03
- Starting Address: 40001
- Quantity: 10 registers
4. Click "Read" → View register values in the table
5. Write Configuration:
- Function Code: FC16
- Starting Address: 40010
- Value: 2300 (new setpoint 23.0°C)
6. Click "Write" → Verify PLC updates

Troubleshooting Holding Register Issues

Exception 0x02: Illegal Data Address

Cause: The register address doesn't exist in the slave's memory map.

Fix: Check the device documentation. Some PLCs start at 40001, others at 40000. Some use 0-based indexing internally.

Exception 0x03: Illegal Data Value

Cause: You're writing a value outside the allowed range (e.g., writing 70000 to a register with a max of 1000).

Fix: Check the register's valid range in the device manual. Respect min/max limits.

Values Are Byte-Swapped

Cause: Endianness mismatch for 32-bit values (integers or floats).

Fix: Toggle byte order in your simulator or SCADA software. Try ABCD → DCBA → BADC → CDAB until values make sense.

Register Updates Don't Persist After Power Cycle

Cause: Some devices store holding register values in RAM, not flash.

Fix: Check if the device has a "Save Configuration" function code or separate configuration registers that persist to non-volatile memory.

ModbusSimulator: Professional Holding Register Testing

ModbusSimulator provides a complete environment for testing holding registers with both master and slave modes in one application.

Master Features

  • FC03 read with 1-125 register support
  • FC16 write with bulk register updates
  • Real-time register value display
  • 16-bit, 32-bit integer, and float data types
  • Endianness toggle for 32-bit values
  • Request/response logging with timestamps

Slave Features

  • Configure custom register maps (40001-49999)
  • Set initial values for each register
  • Manual override during testing
  • Log all incoming FC03/FC06/FC16 requests
  • Multiple slave instances on different unit IDs
  • CSV export of register access history

Why Engineers Choose ModbusSimulator

One license includes both master and slave for $99 (competitors charge $129 each). 30-day free trial with all features unlocked. No subscription, lifetime updates included.

Test Holding Registers Without Hardware

Simulate any Modbus device • Test FC03/FC16 operations • Free 30-day trial

Download Free Trial

FAQ

What's the difference between holding registers and input registers?

Holding registers (40001-49999) are read/write. Input registers (30001-39999) are read-only. Use holding registers for setpoints and configuration. Use input registers for sensor data that the PLC doesn't allow external writes to.

Can I write to input registers?

No. Input registers are read-only via FC04. Attempting to write with FC06/FC16 to addresses 30001-39999 will return exception 0x02 (Illegal Data Address) on most devices.

How many holding registers can I read/write at once?

FC03: Read up to 125 registers in one request.
FC16: Write up to 123 registers in one request.
Limits exist to keep Modbus frames under 256 bytes.

What happens if I read registers that don't exist?

The slave responds with exception code 0x02 (Illegal Data Address). This is normal—it means the register isn't mapped.

Can holding registers store negative numbers?

Yes, if interpreted as signed 16-bit integers (-32,768 to +32,767). The Modbus protocol doesn't specify signed vs unsigned—it's up to the device manufacturer. Always check documentation.

Related Resources

Learn more: Modbus Poll vs ModbusSimulator comparison · Complete guide to all 4 Modbus register types

Publishing technical documentation? IndexFlow automates Google indexing to get your pages crawled faster.