A Modbus RTU slave never starts a transaction, so the micro that runs your steppers cannot poll the panel. Keep the HMI as the only master: bind each button to a write of its request code into one holding register, poll status on a schedule, and consume codes in the micro's normal loop. At 9600 baud a 250 ms poll keeps about four fifths of the wire idle.
The HMI owns the Modbus RTU link and your microcontroller owns the stepper timing. Both facts matter when a button press has to reach the machine. A Modbus slave never starts a transaction, so the micro cannot read a panel tag. It also cannot afford the interrupt load of playing master. The setup that works keeps the panel as the only master and moves the handshake into registers. Each button writes a request code into one holding register. A scheduled poll reads the micro's status registers, and the micro consumes each code inside its normal control loop. Set up this way, a 250 ms poll at 9600 baud occupies about a fifth of the wire and touches the motion code zero times per poll. This article gives the register map, the settings on both ends and the timing math.
Why the micro cannot poll the panel
Modbus RTU puts one device in charge. The master starts every transaction and slaves only answer. This rule applies to every RTU link, not to one panel family. A slave has no way to put a frame on the wire on its own initiative. A micro that wants a tag value from the panel has nothing to send and nobody to answer it.
The tempting second idea is worse than the first: make the micro a second master so it can ask anyway. Two masters on one RS-485 pair transmit over each other. Every collided frame fails its CRC check, and the link looks broken from both ends. That failure and its fix are in two Modbus RTU masters on one RS-485 bus. The wiring, addressing and serial basics for the link itself are in connecting an HMI panel to a microcontroller over Modbus RTU. This article starts where that one stops, at the register design that keeps the motion code out of the conversation.
What you need
- An HMI project whose device driver runs as a Modbus RTU master, with a recurring poll schedule and a write action on button objects.
- A Modbus RTU slave stack on the microcontroller that serves holding registers (functions 03 and 06) from its main loop.
- Agreed serial settings on both ends. The example below uses 9600 baud, 8 data bits, even parity, 1 stop bit. Without parity, the Modbus over Serial Line specification calls for two stop bits, which keeps the character at 11 bits.
- A USB RS-485 adapter and a logging terminal, so you can watch raw frames while you commission.
Map the registers first
| Register | Content | Source | Read by |
|---|---|---|---|
| 0 | request code, 1 to 5; 0 means idle | the HMI, on button press | the micro loop, then it writes 0 |
| 1 | status: 0 idle, 1 busy, 2 done | the micro | the HMI poll |
| 2 to 6 | returned data for the finished request | the micro | the HMI poll |
Define each code once and give it one meaning: 1 jog start, 2 jog stop, and so on through 5, with 0 as nothing pending. Allow one request at a time. The loop consumes a code by doing the work, zeroing register 0, setting register 1 to 2 when done and filling registers 2 to 6 with the answer. If a code arrives while status is busy, the loop leaves it alone. A code that still sits in register 0 after several polls is a request the loop never consumed. All of this moves over two function codes: a single-register write and a holding-register read.
Set the panel side: write on press, poll on a schedule
- Match the device driver's serial settings to the micro: 9600 baud, 8 data bits, even parity, 1 stop bit.
- Bind each button to a write of its own code into register 0: button 1 writes 1, button 2 writes 2, through button 5. Use a write on press. A value tag the driver refreshes every cycle would deliver the same code again each poll, the same re-delivery problem behind how many PLC scans an HMI momentary button bit stays on.
- Add registers 0 through 6 as one recurring read on the driver's poll schedule, or through a scheduled-event tool; one HMI package calls its version Event Manager. Start at 250 ms.
- Set the master's response timeout to 500 ms. The micro answers from its register map, so a control loop that finishes a pass inside 100 ms meets that timeout with room to spare.
- Put register 0 and register 1 on a screen so the operator can watch a request land and finish.
- If the panel lets you disable an object on a tag condition, grey the buttons out while register 1 reads 1, so a second request cannot overwrite a busy one.
Consume the code in the micro's normal loop
The slave stack does the mechanical work and nothing more. The UART takes one service per byte on the wire. The frame parser and the reply run in the main loop.
Function 06 needs no decision. The value in the frame becomes the content of register 0, and the stack echoes the frame back. Function 03 replies with whatever the map holds at that moment. The motion code never learns that a poll happened: between step blocks, the loop reads register 0, acts on a nonzero code once, zeroes it, sets register 1 and fills registers 2 to 6.
The difference matters: byte services are cheap interrupts, while a data-dependent reply inside the motion path is expensive normal program flow. That distinction is set out in how PLC interrupts differ from normal subroutines. Keep the loop's worst-case pass under 100 ms at full step rate and the 500 ms timeout holds.
Example: sizing the poll for a stepper micro at 9600 baud
Inputs, and where each comes from:
- 9600 baud, 8 data bits, even parity, 1 stop bit: the settings this setup agrees on. A Modbus RTU character is 11 bits on the wire: start plus 8 data plus parity plus stop.
- 3.5 character times of silence between frames: required by the Modbus over Serial Line specification.
- Frame sizes: a single-register write is 8 bytes out and 8 bytes back; a one-register read is 8 bytes out and 7 bytes back. These sizes follow from the Modbus frame layout: address, function, data and a 2-byte CRC.
- Request codes 1 to 5 with 0 as idle: the register map in this article.
- Poll period 250 ms: the starting choice for this example, fast enough that a button response lands within a quarter second.
Rule in words: a cycle's line time is the bits in both frames divided by the baud rate, plus one 3.5-character silence ahead of each frame.
Arithmetic:
- Character time: 11 bits / 9600 bit/s = 1.146 ms. One silence: 3.5 x 1.146 ms = 4.0 ms.
- Write cycle: (8 + 8) bytes x 11 bits = 176 bits; 176 / 9600 = 18.3 ms; plus two silences, 18.3 + 8.0 = 26.3 ms.
- Read cycle: (8 + 7) x 11 = 165 bits; 165 / 9600 = 17.2 ms; plus two silences, 25.2 ms.
- Busy cycle, one button press plus the scheduled read: 26.3 + 25.2 = 51.5 ms, call it 52 ms.
- At a 250 ms poll: 52 / 250 = 0.21, so about 21% of the wire is busy and the line idles roughly four fifths of the time. The micro's UART handles 16 + 15 = 31 byte events per cycle, and 31 x 4 cycles per second = 124 byte services per second.
- An idle cycle carries the read only: 25.2 / 250 = 10% of the wire.
Result: the poll costs the stepper micro 124 byte-level UART services per second and zero entries into the motion code, and it occupies about a fifth of a 9600 baud link.
Recommendation: poll at 250 ms on a 9600 baud link, and keep the poll period at least four times the transaction time, 250 ms against 52 ms here. If the panel must see status faster than four times a second, move the link to 19200 baud: the same 341 bits take 341 / 19200 = 17.8 ms plus 8.0 ms of silence, 25.8 ms per cycle, and even a 100 ms poll sits near 26% utilization.
How to check it worked
Commission the whole sequence with the motors stopped or at reduced speed, before any button command runs production motion.
- Press button 3 with the raw-frame logger attached: one function 06 write of 3 into register 0 appears, register 0 reads 3 on the panel screen, and it reads 0 again after the loop's next pass.
- Change the micro's status value by hand and watch the panel screen update within one poll, 250 ms.
- Exercise codes 1 through 5 one at a time. Each must arrive once, run once and clear once. A code that arrives twice points at a tag being rewritten on every cycle, back to step 2 of the panel setup.
- Run the stepper at full rate with polling live and watch the panel's diagnostic counters for timeouts and CRC errors. Timeouts mean the loop missed the 500 ms deadline. The fix is a faster loop pass or the 19200 baud move from the example, and the diagnosis path is in Modbus RTU master no reply and address errors.
Questions
What happens if the micro sends its own Modbus request anyway?
Two drivers on one RS-485 pair at the same time collide, and both ends log CRC errors and retries while the link looks dead. The stepper micro then spends real interrupt time on communication, which is the problem you started with. Keep one master on the wire and add registers the master can poll whenever the micro has new data to give.
How does the panel show that the micro acted on a request?
Add one more holding register that the micro owns, a completed-code register. When the loop consumes a code it copies it there and zeroes the request register. The panel's scheduled poll picks up both, so the screen can show the last finished command. A request code that still sits in the register after several polls means the micro never consumed it, and the timeout counters will usually say why.
Does a faster poll make the motion code see a button sooner?
No. The code lands in the register as soon as the HMI's write frame completes, and the loop sees it on its next pass whatever the poll period is. The poll governs how quickly the panel sees status and returned data. If commands feel slow, shorten the loop's pass time first; move the link to 19200 baud before shortening the poll below 250 ms.
Planning information, not legal or engineering advice. Rules differ by place: check codes and permits with your local authority and your licensed trades.