Read Multiple Registers of Different Widths

I'm implementing a Modbus stack for microcontrollers. And I have a question about an implementation detail.

Imagine we have the following Modbus holding registers defined:
<pre>
40001 00 UINT16 regA
40002 01 FLOAT32 regB
40004 03 UINT16 regC
</pre>
What's the expected response to this Read Holding Registers request:
<pre>
01 device address
03 read holding registers
00 00 starting address
00 04 quantity of registers
xx xx crc
</pre>
My first thought is that it would return an 8 byte response, namely [regA regB regC].

But it's also possible that it would return an Illegal Data Address exception because there is no register defined at address 02.

I'm inclined to implement the former. What's the industry consensus on this?
 
R

Robert Dusza

HI,

My experience with MODBUS register reads is, unless they are contiguous on the device being read, you will need to implement an individual read request for a non-contiguous register.
<pre>Example:

01 device address
02 read holding registers
00 00 starting address
00 02 quantity of registers
xx xx crc

Then,

01 device address
01 read holding registers
00 04 starting address
00 01 quantity of registers
xx xx crc</pre>
 
Your registers are contiguous and they are valid registers.

The slave/server is unlikely to throw a Modbus exception code because it's just supplying data from registers. Modbus is "data agnostic", it doesn't care what the data are or represent. It's up to the Master/client to interpret the received data in its proper format so that it becomes useable data.

I remember 'reading' such contiguous data (int, FP, int) using Simply Modbus, where each value can be independently defined for its data format, integer or FP. And the data looked 'good' to a human, me.

Modscan32 will read the same data and display each register in binary or hex format, but when one switches to integer format, the two middle registers do not display as an FP/real value, those two registers will display as two separate integer values, because the data format selection for Modscan is global: all received data is interpreted in the same format.

Modbus will transfer the data, that's its job. It's up to the master/client at the application level to interpret the bits/bytes and make sense of raw data.
 
1) Try to map your data in groups of the same data type (if useful from application perspective):
<pre>40001 00 UINT16 regA
40002 01 UINT16 regC
40003 02 FLOAT32 regB</pre>
2) It's better to return an exception response when the master requests only parts of cohesive data, e.g. reading a float with two requests likely causes data inconsistency. Same applies for any other data type that is larger than the 16-bit register size.

3) Your user manual should state how the data types are mapped onto the Modbus register structure.
 
This command will give a valid response.

The first 2 bytes will contain the UINT16 value. The next 4 bytes represent the IEEE value of the floating point, and the last 2 bytes contain the last UINT16 value. Possibly you have to do some byte or word swapping.

Address 01 and 02 contains the floating point value so address 00 up to 03 are used addresses.
 
B

Bob Peterson

As it turns out neither of the options that you give are correct. Modbus only deals with 16-bit integers. So what the client would do is to read four registers starting at offset zero and it would return eight bytes or four integers. It is up to the client to know how to deal with the second two integers and convert them to floating point. Incidentally there is no standard modbus approach on the byte or word order of the 32 bits that represents the floating Point value. It is also up to the client to know what the format of the two registers represents and convert it to floating point.
 
Top