Modbus Result

I’m using Lumel’s SM2 module and getting result that I cannot translate it, because I never worked with modbus before. Documentation says that value is located in two successive 16-bite registers.
With this code:


var serialPort = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One);
serialPort.Open();
var rtuInterface = new ModbusRtuInterface(serialPort);
var master = new ModbusMaster(rtuInterface);
ushort[] result = master.ReadHoldingRegisters(1, 7004, 2);

i’m getting results 17912 and 38912. When I translate in into binary form, It doesn’t match with possible values from documentation in any way. I’m using Spider and library from codeshare. Any advice would be appreciated

Hi tvinko,

I am well familiar with Modbus. Data was originally encoded as 2 bytes for each register in the Modbus map giving a 16 bit value but later devices used 2 registers to encode 32 bit values.

Can you share what the register configuration is for your device you are talking to? i.e. what is the value supposed to represent number wise and what is the scaling etc.

For example, I have a Variable Speed Drive on my desk that is modbus and the register for speed setting is described like this.

Logic address: 3202
Type: INT
Unit: 0.1

The type here is critical as it indicates if the value can be negative. UINT would indicate a pos value only. Your code gets back UINT. Type can also be WORD indicating a status bit register.

The UNIT here indicates that the value is stored as 10 times the real value.

If you have the Modbus information for your device, I can work out what the encoding should be.

Thanks Dave.

I don’t find any relevant information, except address of register. Here is link to datasheet
http://www.lumel.com.pl/download/Z2Z4L2x1bWVsL2VuL2RlZmF1bHRfbXVsdGlsaXN0YV9wbGlrb3cudjAvMzQ5/sm209c.pdf

On page 17 there is table with first part of registers, but unit is marked as “-”

This is a strange system.

On page 13, at the bottom, it shows a typical read of 2 registers, which should return 4 bytes but page 14, at the top, shows that it returns 8 which is wrong. Modbus RTU protocol is 16 bit per register.

Page 17 shows that the system is encoded as 32 bit data so you will have to read 2 registers and then OR them together after shifting the 1st 16 bit value 16 bits to the left. Assuming the same HI LO order that is Modbus?

Same for your 7004 register. Read out 7004 and 7005, shift 7004 left 16 bits and add the 2 together (or OR them)

The manuals explanation of the Modbus message is very wrong. There is NO 4 bytes transmitted for each out. To read 2 registers, you need to read 4.

PS> This is the document they refer to and it has nothing in there showing 4 byte data

@ tvinko - Looks like you’re using my Modbuslibrary.
Modbus uses big endian encoding, C# is little endian. (Don’t shoot at me if it’s the other way around, I can never remember :whistle:
My Modbus library already makes this conversion internally, so the 16 bit register values are correct encoded for C#.
But if you look at them byte wise, they might be in opposite order to what your module spec says.
But to generate an 32 bit value from 2 16 bit register values it should work as follows:

 result = master.ReadHoldingRegisters(1, 7004, 2);
uint value = ((uint)result[0]) << 16) | result[1];

Depending on your module you might have to exchange result[0] and [1].

Yes, i’m using your library. It’s great and easy to use, but this spec and results from SM2 are killing me.

I’ll try this suggestions.

Thank you both for help, such topics should have donate button :whistle:

Still don’t understand concept, and swapping bytes all over the place :wall:

17912 (45 F8) -> a
38912 (98 00) -> b


uint value = ((uint)a << 16) | b;   //1000101111110001001100000000000
uint value = ((uint)b << 16) | a;   // 10011000000000000100010111111000

I assume than for endianness check, I must make swap:
F8 45 -> a
00 98 -> b


uint value = ((uint)a << 16) | b;   //11111000010001010000000010011000
uint value = ((uint)b << 16) | a;   //100110001111100001000101

None of this describes correctly Status 2 (in attachment)

It is pretty messy for sure.

The fact that the document shows this to only have 16 bits, you are getting a value for the upper 16 bits and they should be ZERO according to my interpretation.

What do you get if you read registers 7202 and 7204 (page 21 of the manual)

Read out 2 registers for each as the docs show everything is 32 bit.

The confusing part is that there is no indication of the how it’s endian encoded anywhere in the docs that I could find.

Hang on. They’re not BINARY encoded, they are FLOAT. See page 16.

You may have to try and recover the value as a float of 32 bits.

This would certainly explain the strange encoding.

Thanks Dave i see now.
This might be stupid question, but how do you receover value as float?

This might help but I didn’t see any code but the little app they link to might recover your values enough to confirm what you see.

Thanks!

You can also put values into a byte[] and use ExtractValue… from Utilities class

ExtractValueFromArray gets float from byte array. For my case, I suppose I need opposite - byte from float…

You need FLOAT from ARRAY when you read the registers and ARRAY to FLOAT when you want to write something.

Maybe little progress here.
When I read some other register (7613) i get value float value 1, which is expected state.

But, i don’t know, what to do with value, that i get from register Status 2 (7502)

Here is the procedure:

  1. 17912 from register1 and 38912 from register 2 -> 45 F8 98 00
  2. Convert “45 F8 90 00” to float with Float Point Conversion. Btw, great application downloadable from link that Dave provided. Result is 7955 (attachment)

The problem is that 7955 to binary doesn’t give me any meaningful…

If 7955 is decimal then it works out like this.

Binary 16 bit = 0001111100010011

011 4 x pt100 inputs
010 9600 bps
100 8N2

1111 4 inputs are on
0 OC switched off.

Does this make sense based on what you expect it to be?

Yes it does!

Thank you Dave and Reinhard