PLC编程:转换为相同大小的数据类型并返回更改实际值
PLC programming: Conversion to datatype of same size and back changes actual value
一个功能块给了我一些数据类型 REAL。 Real 必须转换为 DWORD。
在使用的平台上,数据类型具有以下大小:
- REAL:32 位(4 字节)
- DWORD:32 位(4 字节)
因此,我的想法是,如果只是在这两种数据类型之间传输位表示,则值不会改变或失去精度。
我想做的是以下内容:
myReal : REAL;
myDWord : DWORD;
myResultReal : REAL;
myReal := 0.819;
myDWord := REAL_TO_DWORD(myReal);
myResultReal := DWORD_TO_REAL(myDWord);
// myResultReal has value: 1
// Also when I check the bit string of the myDWord it differs from the actual
// bit string of myReal. Immediately after the first conversion.
整个问题就是编程语言的规则。由于两种数据类型具有相同的内存大小,因此似乎完全没有必要进行转换。转换的实际原因只是因为我需要稍后将我的号码传递给代码,它只接受 DWORD 数据类型。然后它使用 DWORD 获得一个 REAL,但此时该值受到了不良影响。
问题是您正在使用转换,因此您的 REAL=0.819 将转换为 DWORD=1,然后再转换回 REAL=1。位表示将在每次转换时相应更改。
解决您问题的方法是使用 UNION (IEC 61131-3)。这样您就可以写入 REAL 部分,将 DWORD 部分传递给您的其他代码,然后再次在该代码中使用 REAL 部分。
有两种选择。发烧友是 pboedker 建议的那个:UNION 数据类型。
示例:
TYPE U_TestUnion :
UNION
Value_DWORD : DWORD;
Value_REAL : REAL;
END_UNION
END_TYPE
VAR
TestUnion : U_TestUnion;
END_VAR
TestUnion.Value_REAL := 0.819;
//TestUnion.Value_DWORD is now 1062316540 (=16#3F51A9FC)
TestUnion.Value_DWORD := 10;
//TestUnion.Value_REAL is now 1.401298E-44
TestUnion.Value_DWORD := 1062316540;
//TestUnion.Value_REAL is now 0.819
另一种是使用MEMCPY函数,将值从内存复制到其他位置。该函数在不同系统中的命名可能略有不同。通过这样做,您可以将内容从 REAL 值的位置复制到 DWORD 的地址并向后复制。
REAL->DWORD方向,不用担心。但是从 DWORD 复制到 REAL 时,如果数据有可能在任何地方被修改,则可能会出现一些问题。该值可能是 NaN 或 Infinity,这可能会导致 PLC 崩溃。这意味着 REAL 的十进制数格式不正确。
VAR
Value_DWORD : DWORD;
Value_REAL : REAL;
END_VAR
Value_REAL := 0.819;
MEMCPY(destAddr:=ADR(Value_DWORD), srcAddr:=ADR(Value_REAL), n:=SIZEOF(Value_REAL));
//Value_DWORD is now 1062316540 (=16#3F51A9FC)
Value_DWORD := 10;
MEMCPY(destAddr:=ADR(Value_REAL), srcAddr:=ADR(Value_DWORD), n:=SIZEOF(Value_DWORD));
//Value_REAL is now 1.401298E-44
Value_DWORD := 1062316540;
MEMCPY(destAddr:=ADR(Value_REAL), srcAddr:=ADR(Value_DWORD), n:=SIZEOF(Value_DWORD));
//Value_REAL is now 0.819
一个简单的解决方案是在转换之前将实际值乘以 10 n 次,具体取决于您想要的精度,如下所示:
myReal := 0.819;
myDWord := REAL_TO_DWORD(myReal * 1000);
myResultReal := DWORD_TO_REAL(myDWord)/1000;
一个功能块给了我一些数据类型 REAL。 Real 必须转换为 DWORD。 在使用的平台上,数据类型具有以下大小:
- REAL:32 位(4 字节)
- DWORD:32 位(4 字节)
因此,我的想法是,如果只是在这两种数据类型之间传输位表示,则值不会改变或失去精度。 我想做的是以下内容:
myReal : REAL;
myDWord : DWORD;
myResultReal : REAL;
myReal := 0.819;
myDWord := REAL_TO_DWORD(myReal);
myResultReal := DWORD_TO_REAL(myDWord);
// myResultReal has value: 1
// Also when I check the bit string of the myDWord it differs from the actual
// bit string of myReal. Immediately after the first conversion.
整个问题就是编程语言的规则。由于两种数据类型具有相同的内存大小,因此似乎完全没有必要进行转换。转换的实际原因只是因为我需要稍后将我的号码传递给代码,它只接受 DWORD 数据类型。然后它使用 DWORD 获得一个 REAL,但此时该值受到了不良影响。
问题是您正在使用转换,因此您的 REAL=0.819 将转换为 DWORD=1,然后再转换回 REAL=1。位表示将在每次转换时相应更改。
解决您问题的方法是使用 UNION (IEC 61131-3)。这样您就可以写入 REAL 部分,将 DWORD 部分传递给您的其他代码,然后再次在该代码中使用 REAL 部分。
有两种选择。发烧友是 pboedker 建议的那个:UNION 数据类型。
示例:
TYPE U_TestUnion :
UNION
Value_DWORD : DWORD;
Value_REAL : REAL;
END_UNION
END_TYPE
VAR
TestUnion : U_TestUnion;
END_VAR
TestUnion.Value_REAL := 0.819;
//TestUnion.Value_DWORD is now 1062316540 (=16#3F51A9FC)
TestUnion.Value_DWORD := 10;
//TestUnion.Value_REAL is now 1.401298E-44
TestUnion.Value_DWORD := 1062316540;
//TestUnion.Value_REAL is now 0.819
另一种是使用MEMCPY函数,将值从内存复制到其他位置。该函数在不同系统中的命名可能略有不同。通过这样做,您可以将内容从 REAL 值的位置复制到 DWORD 的地址并向后复制。
REAL->DWORD方向,不用担心。但是从 DWORD 复制到 REAL 时,如果数据有可能在任何地方被修改,则可能会出现一些问题。该值可能是 NaN 或 Infinity,这可能会导致 PLC 崩溃。这意味着 REAL 的十进制数格式不正确。
VAR
Value_DWORD : DWORD;
Value_REAL : REAL;
END_VAR
Value_REAL := 0.819;
MEMCPY(destAddr:=ADR(Value_DWORD), srcAddr:=ADR(Value_REAL), n:=SIZEOF(Value_REAL));
//Value_DWORD is now 1062316540 (=16#3F51A9FC)
Value_DWORD := 10;
MEMCPY(destAddr:=ADR(Value_REAL), srcAddr:=ADR(Value_DWORD), n:=SIZEOF(Value_DWORD));
//Value_REAL is now 1.401298E-44
Value_DWORD := 1062316540;
MEMCPY(destAddr:=ADR(Value_REAL), srcAddr:=ADR(Value_DWORD), n:=SIZEOF(Value_DWORD));
//Value_REAL is now 0.819
一个简单的解决方案是在转换之前将实际值乘以 10 n 次,具体取决于您想要的精度,如下所示:
myReal := 0.819;
myDWord := REAL_TO_DWORD(myReal * 1000);
myResultReal := DWORD_TO_REAL(myDWord)/1000;