Binary32 Coversions in DeltaV

 Greetings All,

So i have come accross a challenge here where i need some assistance. I need to exchange 32bit Real data between a PLC (Siemens S7) and DCS (DeltaV 11.3.1) via Modbus. However modbus is designed as a 16 bit protocol, so the 32bit data received from the PLC is actually split in 2 registers. Ive used modbus before, so i have managed to setup the network and pull the data in, (i created a dataset with 16 bit registers, so every 2 registers is for 1 32bit real data from the PLC). 

So currently using 2 x BFO blocks i see 0100000110100001 Upper Byte and 1000010100011111 Lowe Byte, which if i do a binary32 conversion to equals 20.190000534057617 which i what i want. 

The question is how can i do this conversion in DeltaV? I was wonedring if there is an easy way to covert this data to a Floating point value in DeltaV?

Once done, i need to the converse as well, and convert a Floating point back to binary and write it out as a 2x16bit integers for the PLC.

 

Thanks in advance,


Regards

10 Replies

  • Calc Block Logic to meet your requirement of converting 32 to 16 and back
    (* 32 Bit To 2 x 16 bit *)
    '^/16bit_para1.cv' := ROTR(SHL('^/32bit_para1.cv', 16),16);
    '^/16bit_para2.cv' := SHR('^/32bit_para1.cv', 16);
    (* 2 x 16 bit to 32 bit *)
    '^/32bit_para2.cv' := ((SHL('^/16bit_para4.cv',16) + '^/16bit_para3.cv');
  • In reply to Steve Linehan:

    That does the first part, but then you need to do some maths to convert back to a real. Search on the exchange for IEEE 754

    But try this module, claims to do exactly what you want

    http://news.easydeltav.com/2005/12/ieee754_floatin/

  • Till now, I always managed to let the card do the conversion. In DeltaV, on the dataset properties, you can actually define the DeltaV data type to be floating point. The card will read the two consecutive 16-bit registers and give you a 32-bit floating point.
    Only thing is, the register numbering will be a bit off.
    Example: in the PLC you have registers 40000 - 40010 holding your values. 40000+40001 gives you one floating point, and so on, total 5 floating points. In DeltaV, you can map this with the with the following parameters:
    DeltaV data type: floating point
    device data type: 3 (for holding registers)
    data start address: 0
    number of values: 5
    you will get R1-R5 created under the dataset. R5 will map to 40009+40010!
    I am using VIM cards, so it might be slightly different with traditional serial cards.
  • Hi,

    why would you turn the value into bits?

    The S7 have  DD registers  in Datablocks, just read them and they will work.. only thing that can mess things up are big/small endiands, you might have to swap the words beffore moving to double word..

    Make a Modbus recive block like this one:

    Niklas Flykt 

    Klinkmann Oy

    Key Account Manager safety products

    nikfly@gmail.com

  • In reply to Niklas Flykt:

    you can also correct the endianness on the DeltaV side, using one of the special data parameters of the dataset... but I think it only works for a VIM card
  • In reply to Steve Linehan:

    Hi Steve,

    I think this only works for conversion to 32-bit integer. It would not work for 32-bit floating point.
  • In reply to IntuitiveNeil:

    I knew I'd posted this somewhere before

    If none of the other solutions help you out

    Determine which group of 16 bits represent the high order 16 bits of your 32 bit word (big or little endianness) code similar to Steve Linehans above should be used to combine into a 32bit unsigned integer,

    Then use the following CALC block code to perform the function that you need


    VAR EXPONENT END_VAR;
    VAR SGN END_VAR;
    VAR MANTISSA END_VAR;

    (* IEEE754_IN is a 32 Bit Unsigned Integer parameter *)
    (* FLOAT is a floating point parameter *)

    (* Extract the Exponent from the bits 24 to 31 of the 32 bit word *)
    (* AND Mask to extract bits 24 to 31 then shift 23 bits to the right *)
    EXPONENT := SHR(('^/IEEE754_IN.CV' & 2139095040),23);

    (* Extract the Sign from the bit 32 of the 32 bit word *)
    (* AND Mask to extract bit 32 then shift 31 bits to the right *)
    SGN := SHR(('^/IEEE754_IN.CV' & 2147483648),31);

    (* Extract the Mantissa from the bits 1 to 23 of the 32 bit word *)
    (* AND Mask to extract bits 1 to 23 *)
    MANTISSA := ('^/IEEE754_IN.CV' & 8388607);


    (* The maths used to create the FLOAT from SIGN, EXPONENT and MANTISSA *)

    OUT1 := EXPONENT - 127;
    OUT2 := SGN;
    OUT3 := MANTISSA;

    '^/FLOAT.CV' := (1+ (MANTISSA * (2 ** -23))) * (2 ** OUT1);

    IF SGN THEN '^/FLOAT.CV' := '^/FLOAT.CV' * -1; ENDIF;
  • In reply to IntuitiveNeil:

    Greetings,

    Thanks for the assistance, i managed to get it to work using a combination of the calcs from Steve/IntuitiveNeil.

    @niklas, the the DCS modbus goes through an Anybus convertor(Profibus slave <-> Modbus Slave) to Profibus of the PLC side, hence i could not do that.

    Thanks again.
  • In reply to AqAmra:

    IntuitiveNeil, I just found this site out, your math and programming are spot on!! I also need to go from the Floating Point back to a 32Bit number. Am i missing something above, or did you not include it?
  • In reply to IntuitiveNeil:

    I am having difficulty trying to convert the float back to a 32bit UINT to send a signal back to PF755 drives. Correct me if I am wrong, but the PF755 drives will only take 32UINT. Can I use the same code, but reverse logic to convert it into 32bit UINT?