Стартовая страница › Форумы › Взаимодействие с устройствами › Modbus › Не удается записать переменную типа real (float)
- В этой теме 44 ответа, 3 участника, последнее обновление 9 лет, 2 месяца назад сделано
manjey73.
-
АвторСообщения
-
24.12.2016 в 23:40 #3925
manjey73УчастникЧерез Modbus RTU.
Что-то не пойму что надо выбирать, почему в командах не сделать так же, как в опросе, выбор переменной, перестановка битов ???26.12.2016 в 11:17 #3926
MikhailМодераторЕсли команда для Holding Registers и не «множественная», то тип у неё UInt16.
Перестановку битов было бы полезно сделать. Пока этой функции нет, нужно использовать формулы для каналов управления.26.12.2016 в 11:32 #3927
manjey73УчастникЧтобы передать 4 байта, необходимо в любом случае устанавливать команду как «множественную» ?
Можно при этом использовать тип команды «Стандартная» ?
Перестановки байт не хватает. Было бы удобнее, нежели использование формул, если бы этим занималась библиотека…
26.12.2016 в 17:21 #3932
MikhailМодераторЧтобы передать 4 байта, необходимо в любом случае устанавливать команду как «множественную» ?
Да, это определяется стандартом Модбас
Можно при этом использовать тип команды «Стандартная» ?
Да. Нужно, чтобы отправляемое в команде число double при декодировании содержало нужные байты.
Перестановки байт не хватает. Было бы удобнее, нежели использование формул, если бы этим занималась библиотека…
Средствами библиотеки было бы удобнее, но формулами можно сделать всё что угодно.
26.12.2016 в 22:46 #3939
manjey73УчастникТогда объясните, какие 4 байта double соответствуют 4-рем байтам float
А так же:
1. в какой последовательности необходимо расположить байты в double, чтобы в ПЛК прилетело только нужные 4 байта
2. Что произойдет с double, если мы ему пересортируем байты, ПК вообще поймет, что это тоже double или однажды нарвется на ошибку, так как не сможет его сконвертировать ?27.12.2016 в 11:15 #3943
manjey73Участникpublic double fRevers (int rev)
{
float q = Convert.ToSingle(CmdVal);
byte[] f = new byte[4];
byte[] o = new byte[4];
f = BitConverter.GetBytes(q);
if (rev == 1)
{
Array.Copy(f, 0, o, 1, 1);
Array.Copy(f, 1, o, 0, 1);
Array.Copy(f, 2, o, 3, 1);
Array.Copy(f, 3, o, 2, 1);
}
else o = f;
Array.Resize(ref o, 8);
Double ou = BitConverter.ToDouble(o,0);
return ou;
}———————————————————————————-
public double fRevers (int rev)
{
float q = Convert.ToSingle(CmdVal);
byte[] f = new byte[4];
byte[] o = new byte[4];
f = BitConverter.GetBytes(q);
o = f;
if (rev == 1)
{
Array.Copy(f, 0, o, 1, 1);
Array.Copy(f, 1, o, 0, 1);
Array.Copy(f, 2, o, 3, 1);
Array.Copy(f, 3, o, 2, 1);
}
Array.Resize(ref o, 8);
Double ou = BitConverter.ToDouble(o,0);
return ou;
}Интересно, что в почти одинаковых кодах не так, с точки зрения логики, что работают они по разному ?
А так же хотелось бы понять, почему при чтении я переставляю в запросе байты 2301 а при записи делаю 1032 ?
27.12.2016 в 14:06 #3948
MikhailМодераторo = f — присваивается ссылка на массив, а не значения. Во 2-м примере Вы работаете на самом деле только с одним массивом
27.12.2016 в 14:11 #3949
MikhailМодераторЕсли у Вас команда НЕ множественная, то нужно отправлять стандартную команду. При этом её значение просто округляется и обрезается до UInt16.
Если команда множественная, то Коммуникатору нужен массив байт. Либо он его возьмёт из double — это 8 байт, либо возьмёт из явно заданного массива. Применительно к модулю авто управления нет никакого смысла пытаться зашифровать double, просто передавайте нужные байты в бинарной команде. Если всё же хочется зашифровать, то используйте http://www.binaryconvert.com/ или аналогичные утилиты.
27.12.2016 в 14:14 #3950
MikhailМодератор1. в какой последовательности необходимо расположить байты в double, чтобы в ПЛК прилетело только нужные 4 байта
В той же, как работает BitConverter.GetBytes, если не ошибаюсь, будут переданы старшие байты.
2. Что произойдет с double, если мы ему пересортируем байты, ПК вообще поймет, что это тоже double или однажды нарвется на ошибку, так как не сможет его сконвертировать ?
Мне не доводилось сталкиваться с ошибкой преобразования, какие бы байты не конвертировались. Математика описана здесь https://en.wikipedia.org/wiki/Double-precision_floating-point_format
27.12.2016 в 19:56 #3956
manjey73Участникна счет ссылки на массив понял.
В остальном, когда rev = 1 то все работает, float записывается.
Только непонятно почему при чтении байты имеют последовательность 2301 а при записи надо 1032 делать ?Если использовать Бинарную команду то это смерть оператору…
Нам надо ввести температуру, например 22,0 градуса, вводить в бинарном виде, учитывая еще и переворот это просто жесть.ИМХО, надо разделять тип ввода команды и тип передачи команды. Например Серверу говорим тип ввода будет Стандартный (то есть числовое значение) а Сервер должен понимать для отправки double, byte[], string. Собственно мы указываем это в формуле, что мы вернем серверу и он должен это понимать.
Потому что возвращая только double приходится выполнять лишние телодвижения.28.12.2016 в 09:35 #3959
MikhailМодераторна счет ссылки на массив понял.
Массив — это объект, при присваивании присваивается только ссылка на объект.
Если использовать Бинарную команду то это смерть оператору…
Это относилось к модулю авто управления. При ручной отправке команды работают формулы каналов управления.
30.03.2017 в 15:46 #4971
VitaliyATУчастникИз этого диалога ничего непонятно.
Вот как считать float я понял — надо развернуть местами по 2 байта. То есть была последовательность байтов 1234, надо отправить 3412.
Как это сделать через Коммуникатор-программы?
Я делал ЛинииСвязи-ЛинияХ-Команда-Стандартная-654,321-отправить — приходит мракобесинаКак из самой СКАДЫ? Какое доп. шаманство там надо? Видео про это ничего не говорит. Там ещё как-то? Запишите доп. видео по приёму-передаче float значений пожалуйста.
С Coil вопросов нет.
30.03.2017 в 16:02 #4975
manjey73УчастникVitaliyAT проблема заключается в том, что разные процессоры имеют разную архитектуру по последовательности байт, плюс сам Modbus еще имеет какие-то особенности.
в ПЛК63 и в ПР200 я записываю float так:
Добавил в базу формул такую функцию(формулу)public double fRevers (int rev)
{
float q = Convert.ToSingle(CmdVal);
byte[] f = new byte[4];
byte[] o = new byte[4];
f = BitConverter.GetBytes(q);
Array.Copy(f,0,o,0,4);
if (rev == 1)
{
Array.Copy(f, 0, o, 1, 1);
Array.Copy(f, 1, o, 0, 1);
Array.Copy(f, 2, o, 3, 1);
Array.Copy(f, 3, o, 2, 1);
}
Array.Resize(ref o, 8);
Double ou = BitConverter.ToDouble(o,0);
return ou;
}И в канале управления указываю использовать формулу fRevers(1) тип команды Стандартная. (1) это просто один из вариантов переворота float, который понимает ПЛК63 и ПР200 от Овен. Потребуется еще как-то перевернуть, просто добавить if (rev == 2) и свой переворот.
Из Коммуникатора никак не переставить байты местами вроде, кроме как правильно для передающего устройства послать их в бинарном виде.
-
Ответ изменён 9 лет, 2 месяца назад пользователем
manjey73.
30.03.2017 в 16:17 #4977
MikhailМодераторПри отправке команды для изменения порядка байт нужно использовать формулу канала управления. Формула зависит от того, что именно требуется контроллеру — желательно посмотреть в его документации.
30.03.2017 в 16:31 #4983
VitaliyATУчастникПри отправке 654,321 из коммуникатора и получении в первом элементе байтового массива «8624», второго — «29288».
Приёмку значений на стороне ПЛК отрабатывает код (на ST + ПЛК B&R):
CASE fWordSwap OF 0: // без переворота 0123 = 0123 brsmemcpy(pReal, pMBT, 4); 1: // Простой переворот 0123 = 2301 brsmemcpy((pReal+0), (pMBT+2), 1); brsmemcpy((pReal+1), (pMBT+3), 1); brsmemcpy((pReal+2), (pMBT+0), 1); brsmemcpy((pReal+3), (pMBT+1), 1); //brsmemcpy(pReal, (pMBT+2), 2); //brsmemcpy((pReal+2), pMBT, 2); 2: // Хитрый переворот 1 0123 = 1032 (Рэпид скаде такой вроде) brsmemcpy((pReal+0), (pMBT+1), 1); brsmemcpy((pReal+1), (pMBT+0), 1); brsmemcpy((pReal+2), (pMBT+3), 1); brsmemcpy((pReal+3), (pMBT+2), 1); 3: // Хитрый переворот 2 0123 = 3210 brsmemcpy((pReal+0), (pMBT+3), 1); brsmemcpy((pReal+1), (pMBT+2), 1); brsmemcpy((pReal+2), (pMBT+1), 1); brsmemcpy((pReal+3), (pMBT+0), 1); 4: // Хитрый переворот 3 0123 = 3120 brsmemcpy((pReal+0), (pMBT+3), 1); brsmemcpy((pReal+1), (pMBT+1), 1); brsmemcpy((pReal+2), (pMBT+2), 1); brsmemcpy((pReal+3), (pMBT+0), 1); 5: // Хитрый переворот 4 0123 = 3021 brsmemcpy((pReal+0), (pMBT+3), 1); brsmemcpy((pReal+1), (pMBT+0), 1); brsmemcpy((pReal+2), (pMBT+2), 1); brsmemcpy((pReal+3), (pMBT+1), 1); END_CASE;копировать_в_память (куда, откуда, сколько)
Ничего вразумительного ни по одному из авриантов я не получаю.
Я хочу организовать расшифровку на стороне ПЛК.
Как отправку кодирует Коммуникатор?
…ОК… допусти если кодировать будет СКАДА получается кодирует по другому, точнее её можно заставить кодировать по другому через вышеприведённую формулу…
Уважаемые разработчики, сделайте настройки для кодирования float параметров по человечески, пожалуйста! Чтоб можно было выбирать что и как вращается и местами меняется.
-
Ответ изменён 9 лет, 2 месяца назад пользователем
-
АвторСообщения
- Для ответа в этой теме необходимо авторизоваться.