Put an HMI panel on a custom Modbus RTU slave

7 min read · Published November 7, 2026

The HMI panel runs the Modbus RTU master, so your firmware must answer as the slave. Set both ends to 9600 baud, 8 data bits, even parity and 1 stop bit, give your device unit address 1, and prove the link with a single read-only holding register that returns 1234. Build screens only after that value displays.

An HMI panel that speaks Modbus RTU is almost always set up as the master. It polls; your device answers. That makes your microcontroller firmware an RTU slave, and the job is bounded: one serial combination, one unit address, one register map, and replies that fit the frame timing. Prove all four with a single read-only register before you draw any screen, because a finished screen cannot tell a wiring fault from a wrong register number. This article gives the settings and their arithmetic, the exact bytes of a working request and reply, the bring-up steps, and the check order when nothing answers.

The roles, and the two documents behind them

Read the panel manual's communications chapter first and note the configured role. Some manuals say client and server; the mapping is client = master, server = slave. The common case drives everything below:

Panel project Your firmware Proof of a working link
Panel polls as Modbus RTU master Answer as an RTU slave on one unit address A correct reply to the first read
Panel exposes its data as a Modbus slave Poll it as a master The panel's values appear on your side

Two documents govern the exchange: the application protocol specification V1.1b3 defines the function codes, the register tables and the exception responses, and the serial line specification V1.02 defines the character format, the frame timing and the CRC. Both are free downloads from the protocol's own site; keep them next to the project, because every number in this article traces to one of the two.

One serial combination on both ends

Use 9600 baud, 8 data bits, even parity and 1 stop bit on both ends, written 9600 8E1. The panel manual lists the combinations its driver accepts, and whichever one you pick, the firmware must mirror it exactly. With parity, an RTU character is 11 bits: 1 start, 8 data, 1 parity, 1 stop. At 9600 baud that is 11 ÷ 9600 = 1.15 ms of line time per character, and the frame rules follow from it:

  • A silence of 3.5 characters closes a frame: 3.5 × 1.15 ms ≈ 4.0 ms.
  • A silence over 1.5 characters, 1.5 × 1.15 ≈ 1.7 ms, inside a frame marks it incomplete. Discard it and wait for the next frame.
  • Start your reply only after the request's 4.0 ms of silence has passed, then send it as one continuous burst.

Your receiver needs three habits. Verify the CRC on every frame: RTU uses CRC-16, initial value 0xFFFF, reflected polynomial 0xA001, transmitted low byte first. Discard a frame with a bad CRC silently; the panel learns of it through its own timeout. And act only on frames that carry your unit address.

On the wire this is a two-wire RS-485 pair: A to A, B to B, short drop stubs, and 120 Ω termination at each end of the pair if the run goes beyond a few meters. Set the panel's response timeout to 500 ms or leave the usual 1000 ms default; your firmware should put the first reply byte on the wire within single-digit milliseconds of finishing the request.

One unit address

Set the device to unit address 1, called station number or slave ID in some manuals, and put the same number in the panel project. The serial line spec allows slave addresses 1 through 247; address 0 is broadcast, which every slave acts on and none ever answers, and 248 through 255 are reserved. On a two-device link nothing collides, and address 1 leaves the rest of the range free for devices added later.

The register map, one row per value

Write the map before the driver. One row per value the screens will use, with both address conventions filled in:

Value Panel reference Protocol address Function Count Access
Test value 40001 0x0000 03 read holding registers 1 read only

Function 03 reads holding registers, and the reference convention is the classic trap: many panel drivers enter 40001 for protocol address 0x0000, others take the raw four-digit offset. An off-by-one here returns a valid reply with the wrong value, or an exception, and either one reads as a firmware bug. Decide the convention from the panel manual and record both numbers in the row.

Start read-only, with a value you chose, so a correct link is distinguishable from a lucky one. Writes come after the read path is verified: function 06 writes one register, function 16, written 0x10 in hex, writes a block, and the first write target is a test variable with no path to any output.

When the panel asks for a function or an address you have not implemented, reply with an exception: the function code plus 0x80, so 03 becomes 83, then one code byte. 01 illegal function, 02 illegal data address, 03 illegal data value. That reply tells the panel your map lacks the entry, which is a different fault from silence.

If the master side is a CODESYS runtime rather than a panel, the same rows are what its device descriptor holds; the mapping work is described in Build a custom Modbus RTU device descriptor in CODESYS.

Scenario: panel and your device on the bench, RS-485 pair between them, no machine attached. Panel project: 9600 baud, 8 data bits, even parity, 1 stop bit, unit address 1, function 03, register 40001, quantity 1, response timeout 1000 ms. Your firmware holds 1234, which is 0x04D2, in holding register 0x0000 and implements nothing else yet.

