Не удается записать переменную типа real (float)

Стартовая страница Форумы Взаимодействие с устройствами Modbus Не удается записать переменную типа real (float)

Просмотр 15 сообщений - с 1 по 15 (из 45 всего)
  • Автор
    Сообщения
  • #3925
    manjey73
    Участник

    Через Modbus RTU.
    Что-то не пойму что надо выбирать, почему в командах не сделать так же, как в опросе, выбор переменной, перестановка битов ???

    #3926
    Mikhail
    Модератор

    Если команда для Holding Registers и не «множественная», то тип у неё UInt16.
    Перестановку битов было бы полезно сделать. Пока этой функции нет, нужно использовать формулы для каналов управления.

    #3927
    manjey73
    Участник

    Чтобы передать 4 байта, необходимо в любом случае устанавливать команду как «множественную» ?

    Можно при этом использовать тип команды «Стандартная» ?

    Перестановки байт не хватает. Было бы удобнее, нежели использование формул, если бы этим занималась библиотека…

    #3932
    Mikhail
    Модератор

    Чтобы передать 4 байта, необходимо в любом случае устанавливать команду как «множественную» ?

    Да, это определяется стандартом Модбас

    Можно при этом использовать тип команды «Стандартная» ?

    Да. Нужно, чтобы отправляемое в команде число double при декодировании содержало нужные байты.

    Перестановки байт не хватает. Было бы удобнее, нежели использование формул, если бы этим занималась библиотека…

    Средствами библиотеки было бы удобнее, но формулами можно сделать всё что угодно.

    #3939
    manjey73
    Участник

    Тогда объясните, какие 4 байта double соответствуют 4-рем байтам float
    А так же:
    1. в какой последовательности необходимо расположить байты в double, чтобы в ПЛК прилетело только нужные 4 байта
    2. Что произойдет с double, если мы ему пересортируем байты, ПК вообще поймет, что это тоже double или однажды нарвется на ошибку, так как не сможет его сконвертировать ?

    #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 ?

    • Ответ изменён 9 лет, 5 месяцев назад пользователем manjey73.
    • Ответ изменён 9 лет, 5 месяцев назад пользователем manjey73.
    #3948
    Mikhail
    Модератор

    o = f — присваивается ссылка на массив, а не значения. Во 2-м примере Вы работаете на самом деле только с одним массивом

    #3949
    Mikhail
    Модератор

    Если у Вас команда НЕ множественная, то нужно отправлять стандартную команду. При этом её значение просто округляется и обрезается до UInt16.

    Если команда множественная, то Коммуникатору нужен массив байт. Либо он его возьмёт из double — это 8 байт, либо возьмёт из явно заданного массива. Применительно к модулю авто управления нет никакого смысла пытаться зашифровать double, просто передавайте нужные байты в бинарной команде. Если всё же хочется зашифровать, то используйте http://www.binaryconvert.com/ или аналогичные утилиты.

    #3950
    Mikhail
    Модератор

    1. в какой последовательности необходимо расположить байты в double, чтобы в ПЛК прилетело только нужные 4 байта

    В той же, как работает BitConverter.GetBytes, если не ошибаюсь, будут переданы старшие байты.

    2. Что произойдет с double, если мы ему пересортируем байты, ПК вообще поймет, что это тоже double или однажды нарвется на ошибку, так как не сможет его сконвертировать ?

    Мне не доводилось сталкиваться с ошибкой преобразования, какие бы байты не конвертировались. Математика описана здесь https://en.wikipedia.org/wiki/Double-precision_floating-point_format

    #3956
    manjey73
    Участник

    на счет ссылки на массив понял.
    В остальном, когда rev = 1 то все работает, float записывается.
    Только непонятно почему при чтении байты имеют последовательность 2301 а при записи надо 1032 делать ?

    Если использовать Бинарную команду то это смерть оператору…
    Нам надо ввести температуру, например 22,0 градуса, вводить в бинарном виде, учитывая еще и переворот это просто жесть.

    ИМХО, надо разделять тип ввода команды и тип передачи команды. Например Серверу говорим тип ввода будет Стандартный (то есть числовое значение) а Сервер должен понимать для отправки double, byte[], string. Собственно мы указываем это в формуле, что мы вернем серверу и он должен это понимать.
    Потому что возвращая только double приходится выполнять лишние телодвижения.

    #3959
    Mikhail
    Модератор

    на счет ссылки на массив понял.

    Массив — это объект, при присваивании присваивается только ссылка на объект.

    Если использовать Бинарную команду то это смерть оператору…

    Это относилось к модулю авто управления. При ручной отправке команды работают формулы каналов управления.

    #4971
    VitaliyAT
    Участник

    Из этого диалога ничего непонятно.

    Вот как считать float я понял — надо развернуть местами по 2 байта. То есть была последовательность байтов 1234, надо отправить 3412.

    Как это сделать через Коммуникатор-программы?
    Я делал ЛинииСвязи-ЛинияХ-Команда-Стандартная-654,321-отправить — приходит мракобесина

    Как из самой СКАДЫ? Какое доп. шаманство там надо? Видео про это ничего не говорит. Там ещё как-то? Запишите доп. видео по приёму-передаче float значений пожалуйста.

    С Coil вопросов нет.

    • Ответ изменён 9 лет, 2 месяца назад пользователем VitaliyAT.
    • Ответ изменён 9 лет, 2 месяца назад пользователем VitaliyAT.
    #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.
    #4977
    Mikhail
    Модератор

    При отправке команды для изменения порядка байт нужно использовать формулу канала управления. Формула зависит от того, что именно требуется контроллеру — желательно посмотреть в его документации.

    #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 месяца назад пользователем VitaliyAT.
    • Ответ изменён 9 лет, 2 месяца назад пользователем VitaliyAT.
    • Ответ изменён 9 лет, 2 месяца назад пользователем VitaliyAT.
    • Ответ изменён 9 лет, 2 месяца назад пользователем VitaliyAT.
Просмотр 15 сообщений - с 1 по 15 (из 45 всего)
  • Для ответа в этой теме необходимо авторизоваться.