Skip to main content
Version: 1.0.8

Modbus

Modbus is simple, ubiquitous and completely untyped: the device gives you 16-bit registers and it is your job to know what they mean. QUBIQ's Modbus support is about making that mapping explicit and repeatable.

Configuration​

FieldDescription
NameConnection identifier.
HostDevice IP or hostname.
Port502 for Modbus TCP; the gateway's port for RTU-over-TCP.
Framing modetcp (Modbus TCP), rtu (RTU framing over a serial gateway), ascii.
Unit IDThe slave/unit address. 1 unless the device or gateway says otherwise.
Byte orderHow multi-register values are assembled — see below.
Connect timeout (ms)How long to wait for the socket.
Request timeout (ms)How long to wait for a response before failing the read.
Probe address / quantityThe holding register the connection check reads to prove the link — when the device does not identify itself.

The device names itself New in 1.0.7​

The connection check first asks the device to identify itself (function code 43, Read Device Identification), and when it answers, the check's message names it — device responded — <vendor> <product> <revision>. A register read proves that something answered on that address; it cannot tell you an IP was reused or a gateway is fronting the wrong unit, and that is the question commissioning actually has.

Function code 43 is optional in the Modbus specification. A device that does not implement it answers illegal function, which is ordinary: the check falls back to reading the probe address, exactly as before.

Byte and word order​

The single most common source of wrong Modbus values. A 32-bit float spans two registers, and vendors disagree on the order of both the words and the bytes within them.

OrderAlso calledRegisters for 1.0f (0x3F800000)
Big-endianABCD0x3F80, 0x0000
Little-endianDCBA0x0000, 0x803F
Big-endian byte swapBADC0x803F, 0x0000
Little-endian byte swapCDAB0x0000, 0x3F80

If a value reads as an absurd number (4.6e-41, 1.7e38), the order is wrong — not the address. Read a register whose value you know, and try orders until it matches.

Strings New in 1.0.7​

The Modbus specification has no string type, but packing ASCII into a block of registers is how nearly every device exposes a name, a batch id or a serial number — and until 1.0.7 a string tag could not be bound to Modbus at all. Now it can:

PackingTwo characters per register, high byte first.
Length10 registers — 20 characters.
PaddingTrailing NULs and spaces are trimmed on read. On write the value is padded to the full 10 registers and sent in one request, so a shorter new value cannot leave the tail of the old one behind.
Byte orderOnly the byte half applies: BADC/DCBA swap each pair of characters. The word half does not — reversing the words would reverse the text in pairs, which no device means.

The register preview in the binding form decodes a string the same way the poller does and shows it in quotes, so trimmed padding is visibly absent and an empty block reads "".

Register addressing​

Modbus has four address spaces. Which one you are reading is part of the address.

SpaceFunction codeAccessTypical notation
Coils1 / 5 / 15read/write bit0xxxx
Discrete inputs2read bit1xxxx
Input registers4read 16-bit3xxxx
Holding registers3 / 6 / 16read/write 16-bit4xxxx
Off-by-one

Vendor documentation is inconsistent about whether addresses are 0-based (protocol) or 1-based (documentation). Holding register "40001" in a manual is protocol address 0. If everything is shifted by exactly one, this is why.

One bit of a register New in 1.0.7​

Packed status words are the norm in Modbus: sixteen flags in one holding register. Address one of them by adding the bit number, 0–15 with 0 the least significant:

HR:100.3 bit 3 of holding register 100
IR:7.9 bit 9 of input register 7

In the binding form, choose HR or IR, enter the register, and put the bit in the bit (0-15) field beside it; leave that field blank to read the whole register. Coils and discrete inputs are already one bit per address, so they take no bit — COIL:16.1 is refused while you type rather than quietly read as something else. A UDT address parameterises the same way: HR:{Base}.3.

A Boolean on a whole register means "any bit set"

Before 1.0.7 there was no way to name a bit, so a boolean tag bound to HR:100 read true whenever any of the sixteen bits was set — a tag meant to watch bit 0 turned true when bit 7 did, with the right address and no error anywhere. That is still what a Boolean on a whole register means, and upgrading changes nothing for an existing binding. If a Boolean tag is meant to follow one flag of a status word, add the bit.

Binding tags​

