LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

MODBUS formatting U16 to single, back and forth

Solved!
Go to solution

Greetings everyone, I'm working with a couple Kollmorgen servo drives that give and receive data via MODBUS. Using the LabView user library I have had no issues in reading and writing data registries from them (provided I don't do it more often than 10 times per second). However, I'm having some issues with the data format. Kollmorgen hasn't exactly settled on a standard, and thus some values are 32 bit registries, some are 64 bit and to boot, some are signed and some are not; they are all however, delivered in 16 bit sized chunks by the "read holding registries" function. Right now I'm exclusively interested in the 32 bit, signed value variety. 

 

While I am able to read, and am certain I'm reading the values I wish to (I can modify the value from Kollmorgen's workbench and LabView reflects the value change), the output doesn't make much sense. For positive values it's pretty intuitive, as the first U16 (I'm reading an array of 2 U16 values) is always a zero, and the other is a x1000 of what the actual positive value is. So if for example I'm reading a current of 3.5 amps, the first U16 is a zero and the second one is 3500; If I'm reading 1.23 amps it's zero and 1230 and so on.

 

However, when reading negative values, I have failed to see a pattern, for it almost always go to a rather high value (65,324 or something) in both registries in rather low numbers like -2. I have already tried several of the data handling methods listed here, including:

 

-Typecast a single into 2 U16 array, then back via join numbers

-Convert number to binary array, then binary array back to number

-Coerce into single, then using convert to I32, and split those

 

So far no luck, has anyone had a similar experience, or has worked with those drives in the past? Also can't find much information on Kollmorgen's documentation, and their website only states that the MSB is sent as the first registry on 64bit sized registries. Probably the format of positive data gives a clue, but so far no luck on guessing it.

0 Kudos
Message 1 of 6
(6,932 Views)

The first bit is usually the sign.

 

The snippet will return -1 when run.

undefined

 

Sorry I don't have more information specific to Killmorgen drives.

 

More on signed numbers: https://en.wikipedia.org/wiki/Two%27s_complement

0 Kudos
Message 2 of 6
(6,923 Views)
Solution
Accepted by Daikataro

Typecast the array of U16's to an I32.  Divide by 1000.

 

In reverse.  Take your floating point number.  Multiply by 1000.  Coerce to a U32.  Typecast to an array of U16.

 

 

 

EDIT:  Don't mess with Fixed Point.  That is for very special situations, usually involving FPGA's.

Message 3 of 6
(6,913 Views)

Thanks a bunch RavensFan! Actually several of my attempts were based on your solutions, so thanks a lot for the info.

 

It worked awesome, can now do the conversions back and forth without issues, just a few observations:

 

-You say coerce to U32, but actually it's I32, and code snippet shows same, most likely typo

-Gonna stick to single precision to keep it in just 2 U16 chunks

 

Thanks again for the help, this will simplify coding a lot.

0 Kudos
Message 4 of 6
(6,897 Views)

Do you have much knowledge about how signed/unsigned numbers are represented in binary? For a signed number, 2's complement is used to represent the number - you can spot a negative number because the most significant bit is a 1.

 

If you get your unsigned 32-bit number (U32 - by joining the two U16s), if you then type-cast to a signed 32-bit number (I32), it should then be represented correctly in LabVIEW (and you can do your scaling etc.).


LabVIEW Champion, CLA, CLED, CTD
(blog)
0 Kudos
Message 5 of 6
(6,879 Views)

@Daikataro wrote:

Thanks a bunch RavensFan! Actually several of my attempts were based on your solutions, so thanks a lot for the info.

 

It worked awesome, can now do the conversions back and forth without issues, just a few observations:

 

-You say coerce to U32, but actually it's I32, and code snippet shows same, most likely typo

-Gonna stick to single precision to keep it in just 2 U16 chunks

 

Thanks again for the help, this will simplify coding a lot.


You're right.  That was just a typo on my part.

 

It doesn't really matter whether you use single precision or double precision.  (4 bytes vs. 8 bytes of the floating point).  The coercion bullet to an I32 in one direction will take either a 4-byte float (SGL) or 8-byte float (DBL) to the 4 byte integer without any difference in result.  And the division of two integers in the other direction are going to naturally yield a DBL precision out of the divide function.

0 Kudos
Message 6 of 6
(6,862 Views)