The panel puts 8 bytes on the wire: 01 03 00 00 00 01 84 0A. Unit 1, function 03, start address 0x0000, quantity 0x0001, then CRC 84 0A, low byte first. Check your CRC routine against these six payload bytes first: initial value 0xFFFF with the reflected polynomial 0xA001 gives 0x0A84, sent as 84 0A. A byte-order bug in the checksum surfaces here in one minute.

After the 4.0 ms of silence, your firmware answers with 7 bytes: 01 03 02 04 D2 3A D9. Unit 1, function 03, byte count 02, the value 0x04D2, then CRC 3A D9. The reply is 7 characters × 11 bits = 77 bits on the wire, and 77 ÷ 9600 baud = 8.0 ms, so the 1000 ms timeout carries margin for ordinary processing delays.

When the panel screen shows 1234, the wiring, framing, CRC, unit address and first map row are all checked in one pass. Only then do screens earn their build time.

The bring-up steps

  1. Write the register map first: one row per value, with the panel reference, the protocol address, the function, the count, the data type, the word order and the access.
  2. Set the panel project to the serial combination above, unit address 1, function 03, register 40001, quantity 1, response timeout 1000 ms.
  3. In firmware, close a frame on 4.0 ms of line silence, verify the CRC, and discard silently on a CRC failure or a unit address other than 1.
  4. Answer function 03 inside the map, and reply to everything outside it with the exception form: function plus 0x80, code 02 for a missing address.
  5. Load 1234 into register 0x0000 and implement nothing else.
  6. Bench test with a third RS-485 adapter as a tap, and compare the bytes on the wire with 01 03 00 00 00 01 84 0A.
  7. Once 1234 displays, build the screens, then add one write with function 06 to a test register and confirm the value arrives unchanged in the firmware.

How to check it worked

Power-cycle both devices and let the panel poll again. RTU keeps no session, so the first poll after your firmware is up should return 1234 with no timeout error.

Three outcomes cover the bench, each with its own fix:

  • Request visible on the tap, no reply: the bytes never arrived as an acceptable frame. Check in order: A and B swapped, a baud or parity difference, a unit address mismatch, then your CRC routine against the test frame.
  • The panel shows exception 83 with code 02: the link is good and the panel asked for an address outside the map. Fix the reference convention in the project.
  • A reply arrives with the wrong value: the link is good and the map row is wrong: scaling, signedness or word order.

The same three faults look different from the master's chair; Modbus RTU master no reply and address errors: fix both walks the panel side.

Recommendation and decision

Recommendation: bring the link up at 9600 baud, 8E1, unit address 1, with one read-only holding register at protocol address 0x0000 returning 1234, and draw no screen until that value displays. If the panel's driver has no even-parity option, use its no-parity format with 2 stop bits and change nothing else; any single combination works while both ends match it. Add writes only after the test register displays, and route a panel value to an output only through deliberate logic in the firmware. One safety note: a Modbus link carries data and no interlocks, so whatever must stop the machine stops it in hardware or in firmware logic that runs without the screen.

The decision, case by case: no reply, fix wiring, then settings, then CRC; an exception, fix the map reference; a wrong value, fix the data row. Each check takes minutes once the tap is on the line.

The HMI link serves the operator at the machine. A wall board for the rest of the line is a separate screen with a separate job; the shop-floor signage screens category covers those.

Questions

What if the panel's serial port offers no parity setting?

Use the serial line spec's other accepted format: 8 data bits, no parity, 2 stop bits. Both accepted formats carry 11 bits per character, so at 9600 baud the timings hold: 1.15 ms per character and 4.0 ms of silence to close a frame. Set the identical combination on the panel and in the firmware, and nothing else in this article changes.

How many registers can one Modbus read carry?

A function 03 or 04 read returns up to 125 registers in one exchange, and a function 16 write covers up to 123. Keep early screens to a handful of rows. Every register in a block still uses its two data bytes on the wire, and a register your map never implemented answers with exception code 02, so the screen shows a fault instead of a plausible zero.

Do I still need a PLC between the panel and my device?

No. The panel polls your device directly over the RS-485 pair, and Modbus carries data only. A PLC would normally supply interlocks, sequencing and fault handling, and those have to exist somewhere: in your firmware as deliberate logic, or in hardware safety devices. If the machine has to stop when the link is down, that requirement sits outside the protocol.

Planning information, not legal or engineering advice. Rules differ by place: check codes and permits with your local authority and your licensed trades.

Keep reading

Build your signAsk for a quote