FieldNotes
RegisterThe register space (HR, IR, Coil, DI), the number, an optional bit, and 1-based addressing (datasheet) if you are typing the number from a manual. They compose the address — HR:100, or HR:100.3 for one bit.
Byte / Word OrderABCD (default), CDAB, BADC, DCBA — see byte and word order. The width comes from the tag's data type.
Poll Rate (ms)Poll period, 1000 by default.

Modbus is strictly request/response: every Modbus tag is polled. The deadband is the tag's own, on its History tab.

Poll rate and register grouping​

QUBIQ groups contiguous registers into single requests. Two consequences:

  • Contiguous addresses are much cheaper than scattered ones. If you can influence the device's register map, block related values together.
  • Do not poll faster than the device can answer. A small PLC serving a serial gateway may manage a few requests per second. Polling every 100 ms produces timeouts, not fresher data.

Start at 1000 ms and reduce only where a faster value demonstrably matters.

Verifying a register​

Use Read registers in the connection's editor (needs View Connections). It performs a one-shot read of a register range, so you can confirm an address and byte order before building tags on it.

Scaling​

Devices frequently transmit scaled integers: temperature as tenths of a degree, pressure as hundredths of a bar. Do not scale in every widget — configure it once on the tag:

Raw low 0 Eng low 0.0
Raw high 10000 Eng high 100.0

Scaling is applied after the read and before history and alarms, so everything downstream sees engineering units. → Tag properties

Writing​

Writable tags issue function code 5/6/15/16 depending on the target space and width. A write is acknowledged by the device; a failure surfaces as a rejected write, not a silent no-op.

Writing one bit of a holding register 1.0.7 — a tag bound to HR:100.3 — uses function code 22, Mask Write Register. The device itself applies the change to the register's current contents, in one transaction, so the other fifteen bits are untouched and there is no read-modify-write window in which another master's write could be lost. The value is simply on or off; scaling and byte order do not apply to a bit.

Function code 22 is optional. A device that does not implement it answers illegal function, and the write is refused with that — QUBIQ does not quietly fall back to reading the register and writing all sixteen bits, which is exactly the race the function exists to avoid. Input registers are read-only, bit or not.

A write larger than one Modbus request can carry — 123 registers or 1968 coils — is refused naming the limit, where the device used to answer a bare illegal data value and leave you to work out which limit you had crossed. 1.0.7

Gate device writes with a write-security level on the tag so only sufficiently privileged runtime operators can drive equipment. → LiveView authentication

One slow device, one slow connection Changed in 1.0.7​

Every Modbus connection is served by one worker, and three things used to let a single device make the others wait:

  • Requests were handled one at a time across every connection. A connection check, a register read from the binding form or a write to one unreachable device held every other connection's request behind it, until each caller timed out and reported the worker unavailable. Requests for different devices are now handled side by side; one device still gets one request at a time, because that is what its socket can take.
  • Changing one connection's configuration stalled the rest while its poller wound down. That wait is now that connection's alone.
  • A reply that arrived just after its timeout cost a reconnect. The late frame was still queued on the socket, the next request read it, found it belonged to someone else, and the connection was torn down — so a device running close to its Request timeout reconnected over and over. The stale reply is now recognised and discarded, and the socket kept. The same check is what stops a mismatched reply from ever being decoded as data, which on a gateway would put correct-looking values under the wrong tags.

Troubleshooting​

SymptomCheck
Connection test times outWrong port; some devices use RTU-over-TCP on a non-502 port. Check the unit ID too.
Illegal data addressThe register does not exist, or the off-by-one above, or the wrong address space.
Illegal functionThe device does not support that function code — often read-only registers being written.
Values are nonsense floatsByte/word order.
Values are exactly 10× or 100× offMissing scaling.
Intermittent timeoutsPolling faster than the device or serial gateway can serve. Slow down.
One tag Bad, the rest fineThat register is outside a valid block; the grouped read fails for it only.
A Boolean on a holding register is true when its flag is not setIt is bound to the whole register, which reads "any bit set". Name the bit.
Writing a register bit fails with illegal functionThe device does not implement function code 22, Mask Write Register.
The connection check does not name the deviceThe device does not implement function code 43; the check fell back to the probe register.

Next​

→ SNMP · Binding tags