Welcome to our new forum
All users of the legacy CODESYS Forums, please create a new account at account.codesys.com. But make sure to use the same E-Mail address as in the old Forum. Then your posts will be matched. Close

AcuCD 240 data conversions

Timo-P
2013-05-30
2013-06-22
  • Timo-P - 2013-05-30

    I'm using AcuCD 240 with PLC measuring voltage, current and power with codesys. Communication via modbus. I have difficulties with data type conversion. I can't get right values after conversion. Conversion is hex to float. Internet calculation programs give right values, but code give following:

    Internet:

    hex value is 43cba825 and result is : 407,313629. this is correct.

    on code same conversion
    2 word to 1 dword -> dword to string -> float to real
    result is 1137420325, this is wrong value.

    Can you give good tips to this?

     
  • shooter - 2013-05-30

    go to w www.oscat.de w
    get the basic library and try some functions.

    i do know how to do it, but cant remeber it anymore.

     
  • Timo-P - 2013-06-17

    Hi,

    Thank you for your reply. Oscat didn't offer this kind of function. We solved the problem and write custom function to this.

    We did it this way:

    http://www.tfinley.net/notes/cps104/floating.html m

     
  • shooter - 2013-06-17

    i do know the notes of finley

    If you solved it in codesys please send it here or at oscat, they will put it in their standard library if you like to publish it.
    If you like i can revise the program, did not have time to have a good look at your problem.

     
  • jzhvymetal - 2013-06-21

    This can easily be done be using fixed mapping to your variables. Most CoDeSys controllers have fixed memory address. If you map a REAL and a DWORD to the same memory location it will CAST it to a REAL. This method will work in all versions of CoDeSys. Below is an example how:

    VAR
    myReal AT %MD0 : REAL;
    myDword AT %MD0 : DWORD;
    myByteArary AT %MB0 : ARRAY[0..3] OF BYTE;
    END_VAR

    myDword:=16#43CBA825; (THIS WILL EQUAL myReal=407.313629)

    To give you a better understanding how the memory map works refer to my other post for an excel sheet.

    l viewtopic.php?f=2&t=5045#p8228 l

     
  • spfeif - 2013-06-21

    Not sure do you mean you are trying to convert IEEE754 to REAL? Yes I used my FB and I calculated the correct number from your example. You need to use an algorithm it's IEEE754. You can find it on the internet. Funny a forum for CoDeSys and they don't let you post export file . But I will give it to you here there are catches when the number is not accurate you can adjust to anything you want:

    FUNCTION MATH_IEEE754_TO_REAL : REAL
    (*
      This is a conversion of single precision IEEE754 to real. The equation is as follows:
      (-1)^s * 2^(E-127) * (1.M)
      s = sign bit         = bit 31
      E = singed exponent  = bits-30 to 23
      M = Fraction         = bits 0-22
      There are some restrictions
      
      E = 255 and M <> 0 NaN
      E = 255 and M = 0 (-1)S oo (Infinity)
      E = 0 and M <> 0 (-1)S2-126(0.M)
      E = 0 and M = 0 (-1)S0
    *)
    VAR_INPUT
        i_lInput :DINT;
    END_VAR
    VAR
     ssign    :INT;
     exponent :INT;
     rexponent :REAL;
     rfraction :REAL;
     radder    :REAL;
     dwTemp: DWORD;
    END_VAR
    dwTemp := DINT_TO_DWORD(SHR(i_lInput,31));                    (* S *)
    IF (dwTemp = 0) THEN
        ssign := 1;
    ELSE
        ssign := -1;
    END_IF
    radder    := 1;                                              (* Standard adder for 1.M *)
    dwTemp    := DINT_TO_DWORD(i_lInput) AND 16#007FFFFF;
    rfraction := DWORD_TO_REAL(dwTemp) / 8388608;                  (* E *)
    dwTemp    := DINT_TO_DWORD(SHR(i_lInput,23)) AND 16#000000FF;
    exponent := DWORD_TO_INT(dwTemp);                             (* M *)
    IF (exponent = 255) AND (rfraction <> 0) THEN  (* Not a Number *)
        MATH_IEEE754_TO_REAL := 0;
    ELSIF (exponent = 255) AND (rfraction = 0) THEN (* -1^s oo (Infinity) *)
        MATH_IEEE754_TO_REAL := 0;
    ELSIF (exponent = 0) AND (rfraction <> 0) THEN
        radder    :=    0;
        exponent := -126;
    ELSIF (exponent = 0) AND (rfraction = 0) THEN
        MATH_IEEE754_TO_REAL := 0;
    ELSE
        rexponent := EXPT(2,(exponent - 127));
        MATH_IEEE754_TO_REAL := INT_TO_REAL(ssign) * rexponent * (radder + rfraction);
    END_IF
    

    Do you want to know another crazy thing? I had the variable "xesponent" (Turn the xes around since the editor will not display it) and the forum editor changed the variable name to "-". The reason is it scanned it and must have found "xes" and cut the word. I removed the s and everything worked. What type of forum is this? I thought Germans were very liberal ?

     
  • spfeif - 2013-06-21

    jzhvymetal love that icon. I too work with SoMachine. But not sure your example works see image? What Tim_P is referring to is something different.

    IMG: IEEE754.JPG

     
  • jzhvymetal - 2013-06-22

    Steve,

    It worked on my platforms. Maybe the reason it does not work on your platform is a little endian and big endian problem. Since I am simulating on CoDeSys runtime my the computer it is little endian. Can you verify the byte order is the same on your platform? If they are different there is no need for special function block you just need to arrange the bytes then cast it to the right variable type. It is bad that CoDeSys does not have the ability to cast like in C/C++. The function DINT_TO_FLOAT only take the current number in the DINT then converts to the equivalent REAL number. For example if you have 1137420325 it it will convert it to 1137420325.0 or 1.13742E+09.

    P.S. We did previous business together. I used to work for Schneider Electric.

    jzhvymetal

    IMG: CAST_DWORD_FLOAT.jpg

    IMG: CAST_DWORD_FLOAT2.jpg

    IMG: CAST_DWORD_FLOAT_M238.jpg

     

Log in to post a comment.