Hi everyone,
I'm trying to figure how how to correctly display a two word (32 bit) parameter value from a serial device. The problem is that this register is sent by the device using the following order: higher value word: first 16 bit, lower value: second 16 bit.
I've created a 32 bit unsigned data type dataset, as the device memory map establishes for the data type of the register. I'm reading the register this way and I've found out that what I'm displaying isn't the actual value of the register but an inverted value: because of the order that the device uses to send the data (16 bit with highest value first), I'm receiving the two words inverted!
To make thing more easy to understand I'm going to make some numbers:
Say that actual register value is 227,149.... this in binary is interpreted as 0000 0000 0000 0011 0111 0111 0100 1101.... being the first 16 bits one word (0000 0000 0000 0011), and of course the other 16 bits the second word (0111 0111 0100 1101). Now, what the devices is doing is comparing both words (both 16 bit halves) and sending the second one first, as it has a higher value compared to the first word. This way, what I'm receiving is 0111 0111 0100 1101 0000 0000 0000 0011... that converted to decimal corresponds to the number 2,001,534,979!
Has anyone experience solving anything like this? I would appreciate any help.
Thanks in advance!.
Hi
How the data field arrives to the "serial device" ?
Because this kind of inverting order is not "programmaticaly" normal.
If you cannot correct the data source format, you will have to proceed with bit inversion :
- in a CALC block (using 2^^ and &), if the meaning of this value have to be used in a controller
Example :
The fifth bit of an Integer or Long value can be isolated like that : True If (Value & (2^^4)) = (2^^4)
and you will have to create a While/End_While structure to enumerate bits 0 to 31
- in a VBA, you can use this 'rotation' of bits :
Private Function LongLeftRotate(ByVal value As Long) As Long
Dim lngSign As Long, lngI As Long
Dim Bits As Long
Bits = 16
For lngI = 1 To Bits
lngSign = value And &HC0000000
value = (value And &H3FFFFFFF) * 2
value = value Or ((lngSign < 0) And 1) Or (CBool(lngSign And &H40000000) And &H80000000)
Next
LongLeftRotate = value
End Function
and use it like that :
Dim LongInitial As Long
Dim LongModified As Long
LongInitial = 2001534979 ' 0111 0111 0100 1101 0000 0000 0000 0011
LongModified = LongLeftRotate(LongInitial)
MsgBox LongModified ' give 227149 = 0000 0000 0000 0011 0111 0111 0100 1101
Hope that will help
In reply to Jack_France:
It´s the big/little endian problem: en.wikipedia.org/.../Endianness
In the PLC world it would be really easy:
you have 32 bit word. MD 100 (consistes of mb 100,101,102,103)
then you just move the MB:s to a new MD (double)
L MB100 to MB 113
L MB101 to MB 112
and so on... propably you could do the same inside VB code
(depending are the words just swapped or also the Bytes inside the words)
If the bytes are also swapped you can´t use rotate :p
Niklas Flykt
Klinkmann Oy
Key Account Manager safety products
nikfly@gmail.com
In reply to Maarten van der Waal:
@Niklas :
I also thought about little/big endian, but, in that case, it would invert the bits order (0-15 -> 15-0), not inverting 2 blocks of 16 bits in which the order is not changed.
Seems to me the easiest is to simply read the registers as 16 Bit words and combine them in the right order in a CALC block.
Create a 32 Bit destination parameter in the module. Read the MSW and write this to the 32 bit parameter. Shift this left 16 bits. Then bitwise OR (|) this 32 Bit parameter with the LSW.
Note that DeltaV CALC blocks use 32 Bit Floats for internal registers. You need to use a defined 32 Bit parameter to "host" the data as you manipulate it. Using two external reference parameters called 'MSW' and 'LSW'
'^/32-BIT_PARAM.cv' :='^/MSW.CV';
'^/32-BIT_PARAM.cv' := (SHL('^/32-BIT_PARAM.cv' , 16 ) );
'^/32-BIT_PARAM.cv' := '^/32-BIT_PARAM.cv' | '^/LSW.CV';
The above three lines can be condensed to the following:
'^/32-BIT_PARAM.cv' := (SHL('^/MSW.CV', 16 ) | '^/LSW.CV';
The Programmable serial card has 5 special data fields that can be used to 'adjust' the order of bytes and words so that the Dataset holds the converted value. I think Special Data 2 will swap the two 16 bit registers and give you a 32 Bit word in the Data set without the need for the above expression. This used to be a downloadable driver from Mynah. I think the default for the serial card is this driver. A quick check on my machine shows the Special Data fields available. Mynah has a document called "Special Modbus Driver
Programmable Serial Interface Card" that discusses this option.
If you are using the MODBUS TCP driver for the VIM, it emulates the Programable card and can swap the word order using Special Data 2 set to "1".
Andre Dicaire
In reply to Andre Dicaire:
Thank you all guys. Problem solved.