Стартовая страница › Форумы › Взаимодействие с устройствами › Опрос СТУ-1
- В этой теме 13 ответов, 4 участника, последнее обновление 2 года, 1 месяц назад сделано
Mikhail.
-
АвторСообщения
-
29.04.2024 в 19:41 #32566
Wizard256
УчастникЗдравствуйте!
Есть прибор СТУ-1 работает по Modbus. С текущими значениями разобрался по документации (для float порядок байт 2301). Проблема с Накопленными значениями Например накопленная энергия Е1 в документации написано:
002E/002F/0030/0031 Накопленная тепловая энергия 1 тепловвода E1, ГДж тип long/float
Значения накопленного объема (накопленной массы, накопленной энергии) представляют две составляющие типа long и float. В четырех первых байтах содержится целая часть значения (long), в остальных четырех – вещественная (float).
Инструкция к СТУ-1 по модбас
Лог Коммуникатора:
Запрос значений группы элементов «Nakopl»
Отправка (8): 01 03 00 2E 00 38 24 11
Приём (2/2): 01 03
Приём (115/115): 70 90 AF 00 06 8C 13 3F 0F F8 F7 00 02 79 E1 3E 66 00 00 00 00 00 00 00 00 00 00 00 00 9C 05 33 EF 65 C0 00 1B 9C 54 3D 14 48 5F 00 27 96 3D 3E BC 57 55 00 0C C7 7C 3F 36 F9 28 00 0B 53 72 3E 8F 00 00 00 00 00 00 00 00 00 00 00 00 D5 4A 33 EC CB 24 00 19 38 7C 3F 65 B5 18 00 25 C2 D1 3E 16 D2 B8 00 0B D4 18 3E 34 78 F4 00 0B BA 93 3F 2E 3B 28
ОК
вопрос, как мне получить значение E1 (на экране прибора E1=430255.560731)
из этих 8 байт 90 AF 00 06 8C 13 3F 0F
Онлайн конвертеры говорят:
00 06 90 AF = 430255
3F 0F 8C 13 = 0.5607311
собственно как из 8 байт собрать число Е1 не плодя каналы
пока настройки такие:
<?xml version=»1.0″ encoding=»utf-8″?>
<DeviceTemplate>
<Options>
<ZeroAddr>true</ZeroAddr>
<DecAddr>false</DecAddr>
<DefByteOrder2 />
<DefByteOrder4 />
<DefByteOrder8 />
</Options>
<ElemGroups>
<ElemGroup active=»true» dataBlock=»HoldingRegisters» address=»0″ name=»Izmereniya»>
<Elem type=»float» byteOrder=»2301″ readOnly=»true» isBitMask=»false» tagCode=»v1″ name=»v1″ />
<Elem type=»float» byteOrder=»2301″ readOnly=»true» isBitMask=»false» tagCode=»v2″ name=»v2″ />
<Elem type=»float» byteOrder=»2301″ readOnly=»true» isBitMask=»false» tagCode=»v3″ name=»v3″ />
<Elem type=»float» byteOrder=»2301″ readOnly=»true» isBitMask=»false» tagCode=»v4″ name=»v4″ />
<Elem type=»float» byteOrder=»2301″ readOnly=»true» isBitMask=»false» tagCode=»v5″ name=»v5″ />
<Elem type=»float» byteOrder=»2301″ readOnly=»true» isBitMask=»false» tagCode=»v6″ name=»v6″ />
<Elem type=»ushort» readOnly=»true» isBitMask=»false» tagCode=»t1″ name=»t1″ />
<Elem type=»ushort» readOnly=»true» isBitMask=»false» tagCode=»t2″ name=»t2″ />
<Elem type=»ushort» readOnly=»true» isBitMask=»false» tagCode=»t3″ name=»t3″ />
<Elem type=»ushort» readOnly=»true» isBitMask=»false» tagCode=»t4″ name=»t4″ />
<Elem type=»ushort» readOnly=»true» isBitMask=»false» tagCode=»t5″ name=»t5″ />
<Elem type=»ushort» readOnly=»true» isBitMask=»false» tagCode=»t6″ name=»t6″ />
<Elem type=»ushort» readOnly=»true» isBitMask=»false» tagCode=»p1″ name=»p1″ />
<Elem type=»ushort» readOnly=»true» isBitMask=»false» tagCode=»p2″ name=»p2″ />
<Elem type=»ushort» readOnly=»true» isBitMask=»false» tagCode=»p3″ name=»p3″ />
<Elem type=»ushort» readOnly=»true» isBitMask=»false» tagCode=»p4″ name=»p4″ />
</ElemGroup>
<ElemGroup active=»true» dataBlock=»HoldingRegisters» address=»46″ name=»Nakoplennie dannie»>
<Elem type=»long» readOnly=»true» isBitMask=»false» tagCode=»e1″ name=»e1″ />
<Elem type=»long» readOnly=»true» isBitMask=»false» tagCode=»e2″ name=»e2″ />
<Elem type=»long» readOnly=»true» isBitMask=»false» tagCode=»nv1″ name=»nv1″ />
<Elem type=»long» readOnly=»true» isBitMask=»false» tagCode=»nv2″ name=»nv2″ />
<Elem type=»long» readOnly=»true» isBitMask=»false» tagCode=»nv3″ name=»nv3″ />
<Elem type=»long» readOnly=»true» isBitMask=»false» tagCode=»nv4″ name=»nv4″ />
<Elem type=»long» readOnly=»true» isBitMask=»false» tagCode=»nv5″ name=»nv5″ />
<Elem type=»long» readOnly=»true» isBitMask=»false» tagCode=»nv6″ name=»nv6″ />
<Elem type=»long» readOnly=»true» isBitMask=»false» tagCode=»nm1″ name=»nm1″ />
<Elem type=»long» readOnly=»true» isBitMask=»false» tagCode=»nm2″ name=»nm2″ />
<Elem type=»long» readOnly=»true» isBitMask=»false» tagCode=»nm3″ name=»nm3″ />
<Elem type=»long» readOnly=»true» isBitMask=»false» tagCode=»nm4″ name=»nm4″ />
<Elem type=»long» readOnly=»true» isBitMask=»false» tagCode=»nm5″ name=»nm5″ />
<Elem type=»long» readOnly=»true» isBitMask=»false» tagCode=»nm6″ name=»nm6″ />
</ElemGroup>
<ElemGroup active=»true» dataBlock=»HoldingRegisters» address=»102″ name=»Vremya narabotki»>
<Elem type=»int» byteOrder=»012″ readOnly=»false» isBitMask=»false» tagCode=»tt1″ name=»tt1″ />
<Elem type=»int» byteOrder=»012″ readOnly=»false» isBitMask=»false» tagCode=»tt2″ name=»tt2″ />Так же интересно интересно время наработки.
Из документации:0066/0067 Время наработки 1 канала, мин тип 3 байта
Накопленное время наработки хранится в младших 3 байтах, в минутах.Из коммуникатора:
Запрос значений группы элементов «Twr»
Отправка (8): 01 03 00 66 00 04 A4 16
Приём (2/2): 01 03
Приём (11/11): 08 A0 9B 2C 04 A3 EF 2C 0C 4C 7E
OK
на экране прибора значение 5054,32.
С программированием не дружу, специфика работы КИПиА.
Заранее спасибо.29.04.2024 в 20:50 #32569
MikhailМодераторДобрый день!
В четырех первых байтах содержится целая часть значения (long), в остальных четырех – вещественная (float).
Считать целую и дробную часть числа как отдельные теги устройства. Они запишутся в разные каналы. Затем в расчётном канале сложить их для получения конечного результата. Неудобно, конечно, но как видите, значения имеют разные типы данных.
0066/0067 Время наработки 1 канала, мин тип 3 байта
Накопленное время наработки хранится в младших 3 байтах, в минутах.Забрать данные в канал и в формуле канала по маске взять 3 байта.
> С программированием не дружу, специфика работы КИПиА
Программирование не понадобится. Только формулы из математики.P.S. Разбирать настройки в XML на глаз вряд ли кто-то будет. Делайте скриншоты настроек.
30.04.2024 в 10:24 #32573Wizard256
УчастникДобрый день!
С накопленными разобрался, на каждое значение сделал 2 канала 1 int и 2 float, потом доделаю каналы с суммами 2х чисел. Проблема с временем наработки.
из лога коммуникатора:
Запрос значений группы элементов «Vremya narabotki»
Отправка (8): 01 03 00 66 00 04 A4 16
Приём (2/2): 01 03
Приём (11/11): 08 A0 9B 2C 04 A3 EF 2C 0C 4C 7E
OKздесь 2 числа
Twr1: A0 9B 2C 04
Twr2: A3 EF 2C 0C
далее на табло у нас значение в часах, например Twr2=13806.65 далее переводим в минуты получаем 828 399. Онлайн калькулятор нам говорит 00 0C A3 EF , т.е. если я правильно понял то порядок байт 301.
На выходе получаем не то что надо, куда копать ?
скрин и файлы
Ссылка на диск30.04.2024 в 10:59 #32576
JurasskParkУчастникTwr1: A0 9B 2C 04
В карте регистров написано 3байта.
То есть A0 — выкидываете.
9B 2C 04 — 10 169 348 минут30.04.2024 в 11:29 #32577Wizard256
УчастникЯ чего-то не понимаю, в приборе Twr1 = 5054.32 (округлено) т.е. 303259 минут. По калькуляторам онлайн нужно выкинуть 2С и собрать биты в 04 A0 9B — 303259
как это сделать ?30.04.2024 в 12:01 #32578
JurasskParkУчастникЕсть такой понятие как старший байт, младший байт.
Если представление числа в машинном коде (то есть, в двоичной форме) занимает больше 8 бит (1 байта) , то оно разбивается на несколько байт. Типичный случай — представление целых чисел (integer) в 32-разрядных операционках занимает 32 бита, то есть 4 байта.Первый байт — разряды 1-8,
второй байт — разряды 9-16,
третий байт — разряды 17-24,
и так далее.Байт, в котором хранятся младшие разряды (1-8) — младший, в котором старшие — старший.
303259 = 04 A0 9B, но так как регистр в модбасе по умолчанию 2 байта, то слева нужно добавить 0. Получиться 00 04 A0 9B
То есть 00 04 A0 9B состоит из 2 регистров.
00 04 — первый регистр
A0 9B — второй регистр00 04 A0 9B
00 — старший байт (первый регистр)
04 — младший байт (первый регистр)
A0 — старший байт (второй регистр)
9B — младший байт (второй регистр)Теперь через формулу подставить полученный целое число и получить младший байт.
Сейчас под рукой нет скады. Но вроде там было.ushort number = Convert.ToUInt16(«3510»);
byte upper = (byte) (number >> 8);
byte lower = (byte) (number & 0xff);30.04.2024 в 12:10 #32579
MikhailМодераторОбщая идея как выделить 3 байта из значения канала:
1. Канал хранится как double. Поэтому прежде, чем брать 3 байта, значение канала нужно преобразовать в целый тип. Пожалуй, int подойдёт. На C# int — это 4 байтное целое со знаком.
2. Если нужно удалить старший байт, то применить двоичное умножение на число 0x00FFFFFF
Если нужно удалить младший байт, то сдвинуть вправо на 8 битФормулы уже написаны выше, но удобнее экспериментировать сразу с формулой канала. Она будет примерно такая:
((int)Cnl) & 0x00FFFFFF
или
((int)Cnl) >> 8
(не проверял)30.04.2024 в 12:22 #32582Wizard256
УчастникСпасибо за помощь! Методом перебора в настройках шаблона выставил порядок 230 и получил свои минуты просто считать нужно было с права на лево. посмотрим как будет дальше, а пока значения совпадают с тем что мне нужно. Далее просто Cnl/60 и всё должно быть почти как на экране прибора. Или лучше через формулу а порядок байт в настройках убрать?
30.04.2024 в 13:05 #32583Wizard256
УчастникКак я понял по Онлайн конвертерам и Яндексу, прибор выдаёт значения в Mid-Little Endian (CDAB) (Скорее всего касается и приборов УРЖ2КМ у них один производитель).
В перспективе осталось разобраться с текущим временем прибора 1 регистр в 6 байт (Скорее всего дергать как uLong 1им каналом или 3мя в ushort), в каждом байте десятичное число даты и времени. Скорее всего придется раскладывать на каждый байт по отдельности, конвертировать в десятичное число и собирать в строку.30.04.2024 в 17:32 #32599Wizard256
УчастникИзвиняюсь если достал, насколько я понял драйвер сам по порядку байт собирает число
и заполняет нулями.
Теперь вопрос как собрать из 2х чисел в 4 байта и 2 байта Чтобы потом Можно было воспользоваться DecodeDate(val). Почитав интернет попробовал собрать 2 числа в 1
в vscodec сделал так:UInt32 d = 0x1e041810 ;
ushort t = 0x1224 ;
double val = ((long)d << 16)|((Int16)t ) ;
Console.WriteLine(«,»+val);
,33002932408868по байтам вроде как надо.
Теперь вопрос как это реализовать в Скаде в расчетном канале?
заранее спасибо.02.05.2024 в 12:16 #32625
MikhailМодераторЕсли в скаде эти числа записаны в разных каналах, то простой вариант формулы расчётного канала будет
((long)Val(101) << 16)|((Int16)Val(102))
где 101 и 102 — номера соответствующих каналов.
Формула не учитывает статусы каналов, но для теста её будет достаточно.05.05.2024 в 20:56 #32646Wizard256
УчастникСпасибо за помощь!
В общем после долгих танцев с бубном и из-за недостатка знаний, сделал чтение 3х регистров short и создал 6 расчетных каналов. Далее с помощью операций показанных ранее по смещения и умножения получил отдельные цифры даты и времени. Как сделать лучше пока не придумал. Скриншоты на диске по ссылке. В текстовом файле есть строка преобразования данных в дату и время, только пока не понятно как ее прикрутить к Скаде чтобы уменьшить количество каналов. Если кто сможет помочь буду благодарен.06.05.2024 в 08:55 #32647
manjey73Участник@Wizard256 если часть операций можно сделать сразу во входном канале, то может получится сократить расчетные.
06.05.2024 в 12:34 #32648
MikhailМодераторЕсли много каналов используют аналогичные формулы, то формулу можно внести в таблицу Скрипты в виде отдельной функции, чтобы было удобнее её вызывать.
Длинную формулу тоже лучше сделать отдельной функцией.public double MyFunc() { return ... } -
АвторСообщения
- Для ответа в этой теме необходимо авторизоваться.