Программирование ПЛК: преобразование в тип данных того же размера и обратное изменение фактического значения
Функциональный блок дает мне тип данных REAL. Реальное должно быть преобразовано в DWORD. На используемой платформе типы данных имеют следующие размеры:
- РЕАЛЬНО: 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, чтобы получить РЕАЛЬНОЕ, но в этот момент значение нежелательно.
3 ответа
Есть два варианта. Любитель, который предложил 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, которая копирует значения из памяти в другое место. Функция может называться немного по-разному в разных системах. Делая это, вы можете скопировать содержимое из местоположения вашего реального значения на адрес DWORD и обратно.
В направлении REAL->DWORD не должно быть никаких забот. Но при копировании из DWORD в REAL могут возникнуть некоторые проблемы, если есть вероятность, что данные были изменены где-либо. Возможно, что значением будет NaN или Infinity, что может вызвать сбой ПЛК. Это означает, что РЕАЛЬНО не правильно отформатированный десятичный номер.
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
Проблема в том, что вы используете преобразование, поэтому ваш REAL=0,819 будет преобразован в DWORD=1 и обратно в REAL=1. Битовое представление будет изменяться соответственно при каждом преобразовании.
Решением вашей проблемы является использование UNION (IEC 61131-3). Таким образом, вы можете записать в часть REAL, передать часть DWORD в другой код, а затем снова использовать часть REAL в этом коде.
Простым решением было бы умножить реальное значение в 10 n раз перед преобразованием, в зависимости от требуемой точности, например:
myReal := 0.819;
myDWord := REAL_TO_DWORD(myReal * 1000);
myResultReal := DWORD_TO_REAL(myDWord)/1000;