IEEE754 conversion - 32 bit - Modbus TCP

frandESS

Lifetime Supporting Member
Join Date
Sep 2022
Location
Norway
Posts
14
Hi,

Im doing a project with a Power meter that offers Modbus TCP and each signal is a 32bit Float.¨

I tested the float in Modbus Poll and discovered that this standard is Little Endian - Byte swap.

Searching through forums for a while now and can't really figure out how to convert the data .

So far I have been blessed converting to 32 bit by this code:

ArrayToInt[0] :=MBTCP_1.DATA.ReadData[360];
ArrayToInt[1] :=MBTCP_1.DATA.ReadData[361];
CPS(ArrayToInt[1],DesInt,2);
test_real:=DestInt;

Anyone that has come up with a solution or could guide me?
 
can you give an example of the two Modbus register values (INT or UINT), preferably in hexadecimal, and what you think the corresponding REAL value is (±10%)?

If you can provide that for a few different REAL values that would be even better.
 
@drbitboy - thank you very much for paying interest to my thread.

Value is 237,863 and HEX1 is 0x3372 and HEX2 is 0x436E

So value around 236-238 Volts.

Snapshot 2 is Hex1 0x0EC8 and 0x436E
Snapshot 3 is Hex1 0xAD46 and 0x436D

I m doing structure text in Compact Logix L36ER - 32.011

The Prosoft MBTCP card communicates to PLC via INT
 
Are these data are from a ProSoft module?

In that case, along with the integer and real values, what Swap Code is in effect (preferably None)?
 
That's correct model is MVI69E , using no swappes, also tested in MBTCP client AOI from Rockwell
 
And what is the value of DestInt (hexadecimal preferred) for those three cases?


It is

  • either 0x436E_3372 or 0x3372_436E for the first,
  • either 0x436E_0EC8 or 0x0EC8_436E for the second, and
  • either 0x436D_AD46 or 0xAD46_436D for the third,
is that correct? or feel free to generate new examples.
 
And when you say HEX1 you are referring to .ReadData[360], and HEX2 is .ReadData[361], correct?

Or, more generally, HEX1 is .ReadData[N] and HEX2 is .ReadData[N+1]?
 
Whatever the result, The ProSoft Swap Code will be either None or Swap Words, and the code should look like this:
CPS(MBTCP_1.DATA.ReadData[360], test_real, 1);
as there is no reason to copy the data to an intermediate DINT, since the word-swap will be done in the ProSoft.
 
By the way, here are what those example INTs convert to:

>>> struct.unpack('f',struct.pack('HH',0x3372,0x436e))
(238.20095825195312,)

>>> struct.unpack('f',struct.pack('HH',0x0ec8,0x436e))
(238.0577392578125,)

>>> struct.unpack('f',struct.pack('HH',0xad46,0x436d))
(237.67684936523438,)



0x436E0EC8

+->8-bit integer 0x86 = 134; 134 - 127 = 7; 2^2=128
|
| +->128 + 1*64 = 192
| |
| |+->192 + 1*32 = 224
| ||
| ||+->224 + 0*16 = 224
| |||
| ||| +->224 + 1*8 = 232
| ||| |
| ||| |+->232 + 1*4 = 236
| ||| ||
| ||| ||+->236 + 1*2 = 238
| ||| |||
| ||| |||+->238 + 0*1 = 238
| ||| ||||
| ||| |||| +->238 + 0*0.5 = 238
| ||| |||| |
| ||| |||| |+->238 + 0*0.25 = 238
| ||| |||| ||
| ||| |||| ||+->238 + 0*0.125 = 238
| ||| |||| |||
| ||| |||| |||+->238 + 0*0.0625 = 238
| ||| |||| ||||
| ||| |||| |||| +->238 + 1*0.03125 = 238.03125
| ||| |||| |||| |
| ||| |||| |||| |+->238.03125 + 1*0.015625 = 238.046875
| ||| |||| |||| ||
| ||| |||| |||| ||+->238.046875 + 1*0.0078125 = 238.0546875
| ||| |||| |||| |||
| ||| |||| |||| |||+->238.0546875 + 0*0.00390625 = 238.0546875
| ||| |||| |||| ||||
| ||| |||| |||| |||| +->238.0546875 + 1*0.001953125 = 238.056640625
| ||| |||| |||| |||| |
| ||| |||| |||| |||| |+->238.056640625 + 1*0.0009765625 = 238.0576171875
| ||| |||| |||| |||| ||
| ||| |||| |||| |||| ||+->238.0576171875 + 0*0.00048828125 = 238.0576171875
| ||| |||| |||| |||| |||
| ||| |||| |||| |||| |||+->238.0576171875 + 0*0.000244140625 = 238.0576171875
| ||| |||| |||| |||| ||||
| ||| |||| |||| |||| |||| +->238.0576171875 + 1*0.0001220703125 = 238.0577392578125
| ||| |||| |||| |||| |||| |
<---+---->||| |||| |||| |||| |||| |
2#0100_0011_0110_1110_0000_1110_1100_1000



 
Hi,

Im doing a project with a Power meter that offers Modbus TCP and each signal is a 32bit Float.¨

I tested the float in Modbus Poll and discovered that this standard is Little Endian - Byte swap.
Wrong! Words are big endian. The most significant byte is sent first.

Searching through forums for a while now and can't really figure out how to convert the data .
It doesn't surprise me.

So far I have been blessed converting to 32 bit by this code:

ArrayToInt[0] :=MBTCP_1.DATA.ReadData[360];
ArrayToInt[1] :=MBTCP_1.DATA.ReadData[361];
CPS(ArrayToInt[1],DesInt,2);
test_real:=DestInt;

Anyone that has come up with a solution or could guide me?
Modbus TCP should be sent B1, B0, B3, B2. If you want to send or receive DWORDS or REALS from a Modicon PLC you should need my advice.
Most companies did not and they sent bytes anyway they wanted to.
In other words the bytes of each word or int should be sent big endian with the most significant byte first. However, DWORDs are sent with the LSW first and the MSW second. It is all screwed up. Words are big endian and words withing a DWORD or REAL are sent little endian little endian. I hated Modbus TCP. Now that I am retired, I let you guys screw with it.

What is even worse is that most implementations of Modbus RTU never got the timing right.
 
You can ignore most of @Peter Nachtwey's Myth of Modbus Mayhem.

Yes, Modbus implementations are a all over the map, but there are only a few possible variations, so it's a tempest in a teapot.

We already know that the (16-bit Modbus Register) byte order is correct within the Words (16-bit Modbus Registers) in the .ReadData array read by the ProSoft module from the power meter.

The only remaining issue is the word order within each pair of Words containing the bits of a single REAL value, so there are only two possibilities for the ProSoft Swap Code configuration parameter:

  • 0 - No Change
  • 1 - Word Swap
It is trivial to empirically determine which will work: try one; if it does not work (if the resulting REAL value is not reasonable), then try the other.

And in the unlikely event that both of those do not work, there are only two other possibilities to try:

  • 2 - Word and Byte Swap
  • 3 - Byte Swap
And in the even more unlikely event that none of those work as well, there are still only a limited number of possibilities to consider. E.g. whether the starting register for the floats is even or odd; in fact, there may be a pair of Modbus registers containing a known and constant float value to facilitate that case. Perhaps @frandESS can provide the document with the Modbus register map, or a link to same, for the power meter in question?
 
Woow what great feedback I got from you, and DrBitBoy - upgrade name to ProfBitBoy

You are right in your assumptions of Hex1 / Hex2. I always thought we need to address them individually into the PLC - so i was suprised of your solution proposal:
The CPS(MBTCP_1.DATA.ReadData[360], test_real, 1); went straight through - without need of manipulaiton from Prosoft.

So much knowledge and effort - Thanks alot.
I'm going to use the weekend to up my own learnings on this matter. - Trying to dodge this matter for years :)

Now I have a whole lot of speed issues on the Prosoft - but that's tuning and another story.

One L36ER loaded with 28 Modbus Clients - 20 on AOI and 8 on Prosoft module.
Scan time on 10 transactions is 400mS and no overlaps. 60 INT's read of each MB client, and a few Write commands aswell.

And 2pcs 1734AENT Remote IO with 6 modules + logger

Energy Management System is now completed :
-Shedding load inside factory
-controlling geothermal wells
-1MWh battery with 1MW battery inverter
-PV system of 800kWp Bifacial.
-Peakshaving and Frequency Support for Norwegian grid

Again: thanks to all valuable comments in this thread
 
You are right in your assumptions of Hex1 / Hex2. [i.e. that Hex1, 0xBLAH, is .ReadData[N] and Hex2, 0x43xx, is .ReadData[N+1]]
...
The CPS(MBTCP_1.DATA.ReadData[360], test_real, 1); went straight through - without need of manipulaiton from Prosoft.
So now we know:

  • Since, the Hex2 Word, 0x43xy, is the "high" Word (half) of the REAL*, and
  • the Hex2 Word, is the last Word (half) of the REAL,
  • then the Hex1 Word is the "low" and first Word (half) of the REAL.
  • And assuming
    • LSByte-first also means LSWord-first, and
    • the Power Meter and PLC order each REAL's Word-pair the same as their CPU architecture,
  • Then we know that
    • The the Power Meter uses an LSByte-first CPU
    • The L36ER PLC also uses an LSByte-first CPU
Which is why the No Change value for ProSoft Swap Code works.
I'm going to use the weekend to up my own learnings on this matter. - Trying to dodge this matter for years :)
You will not regret the effort.

"It's just zeros and ones, it cannot be hard" - Jouni Rynö

Start here: https://en.wikipedia.org/wiki/Single-precision_floating-point_format#IEEE_754_standard:_binary32

* 0x43xy implies a REAL value in the range 128-256 if x < 8

and consider that terms like "endian," "byte," "integer," "16-bit, "signed," and "unsigned"are only names we use to define, for convenience, how we order, group, and interpret the bits; the rest is bookkeeping.
 

Similar Topics

Hello. I have a SLC 5/04 with a Prosoft MVI46-DFNT. I am trying to communicate over ethernet to a Panelview Plus 1000. The Communication works but...
Replies
5
Views
2,021
I have a machine which is undergoing upgradation. As part of the process two SEW drives are being replaced., existing Gen B with new Gen C. The...
Replies
3
Views
202
Currently I’m using ESA model VT155W0000 HMI and it’s communicate with Fanuc PLC. Can any one suggest can I convert ESA model to EXOR HMI eSMART07M
Replies
0
Views
88
hi... i have an issue in s7 300 plc, while we run the machine(in idle there is no fault) , plc cpu goes in SF mode, after restart the power cycle...
Replies
2
Views
117
I have a Type C to RS485 adapter connect to my Siemens RWF55. I use modscan to scan it to get a value from the Siemens controller. In the...
Replies
4
Views
104
Back
Top Bottom