PDA

Просмотр полной версии : Пример: Убыстрение опроса модулей Мх110 в CodeSys v2.3 через модули STRING[]



Cs-Cs
16.07.2021, 14:13
Во многих темах камрад Валенок постоянно говорит о том, что если мы хотим читать (или писать) много регистров подряд в CodeSys v2.3 по Modbus, то надо использовать модули STRING. Когда я про это читал, то я примерно понял о чём идёт речь - читать кучку байтов, и собирать из неё значения переменных.
На форуме эта мысль проскакивает в куче тем, но никто не даёт рабочего (или понятного) примера. В одной из тем я обещался написать пост на блоге, когда разберусь. До поста - далеко, поэтому пишу кратко на форум.

В чём особенность работы CodeSys v2.3?
Основная её особенность в том, что каждый элемент, который мы добавляем в Конфигурацию ПЛК, всегда опрашивается (читается/пишется) одним отдельным запросом.
Поэтому если мы для 8 каналов модуля аналоговых вводов добавим в конфигурацую ПЛК 8 значений FLOAT, и ещё и для статуса измерения канала добавим 8 WORD - то CodeSys будет забрасывать этот модуль 8 + 8 = 16 отдельными запросами.
Если поглядеть в спецификацию протокола ModBus RTU, то мы увидим, что на уровне байтиков, которые передаются по линии данных, то один запрос на чтение регистра занимает (ориентируюсь на эту статью из инета https://ipc2u.ru/articles/prostye-resheniya/modbus-rtu/):
* 1 Байт = Адрес устройства
* 1 Байт = Команда (шо делать)
* 2 Байта = Начальный адрес регистра (для чтения данных) - меняется только он
* 2 Байта = Сколько штук регистров читать
* 2 Байта = CRC (проверка верности данных)
То есть, на чтение одного регистра нам надо пихнуть в линию запрос длиной 1 + 1 + 2 + 2 + 2 = 8 байтов.

Ответ модуля на один наш запрос будет представлять такую кучу байтов:
* 1 Байт = Адрес устройства
* 1 Байт = Команда или код ошибки
* 1 Байт = Длина данных дальше - у нас будет равно 2, так как один регистр модуля = 2 байтам
* 2 Байта = Значение регистра, который мы читаем
* 2 Байта = CRC (проверка верности данных)
То есть, один ответ модуля с одним регистром займёт 1 + 1 + 1 + 2 + 2 = 7 байтов.

А теперь множим это на число регистров (16 штук): 16 * 8 + 16 * 7 = 128 + 112 = 240 курвичных байтов у нас уходит на то, чтобы обменяться инфой с модулем!
И байты-то ладно. А в линии ещё есть и разные паузы, и работает передача данных так (очень условно): Пауза - Запрос - Пауза - Ответ - Пауза. И эти паузы сжирают время, которое мы могли бы потратить на опрос других модулей.

Как народ выходит из проблемы? Ведь CodeSys v2.3 не поддерживает групповое чтение регистров?
В CodeSys v2.3 есть возможность читать байты (не регистры!) как STRING[79].
В конфигурацию ПЛК можно добавить "String input module" или "String output module", в котором указать начальный адрес регистра и число байт для чтения. Один регистр занимает два байта.
В этом случае такой STRING[] будет прочитан одним запросом Modbus целиком.
Ограничение этого STRING[] - в 79 байтов. Больше прочитать нельзя и в этом случае вам придётся разбивать ваши регистры на два или более STRING[].

Применить такой метод получится только если все регистры модуля IO идут подряд (или с небольшими пропусками): 0, 1, 2, 3, 4... и так далее.
Есть некоторые устройства (например датчики WirenBoard WB-MSW), которые имеют пропуски в карте регистров, условно: 0, 1... 3, 4, 5... 8, 9, 10, 11. Если такие устройства позволяют читать несуществующие регистры (WirnBoard - нет), то даже в этом случае можно запросить подряд регистры с 0 до 11 в моём примере.

Как рассчитывать длину байт и регистров?
Один регистр WORD/INT занимает 2 байта
Один регистр DWORD/LONG/FLOAT занимает 4 байта

Вот пример моего подсчёта для одного канала модуля аналоговых входов (МВ110-224.8А):

Байт Назначение Порядок Байт
1 = Положение десятичной точки = (LSB)
2 = Положение десятичной точки = (HSB)

3 = Целое значение измерения = (LSB)
4 = Целое значение измерения = (HSB)

5 = Статус измерения канала = (LSB)
6 = Статус измерения канала = (HSB)

7 = Циклическое время измерения = (LSB)
8 = Циклическое время измерения = (HSB)

9 = Измеренное значение Float32 = Старшая часть (LSB)
10 = Измеренное значение Float32 = Старшая часть (HSB)
11 = Измеренное значение Float32 = Младшая часть (LSB)
12 = Измеренное значение Float32 = Младшая часть (HSB)
То есть, на один канал модуля МВ110-224.8А нам надо 12 байт.
Значит, если мы хотим прочитать все 8 каналов этого модуля, нам понадобится 12 х 8 = 96 байт.
У нашего STRING[] имеется ограничение в 79 байт. Значит, в данном случае мы разделим наши каналы на два STRING[]
Я разделил так, чтобы один STRING[] был максимально заполнен: 6 каналов (72 байта) + 2 канала (24 байта).
К этим каналам STRING прямо в конфигурации ПЛК мы привязываем переменные, и дальше работаем с ними.

Как обрабатывать такие данные?
В приложенном примере я написал свою версию обработки с подробными комментариями.
Особенность моей версии в следующем. Из-за странных преобразований типов в CodeSys нельзя просто так взять и обращаться к переменной, которая приязана к такому каналу: она видится как строка, а нам нужны байты.
Народ на форуме делает ручную привязку, объявляя в коде программы массив байтов и привязывая его через команду AT %QB...
Мне этот способ не нравится, так как я не хочу следить за изменением адресов в конфигурации ПЛК, если я туда решу что-то добавить или изменить.
Поэтому я (по аналогии со старым добрым языком СИ) использовать копирование буферов в память при помощи функции SysMemCpy() из библиотеки SysMem. Я копирую заданный мне буфер в свой, и разбираю его побайтно, забирая столько байтов, сколько мне необходимо:

VAR_INPUT
pData : DWORD; (* Указатель (ADR) на переменную начала буфера данных *)
pDataSize : DWORD; (* Максимальная длина данных от модуля - 12 байт *)
END_VAR

SysMemCpy(ADR(pBuffer), pData, pDataSize);
Далее я использую операции с битами (SHL, SHR) и побитные операторы (AND, OR) для того, чтобы склеить число из двух байтов.
Например, чтобы получить WORD из двух байтов, я делаю так:

CSParseMV8A.ValDigPoint := ((BYTE_TO_WORD(pBuffer[1]) OR SHL(BYTE_TO_WORD(pBuffer[2]), 8)));
Младший байт (pBuffer[1]) идёт здесь первым, поэтому я его просто склеиваю через OR
Старший байт идёт здесь вторым, поэтому его надо сдвинуть влево на 8 бит (из 16#0012 превратить в 16#1200) при помощи оператора SHR и снова склеить с нужным нам числом.
Вот так склеивается Float32 (REAL):

VAR
pFloat32Val : ARRAY [1..4] OF BYTE; (* Буфер для сборки переменной типа Float32 побайтно = 4 байта *)
END_VAR

(* Теперь клеим Float32 по схеме из таблички выше *)
(* Просто пихаем в наш буфер нужные байты в нужном порядке [3] [4] [1] [2] *)
pFloat32Val[1] := pBuffer[11];
pFloat32Val[2] := pBuffer[12];
pFloat32Val[3] := pBuffer[9];
pFloat32Val[4] := pBuffer[10];

(* А теперь копируем этот кусочек памяти в нашу переменную REAL - длина = 4 байта (размер REAL) *)
SysMemCpy(ADR(CSParseMV8A.ValFloat), ADR(pFloat32Val), 4);
Я завёл ещё один массив из 4 байтов, в который подставляю байты для сборки Float в нужном порядке (он указан в коде в комментариях), а потом при помощи SysMemCpy представляю этот массив как 4 байта памяти и копирую его в значение типа Float.

Аналогичным образом я делаю запись в модуль аналогового вывода МУ110-224.6У.
Я разбираю число WORD (от 000,0% до 100,0% - от 0 до 1000) на два байта (старший и младший), а потом пихаю их в буфер из массва байтов.А уже этот буфер снова копирую в переменную, привязанную к каналу String Output module:

VAR
(* Тест записи в каналы модуля МУ110-224.6У *)
testBuffer : ARRAY [1..12] OF BYTE; (* Буфер, который мы будем передавать данные для каналов модуля *)
testValueCh1 : WORD := 1000; (* 100,0% для канала *)
testValueCh2 : WORD := 1000;
testValueCh3 : WORD := 1000;
END_VAR

testBuffer[1] := WORD_TO_BYTE(testValueCh1 AND 16#00FF); (* Младший байт *)
testBuffer[2] := WORD_TO_BYTE(SHR(testValueCh1 AND 16#FF00, 8)); (* Старший байт *)

testBuffer[3] := WORD_TO_BYTE(testValueCh2 AND 16#00FF); (* Младший байт *)
testBuffer[4] := WORD_TO_BYTE(SHR(testValueCh2 AND 16#FF00, 8)); (* Старший байт *)

SysMemCpy(ADR(TestAQ), ADR(testBuffer), 12);

Для того, чтобы было удобно работать, я написал функции, которые всю работу делают за меня. Им надо только подпихнуть ссыку на переменную канала STRING[] и длину байт:

(* Это для аналоговых входов *)
(* Здесь каждый кусочек данных одного входв занимат 12 байт
Поэтому номер канала можно вычислить, если домножать 12 на номер канала, считая с нуля
НЕ забываем о том, что наши каналы разбиты на два куска STRING[]: с 1 по 6 и с 7 по 8!
*)
TestAIModule1 := CSParseMV8A(ADR(TestAI1) + (12 * 0), 12, FALSE); (* Канал 1 *)
TestAIModule2 := CSParseMV8A(ADR(TestAI1) + (12 * 5), 12, FALSE); (* Канал 6 *)

TestAIModule3 := CSParseMV8A(ADR(TestAI2) + (12 * 1), 12, FALSE); (* Канал 8 *)

(* А тут ещё скучнее и проще: один модуль ввода параметров электросети = один кусок STRING[] *)
TestPhaseL1 := CSParseME1Ch(ADR(testMEML1), 42);
TestPhaseL2:= CSParseME1Ch(ADR(testMEML2), 42);
TestPhaseL3:= CSParseME1Ch(ADR(testMEML3), 42);

Кое-где моя логика несовершенна и немного накручена. Возможно, позже я что-то исправлю и переделаю более изящно.
Однако сейчас весь пример работает (что видно на скриншотах), и даже на отрицательных значениях Float32 парсится корректно.
Кому надо - пользуйтесь и дорабатывайте под себя!

Cs-Cs
16.07.2021, 14:35
Можно. Но проктологически ипользуя косяк КДС ))
Но поюзав syslibcom - желание парится с конфигурацией пропадает
Не, режим "Это не баг, а фича" не используем =)
Ага, я ща изучаю его на CDS v3 для ускорения опроса. Кое-что получается ужо.
На CDS 2.3 у меня проекты чаще всего простые по конфигурации - DI/DO, AI (температуры смерить).

Cs-Cs
17.07.2021, 10:14
Так могу ли я попросить тебя его тут подробно расписать? Я даже не в курсе про баг и фичу.

Cs-Cs
17.07.2021, 11:55
Зачем тогда про это всё упоминать? Знаю, да не скажу?

capzap
17.07.2021, 13:08
Ну и говнокодище в красивой упаковке. То введение в заблуждение, то масло масленное, то перечисление всего подряд, чтоб видимо если начнут докапываться, сказать что опечатался. Детский сад какой то

Cs-Cs
17.07.2021, 13:42
capzap Критикуя - предлагай ©
Что не так? Я знаю один момент - что я указатели на адреса на валидность не проверя.
Там, где МНЕ непонятно (про байты или буферы) - я писал и буду писать подробные комментарии.

А дополнительно я скажу вот что.
Когда я в некоторых случаях (SysCom) просил помощи - то 2/3 участников форума много говорили, но мало кто давал нормальные (откомментированные, с понятными названиями и назначениями переменных) примеры. Большинство давали или огрызки, или спагетти-код.
Поэтому мне сейчас стало давно плевать. Я обещал, что как сделаю свой рабочий пример, выложу его. Я - выложил. А большинство из вас - нет.

capzap
17.07.2021, 14:18
Вы так усиленно делаете упор на комментарии, так сами то их прочтите, если коммент не отражает назначение переменной это разве правильный код, он уже попахивает

Cs-Cs
17.07.2021, 19:00
capzap Что? Где? Я не понял, о чём речь.
Если кто-то потрудился посмотреть код, то пусть дотрудится до конца и укажет на ошибки или неточности.
В отличие от богов и тех, кто мнит себя ими, я не идеален.

capzap
17.07.2021, 19:59
Смотрите первый пост, яи проект не открывал

kondor3000
19.07.2021, 20:57
Критикуя - предлагай ©
Я - выложил. А большинство из вас - нет.
Как по мне, то код должен быть простым и понятным, даже для новичков. Как вариант, уже предлагал считывать все параметры МВ 8А не байтами, а массивом WORD, что для многих будет проще, так как почти все параметры и читаются в этом виде и не собирать их из байтов. Как известно все регистры занимают 96 байт, разбиваем их пополам, для удобства (не надо высчитывать номера всех регистров, а только половины). В конфигурацию добавляем два String и присваиваем им имена Str14 с 0 адреса, длиной 48 байт и Str58 с 24 адреса и тоже 48 байт.56110
А что бы уйти от ручной привязки, по команде AT %QB..., можно объявить указатель на массив WORD по 24 регистра (48 байт) и сделать это в глобальных, чтобы был доступ из любого ФБ. Ну и конечно, тут же объявим нужные нам переменные. Целочисленные без смещения точки, объявляем как INT, чтобы не потерять знак.

VAR_GLOBAL
w_1 : POINTER TO ARRAY [0..23] OF WORD; (* Указатели на массив WORD *)
w_2 : POINTER TO ARRAY [0..23] OF WORD;

w1,w2,w3,w4,w5,w6,w7,w8 : INT ; (* Целочисленное значение без смещения INT *)
d1,d2,d3,d4,d5,d6,d7,d8 : WORD; (* Смещение точки WORD *)
r1,r2,r3,r4,r5,r6,r7,r8 : REAL; (*Значения REAL *)
r_1 : REAL;
END_VAR

Далее создаём ФБ, например "Opros_MVA", в котором будет только присвоение начальных адресов массивов, ну и если понадобиться присвоение нужных нам переменных.

FUNCTION_BLOCK Opros_MVA
VAR
END_VAR
__________________________________________________ __________________________________________________ ________
w_1:=ADR(Str14); (*Начальный адрес в массиве WORD *)
w_2:=ADR(Str58);



Осталось только объявить в PLC_PRG и в его теле, наш функциональный блок (ФБ). Добавил ещё в примечании, все нужные нам регистры МВА8, для наглядности, пример вызова некоторых переменных из массивов и расчёт REAL из целочисленного значения.

PROGRAM PLC_PRG
VAR
(* Модули МВА_8А нужны регистры - 0,6,12,18,24,30,36,42 - положение десятичной точки, 1,7,13,19,25,31,37,43 - измеренное целое значение без смещения,
2,8,14,20,26,32,38,44 - статус канала, 3,9,15,21,27,33,39,45 - циклическое время, 4-5, 10-11 , 16-17, 22-23, 28-29, 34-35, 40-41, 46-47 - значение REAL *)

Opros_MVA:Opros_MVA;

END_VAR
_____________________________________________

Opros_MVA();


(* Смещение точки WORD *)
d1:=w_1^[0];

(* Целочисленное значение без смещения INT *)
w1:=w_1^[1];

(* Расчёт REAL из целочисленного значения *)
r_1:=w1/10.0;

(* Склейка 2 _ WORD для получения REAL *)
TWO_WORD_TO_REAL(wIn1:=w_1^[5] , wIn2:=w_1^[4] , rOut=>r1 );

Запускаем программу и видим такую простыню из значений в глобальных, далее каждый выберет, то что ему нужно. 56111
Ниже выложил пример проекта. Если кому то будет мало одного знака после запятой, добавил ещё ФБ для склейки REAL из двух WORD и пример его использования. Кстати таким же образом можно считать и массивы из REAL, правда WORD будут перепутаны и остальные данные потеряем. Проект написан для ПЛК 154УМ, при желании можно поменять на любой ПЛК, достаточно добавить в конфиг. UMD с вашим адресом МВА и два String.
Весь код без объявления переменных и примера вызова занял 4 строки!!! Это конечно, не такой красивый код, как у Валенка, но простой и понятный.

На форуме эта мысль проскакивает в куче тем, но никто не даёт рабочего (или понятного) примера.
petera неоднократно выкладывал примеры записи, чтения через STRING https://owen.ru/forum/showthread.php?t=22915&page=40&p=244022&viewfull=1#post244022

Sergey666
19.07.2021, 21:39
Вот вместо того чтобы освоить работу с библиотеками, ради фейковых упрощений, люди идут на реальное усложнение проекта и непрозрачную его работу. Как это объяснить я не понимаю, те, кто на LD и СFC сидят это тоже не освоят, хотя строку можно "клеить" и "переклеивать" и вырезать с помощью стандартных LEN и прочего.
Просят показать..., так тут же начинается:-"Оот ничего нипонятна, да каминтариев не хватает, та указатели на валидность не проверены(трудно что-то тупее заявить). Пробуйте сами, при этом не забывая:- "При использовании чужого кода или идеи крайне необходимо использование собственного мозга...Если мозга нет- вперед конюшни чистить...

Филоненко Владислав
21.07.2021, 08:43
Можно. Но проктологически ипользуя косяк КДС ))

---
Но поюзав syslibcom - желание парится с конфигурацией пропадает

Валенок, конфигурация для начинающих и простых проектов. Или Вы там ожидали минискаду?

Cs-Cs
21.07.2021, 10:30
kondor3000 Пасибо!
Да, я про DWORD не догадался. Сработала инерция мышления - что раз у нас массив байт, то работать будем с байтами.
А регистры же DWORD, точно! =)

Sergey666 Опять высказывания в духе "у вас изо рта щами пахнет" © Алекс Экслер.
В смысле, что в них звучит адский апломб, и унижение всех вокруг.
А вот зачем мне библиотеки, если у меня в проекте шесть модулей дискретного IO, где надо читать только маску входов или маску выходов (один элемент в конфигурации ПЛК всего), и один модуль AI? Ради одного модуля тащить библиотеку?
А если проект у меня совсем примитивный, которому библиотек не требуется ВООБЩЕ? Тогда у меня библиотека появится ради опроса модулей?
Нет уж! Мести всех под одного и унижать - это плохая стратегия. Прежде чем всех судить, надо понять людей и то, почему и для чего они так делают.

Про переклеивать строку. Вот тут я объясню, почему нельзя. Потому что конец строки для функций работы со строками типа LEN, CONCAT в CodeSys, как в СИ - определяется по первому нулевому байту. То есть "Sergey66616#00ляляляля" - конец строки будет на нулевом байте.
Если этот нулевой байт окажется в начале строки, то строковые функции увидят пустую строку, даже если там есть данные.

Sergey666
21.07.2021, 11:13
Sergey666 Опять высказывания в духе "у вас изо рта щами пахнет" © Алекс Экслер.
В смысле, что в них звучит адский апломб, и унижение всех вокруг.
Да вот ничего подобного...
"Простите, Голубчик, я не хотел вас обидеть." к/ф "Собачье сердце.



А вот зачем мне библиотеки, если у меня в проекте шесть модулей дискретного IO, где надо читать только маску входов или маску выходов (один элемент в конфигурации ПЛК всего), и один модуль AI? Ради одного модуля тащить библиотеку?
А если проект у меня совсем примитивный, которому библиотек не требуется ВООБЩЕ? Тогда у меня библиотека появится ради опроса модулей?
Нет уж! Мести всех под одного и унижать - это плохая стратегия. Прежде чем всех судить, надо понять людей и то, почему и для чего они так делают.
Да делайте что хотите. Только в чем унижение состоит? В том, что требуется использование мозга? Это сейчас унижение?


Про переклеивать строку. Вот тут я объясню, почему нельзя. Потому что конец строки для функций работы со строками типа LEN, CONCAT в CodeSys, как в СИ - определяется по первому нулевому байту. То есть "Sergey66616#00ляляляля" - конец строки будет на нулевом байте.
Если этот нулевой байт окажется в начале строки, то строковые функции увидят пустую строку, даже если там есть данные.
Да я понял свой косяк, согласен, ляпнул, не подумавши, т.к опыта мало в подобных извратах...ну да ладно, каждому свое.

kondor3000
21.07.2021, 11:53
kondor3000 Пасибо!
Да, я про DWORD не догадался. Сработала инерция мышления - что раз у нас массив байт, то работать будем с байтами.
А регистры же DWORD, точно! =)

Только один регистр это WORD, а не DWORD.

kondor3000
21.07.2021, 12:52
Вот вместо того чтобы освоить работу с библиотеками, ради фейковых упрощений, люди идут на реальное усложнение проекта и непрозрачную его работу. Как это объяснить я не понимаю, те, кто на LD и СFC сидят это тоже не освоят
Могу ответить только за себя. Начинал с CFC потому, что мне это ближе всего. Но первый же проект, написал уже с применением ST, так как требовалась разветвлённая структурная логика. И лепить её квадратиками на весь доступный лист, как некоторые, мне даже в голову не пришло). Позже начал осваивать библиотеки обмена. Три дня пытал Валенка как синхронизировать чтение и запись.
В итоге библиотеки освоил, перевёл свой проект на библиотеки, но такого же быстродействия и хорошей синхронизации так и не добился. В проекте связь СП310 и ПЛК, порядка 150 переменных, половина из них REAL, битовые маски и реальное время пересчитывается в ПЛК и предаётся в виде таймера на СП. Таймер может запнуться, пропустить секунду и т. д.
Так вот обмен через конфигурацию с применением String, работает быстрее и стабильнее. Нет даже намёка на пропуски, счёт идет плавно как обычные часы. И к чему я это всё пишу. Толковой помощи я практически не получил ни разу. Только Petera помогал, Валенок чутка помог, и то только намёками. А про примеры на форуме я вообще молчу, это что-то(((

Sergey666
21.07.2021, 13:09
Могу ответить только за себя. Начинал с CFC потому, что мне это ближе всего. Но первый же проект, написал уже с применением ST, так как требовалась разветвлённая структурная логика. И лепить её квадратиками на весь доступный лист, как некоторые, мне даже в голову не пришло). Позже начал осваивать библиотеки обмена. Три дня пытал Валенка как синхронизировать чтение и запись.
В итоге библиотеки освоил, перевёл свой проект на библиотеки, но такого же быстродействия и хорошей синхронизации так и не добился. В проекте связь СП310 и ПЛК, порядка 150 переменных, половина из них REAL, битовые маски и реальное время пересчитывается в ПЛК и предаётся в виде таймера на СП. Таймер может запнуться, пропустить секунду и т. д.
Так вот обмен через конфигурацию с применением String, работает быстрее и стабильнее. Нет даже намёка на пропуски, счёт идет плавно как обычные часы. И к чемуя это всё пишу. Толковой помощи я практически не получил ни разу. Только Petera помогал, Валенок чутка помог, и то только намёками. А про примеры на форуме я вообще молчу, это что то(((

Так примеры в описании библиотек Modbus.lib в документации на сайте!!!??? При чем форум?
И я не вижу связи между таймером в ПЛК, опросом модбас устройств и обменом с СП310, что вы собрались синхронизировать, если сам протокол Модбас подразумевает асинхронность?

kondor3000
21.07.2021, 15:22
Так примеры в описании библиотек Modbus.lib в документации на сайте!!!??? При чем форум?
И я не вижу связи между таймером в ПЛК, опросом модбас устройств и обменом с СП310, что вы собрались синхронизировать, если сам протокол Модбас подразумевает асинхронность?

Вот примеры с форума
06. Пример реализации обмена через библиотеки Modbus.Lib и OwenNet.Lib. Скачать (151 Кб)
https://owen.ru/forum/showthread.php?t=13588

Вот с сайта
10 Обмен через библиотеки Modbus и OwenNet Скачать
https://owen.ru/product/codesys_v2/example_program

Примеры одни и те же. Найдите, как говориться 10 отличий! И кстати, пример в описании тот же самый, только на чтение!!! 56146
Теперь дальше. Нужно сделать обмен через библиотеку Modbus.lib между СП310 и ПЛК. Допустим 2 Битовые маски, 10 WORD, 10 REAL. В примере есть отдельно чтение Модбас на ST и отдельно запись. Теперь их надо совместить в одном проекте. С этим я уже разобрался, но запись в панель работает не стабильно. Как это сделать, что бы не тормозила запись в панель?

capzap
21.07.2021, 15:36
Как это сделать, что бы не тормозила запись в панель?

Вы сейчас загрузили архив того что и так на сайте есть? А какой в этом смысл? Почему не создали тему чтоб Вам помогли?

kondor3000
21.07.2021, 16:19
Вы сейчас загрузили архив того что и так на сайте есть? А какой в этом смысл? Почему не создали тему чтоб Вам помогли?
Уже писал, что всё было в теме для новичков, которую удачно снесли. и восстановили только на половину. Я там три дня пытался получить не решение, а только подсказку. И так и не получил ничего, кроме пинка в нужную сторону)).
Как обычно, разобрался сам с обменом через библиотеку Modbus.lib, но у меня через конфигурацию, всё равно работает лучше. А далее, читайте выше.

capzap
21.07.2021, 17:22
но у меня через конфигурацию, всё равно работает лучше. А далее, читайте выше.

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

Cs-Cs
21.07.2021, 17:53
Валенок, про бибку ты ПРАВ во всём!
Но, чёрт побери, у меня пока специфика такая:
а) Проект на ПЛК110 - там тупо светом пощёлкать, и всё. Поэтому там конфигурация пока удобнее.
б) Проект на СПК (CodeSys v3) - вот таааам да! Там у меня всё через бибки работает, чтобы быстрее было и IO побитово удобно было разбирать.
В дальнем проекте сделать себе тулзу, в которую можно будет набивать нужные каналы, устройства, переменные и их биты - а она будет генерировать код для их опроса и разбора данных.
Пока интерфейс написал только, так... балуюсь. Это ОЧЕНЬ дальний проект. Возможно, сделаю шаблоны генерации кода, чтобы под разные либы было.
56153

Alekser91
06.08.2021, 13:24
Как по мне, то код должен быть простым и понятным, даже для новичков. Как вариант, уже предлагал считывать все параметры МВ 8А не байтами, а массивом WORD, что для многих будет проще, так как почти все параметры и читаются в этом виде и не собирать их из байтов. Как известно все регистры занимают 96 байт, разбиваем их пополам, для удобства (не надо высчитывать номера всех регистров, а только половины). В конфигурацию добавляем два String и присваиваем им имена Str14 с 0 адреса, длиной 48 байт и Str58 с 24 адреса и тоже 48 байт.56110
А что бы уйти от ручной привязки, по команде AT %QB..., можно объявить указатель на массив WORD по 24 регистра (48 байт) и сделать это в глобальных, чтобы был доступ из любого ФБ. Ну и конечно, тут же объявим нужные нам переменные. Целочисленные без смещения точки, объявляем как INT, чтобы не потерять знак.

VAR_GLOBAL
w_1 : POINTER TO ARRAY [0..23] OF WORD; (* Указатели на массив WORD *)
w_2 : POINTER TO ARRAY [0..23] OF WORD;

w1,w2,w3,w4,w5,w6,w7,w8 : INT ; (* Целочисленное значение без смещения INT *)
d1,d2,d3,d4,d5,d6,d7,d8 : WORD; (* Смещение точки WORD *)
r1,r2,r3,r4,r5,r6,r7,r8 : REAL; (*Значения REAL *)
r_1 : REAL;
END_VAR

Далее создаём ФБ, например "Opros_MVA", в котором будет только присвоение начальных адресов массивов, ну и если понадобиться присвоение нужных нам переменных.

FUNCTION_BLOCK Opros_MVA
VAR
END_VAR
__________________________________________________ __________________________________________________ ________
w_1:=ADR(Str14); (*Начальный адрес в массиве WORD *)
w_2:=ADR(Str58);



Осталось только объявить в PLC_PRG и в его теле, наш функциональный блок (ФБ). Добавил ещё в примечании, все нужные нам регистры МВА8, для наглядности, пример вызова некоторых переменных из массивов и расчёт REAL из целочисленного значения.

PROGRAM PLC_PRG
VAR
(* Модули МВА_8А нужны регистры - 0,6,12,18,24,30,36,42 - положение десятичной точки, 1,7,13,19,25,31,37,43 - измеренное целое значение без смещения,
2,8,14,20,26,32,38,44 - статус канала, 3,9,15,21,27,33,39,45 - циклическое время, 4-5, 10-11 , 16-17, 22-23, 28-29, 34-35, 40-41, 46-47 - значение REAL *)

Opros_MVA:Opros_MVA;

END_VAR
_____________________________________________

Opros_MVA();


(* Смещение точки WORD *)
d1:=w_1^[0];

(* Целочисленное значение без смещения INT *)
w1:=w_1^[1];

(* Расчёт REAL из целочисленного значения *)
r_1:=w1/10.0;

(* Склейка 2 _ WORD для получения REAL *)
TWO_WORD_TO_REAL(wIn1:=w_1^[5] , wIn2:=w_1^[4] , rOut=>r1 );

Запускаем программу и видим такую простыню из значений в глобальных, далее каждый выберет, то что ему нужно. 56111
Ниже выложил пример проекта. Если кому то будет мало одного знака после запятой, добавил ещё ФБ для склейки REAL из двух WORD и пример его использования. Кстати таким же образом можно считать и массивы из REAL, правда WORD будут перепутаны и остальные данные потеряем. Проект написан для ПЛК 154УМ, при желании можно поменять на любой ПЛК, достаточно добавить в конфиг. UMD с вашим адресом МВА и два String.
Весь код без объявления переменных и примера вызова занял 4 строки!!! Это конечно, не такой красивый код, как у Валенка, но простой и понятный.

Всем привет, я тут новенький и только познаю CDS2.3, столкнулся с проблемой медленного опроса АИшек. У меня по проекту на порту висит 24 АИшных модуля МВ-110-224-8А. Ваш вариант мне показался более простым в реализации, но пока не пойму как лучше мне сделать так, чтобы опрашивать все модули этим способом.

kondor3000
08.08.2021, 11:55
Всем привет, я тут новенький и только познаю CDS2.3, столкнулся с проблемой медленного опроса АИшек. У меня по проекту на порту висит 24 АИшных модуля МВ-110-224-8А. Ваш вариант мне показался более простым в реализации, но пока не пойму как лучше мне сделать так, чтобы опрашивать все модули этим способом.

Ну во первых, вам по любому придётся сделать 24 UMD, для каждого модуля МВ8А со своим адресом, и добавить в каждый по два String. Далее можно тупо размножить указатели и адреса.

Лучше конечно сделать общий массив Mv8 : ARRAY[1..24] OF Opros_MVA; и использовать цикл FOR..... TO, для перебора модулей. Тогда адреса модулей должны быть с одинаковым шагом, например с 16 по 39 адрес (шаг 1).
Но вам придётся подумать, как задавать начальные адреса для каждого String в цикле.
Кстати какой ПЛК используете и какие конкретно вам нужны данные от модулей, целочисленные без смещения или REAL или ещё какие то ?

Alekser91
09.08.2021, 07:49
Ну во первых, вам по любому придётся сделать 24 UMD, для каждого модуля МВ8А со своим адресом, и добавить в каждый по два String. Далее можно тупо размножить указатели и адреса.

Лучше конечно сделать общий массив Mv8 : ARRAY[1..24] OF Opros_MVA; и использовать цикл FOR..... TO, для перебора модулей. Тогда адреса модулей должны быть с одинаковым шагом, например с 16 по 39 адрес (шаг 1).
Но вам придётся подумать, как задавать начальные адреса для каждого String в цикле.
Кстати какой ПЛК используете и какие конкретно вам нужны данные от модулей, целочисленные без смещения или REAL или ещё какие то ?

24 UMD создал, стринги добавил и назначил им имена Str1_1, Str1_2 и т д. В пятницу я попробовал создать ФБ Opros_MVA1 (2,3 и т д) и далее к r1(2..8) или rOut привязать тэги датчиков, но стало понятно что так ничего не выйдет.
ПЛК110-30(М2), забираю с модулей данные с датчиков 4..20мА в формате REAL.

kondor3000
09.08.2021, 15:46
24 UMD создал, стринги добавил и назначил им имена Str1_1, Str1_2 и т д. В пятницу я попробовал создать ФБ Opros_MVA1 (2,3 и т д) и далее к r1(2..8) или rOut привязать тэги датчиков, но стало понятно что так ничего не выйдет.
ПЛК110-30(М2), забираю с модулей данные с датчиков 4..20мА в формате REAL.

Мне больше 2 модулей пока не приходилось подключать, они даже через конфигурацию нормально работают. С вашими 24 модулями идеально бы подошёл вариант Валенка.
Просите его , чтобы выложил свой вариант.

Alekser91
11.08.2021, 07:24
Мне больше 2 модулей пока не приходилось подключать, они даже через конфигурацию нормально работают. С вашими 24 модулями идеально бы подошёл вариант Валенка.
Просите его , чтобы выложил свой вариант.

Он ответил что стрингами не лучший способ опрашивать такое большое количество.
Есть ли у кого-нибудь живой пример использования библиотек? То что выложено на сайте мне кажется непонятным.

Sergey666
11.08.2021, 08:26
Он ответил что стрингами не лучший способ опрашивать такое большое количество.
Есть ли у кого-нибудь живой пример использования библиотек? То что выложено на сайте мне кажется непонятным.

Кажется непонятным что??? Вообще все, или что-то конкретно непонятно? Если что-то конкретно непонятно то создавайте тему отдельную и там непонятность предъявляйте конкретно, и вот тогдааа непонятность может быть рассосется.
А то:- Страшно, очень страшно, мы не знаем, что это такое! Если бы мы знали что это такое, но мы не знаем, что это такое...;)

kondor3000
11.08.2021, 08:53
Он ответил что стрингами не лучший способ опрашивать такое большое количество.
Есть ли у кого-нибудь живой пример использования библиотек? То что выложено на сайте мне кажется непонятным.

Вы вот 4 день писаниной занимаетесь, а я уже протестировал вариант через конфигурацию, добавил 24 UMD (адреса с 16 по 39), в каждый добавил по 8 RealInput с нужными адресами регистров. Правда у меня есть всего 2 модуля 8А, (адреса 16 и 32) их и подключил и вариант Валенка.
Конечно 2 модуля это не 24, но запросы идут на все 24 блока. И результаты поражают.
Для считывания только параметров REAL, конфигурации, в среднем требуется от 30 до 40 сек (жду пока считаются все 16 параметров моих модулей). Вариант Валенка считывает вообще всё, то есть 40*24=960 параметров за 1-2 сек.

В обоих случаях добавлены все 24 блока в конфигурацию, в первом по 8 Real, во втором по 2 String, то есть запросы отправляются всем 24 модулям. При чём у меня старый ПЛК154 и что бы разгрузить процессор, пришлось увеличить время цикла ПЛК до 15 мс. Новый ПЛК 110-30 V2, думаю справится и за 5 мс.

Sergey666
11.08.2021, 17:07
Не надо меня позорить, на 154-ом думаю уложусь в 0.6..0.7 сек на 24 модуля

Ну запрос-ответ где-то 20ms*24:=480ms, плюс паузы между запросами 10ms*24=240ms, таки да в 720ms можно уложиться.

kondor3000
11.08.2021, 17:33
Валенок, сказал как у меня получилось, загрузку проца смотрел по модулю статистики. Что ещё скрины выложить ?

Поставил цикл 1 мс, считывает моментально. Но CPU Overloaded постоянно горит. И на 12 мс тоже постоянно горит, а на 15 мс тухнет.

Проверил ещё раз на 15 мс, сделал 20 сбросов и стартов. Не всегда, но бывает задержка до 3 с на некоторых каналах, чаще всего на первом модуле, адрес 16 почему то.

medvedits
19.04.2023, 14:17
а для лучшего понимания пример со string без дополнительных модулей (чисто в PLC_prg) можете показать, в котором считываются данные с одного блока расширения МВ110.8А в формате real?
Для ПЛК110-30...

kondor3000
19.04.2023, 15:01
а для лучшего понимания пример со string без дополнительных модулей (чисто в PLC_prg) можете показать, в котором считываются данные с одного блока расширения МВ110.8А в формате real?
Для ПЛК110-30...

Вам этого мало? Там и примеры есть. Важно понять принцип работы, дальше дело техники.
petera неоднократно выкладывал примеры записи, чтения через STRING https://owen.ru/forum/showthread.php?t=22915&page=40&p=244022&viewfull=1#post244022

А на 1 странице этой темы, в конце, мой готовый пример чтения МВ110.8А, правда чтение WORD и сборка REAL уже после чтения, можно легко переделать.

Чтение WORD (1 регистр, 2 байта) отличается от чтения REAL ( 2 регистра, 4 байта), только кол-вом переменных в массиве и количеством байт.

medvedits
20.04.2023, 10:41
Вам этого мало? Там и примеры есть. Важно понять принцип работы, дальше дело техники.
petera неоднократно выкладывал примеры записи, чтения через STRING https://owen.ru/forum/showthread.php?t=22915&page=40&p=244022&viewfull=1#post244022

А на 1 странице этой темы, в конце, мой готовый пример чтения МВ110.8А, правда чтение WORD и сборка REAL уже после чтения, можно легко переделать.

Чтение WORD (1 регистр, 2 байта) отличается от чтения REAL ( 2 регистра, 4 байта), только кол-вом переменных в массиве и количеством байт.

прочёл раз 10, вроде бы пазл в голове сложился) наверное повторюсь, заранее извините.
Максимально число байт в троке 80? в мв110-8А последний регистр 47, могу я взять с нулевого 96 байт одной строкой и разбить на массив из 24 REAL,а потом прописать в переменные только те, что являются real значениями на входах?

kondor3000
20.04.2023, 10:53
прочёл раз 10, вроде бы пазл в голове сложился) наверное повторюсь, заранее извините.
Максимально число байт в троке 80? в мв110-8А последний регистр 47, могу я взять с нулевого 96 байт одной строкой и разбить на массив из 24 REAL,а потом прописать в переменные только те, что являются real значениями на входах?

Регистров 48 (с 0 по 47), разбиваете пополам для удобства, по 24 регистра (12 REAL или 48 байт), 2 стринга инпут по 0..11 REAL. При получении выбираете нужные REAL.
Фактически, это мой пример, только 2 раза 24 WORD, заменяете на 12 REAL.

Чем хорош отдельный ФБ, вы научитесь работать с блоками,
кроме того готовый отдельный блок (ФБ) вы можете через экспорт, импорт добавить в любой новый проект и 2 стринга и читать МВ110-8А

medvedits
20.04.2023, 15:16
Регистров 48 (с 0 по 47), разбиваете пополам для удобства, по 24 регистра (12 REAL или 48 байт), 2 стринга инпут по 0..11 REAL. При получении выбираете нужные REAL.
Фактически, это мой пример, только 2 раза 24 WORD, заменяете на 12 REAL.

Чем хорош отдельный ФБ, вы научитесь работать с блоками,
кроме того готовый отдельный блок (ФБ) вы можете через экспорт, импорт добавить в любой новый проект и 2 стринга и читать МВ110-8А

Спасибо,логику использования готовых ФБ и шаблонов я понял еще в ОЛ при работе с ПР,я её ценю,но более наглядно исполнение в одной программе,когда видишь всё целиком. А потом уже можно и сделать красиво.
В качестве эксперимента сделал и одним sring на 96 байт и 2 по 48, но всплыла странная проблема:
значение выхода через чтение отдельного регистра читается,а строка всегда пустая приходит.

kondor3000
20.04.2023, 15:24
Спасибо,логику использования готовых ФБ и шаблонов я понял еще в ОЛ при работе с ПР,я её ценю,но более наглядно исполнение в одной программе,когда видишь всё целиком. А потом уже можно и сделать красиво.
В качестве эксперимента сделал и одним sring на 96 байт и 2 по 48, но всплыла странная проблема:
значение выхода через чтение отдельного регистра читается,а строка всегда пустая приходит.

Значит плохо 10 раз прочитали по ссылке, читайте 11 раз))) Про магическое число 80
Или подробнее опишите в чём проблема и выложите свой проект

medvedits
20.04.2023, 17:22
Значит плохо 10 раз прочитали по ссылке, читайте 11 раз))) Про магическое число 80
Или подробнее опишите в чём проблема и выложите свой проект
всё подключено,сделано по примеру но в real, через регистр данные есть,через строку нули и подключение падает через минуту.проект приложил67457

kondor3000
20.04.2023, 17:45
всё подключено,сделано по примеру но в real, через регистр данные есть,через строку нули и подключение падает через минуту.проект приложил67457

Во первых, зачем вы сделали 2 UMD ( Универсал модбас девайс) для одного модуля 8А ?
Во вторых стринг вы читаете функцией 0х70, а во всех примерах функция 0х03. Ну и в третьих, часть полученных REAL будут неадекватные, выберите нужные.
Конкретно у вас в программе MV8A_1 [3] будет неадекватный.

Да на скрине у вас ещё Старт на нажат.
Ну и напоследок, все модули в программе могут спокойно работать на скорости 115200, зачем вам скорость 9600 ?

Филоненко Владислав
21.04.2023, 10:16
70/71-е функции - специфичные функции для особой периферии, которая в свободной продаже не встречается и использовать их не надо

medvedits
25.04.2023, 11:55
Во первых, зачем вы сделали 2 UMD ( Универсал модбас девайс) для одного модуля 8А ?
Во вторых стринг вы читаете функцией 0х70, а во всех примерах функция 0х03. Ну и в третьих, часть полученных REAL будут неадекватные, выберите нужные.
Конкретно у вас в программе MV8A_1 [3] будет неадекватный.

Да на скрине у вас ещё Старт на нажат.
Ну и напоследок, все модули в программе могут спокойно работать на скорости 115200, зачем вам скорость 9600 ?

1)Чтобы проверять что через конфигурацию данные получаются, а строкой нет (т.е. просто для проверки, это тестовый проект)
2)Было не очевидно что байты нужно читать функцией чтения регистров, но да, так данные появились,спасибо
3)В карте регистров 8А значение первого аналогового входа в формате обозначено в регистрах 4 и 5 начиная с 0,должно попадать во второй,но там отображается число в формате е в степени
4)Скорость маленькая потому что приборы будут разнесены по двум щитам на расстояние около 20 метров или более

kondor3000
25.04.2023, 12:29
1)Чтобы проверять что через конфигурацию данные получаются, а строкой нет (т.е. просто для проверки, это тестовый проект)
2)Было не очевидно что байты нужно читать функцией чтения регистров, но да, так данные появились,спасибо
3)В карте регистров 8А значение первого аналогового входа в формате обозначено в регистрах 4 и 5 начиная с 0,должно попадать во второй,но там отображается число в формате е в степени
4)Скорость маленькая потому что приборы будут разнесены по двум щитам на расстояние около 20 метров или более

Если переменная REAL отображается не правильно, значит в ней переставлены регистры (байты).
Это часто бывает при передаче Float по модбас.
В моём примере по ссылке (уже давал), есть ФБ перестановки регистров. Вот его и примените, чуть переделав код. 67529
Вход REAL там закомментирован, но он вам и нужен, а 2 входа WORD, наоборот закомментируйте.
На скрине 4 возможных варианта перестановки регистров (байт) и работа блока Swap_WORD ниже.

Емельянов Кирилл
27.04.2023, 07:05
зачем вам скорость 9600?

20 метров
Ну вы даёте))

medvedits
28.04.2023, 14:54
Ну вы даёте))
Когда на производстве уже есть рядом 2 СВЧ по 100+ магнетронов каждая, а руководство меняет планы расположения щитов/оборудования чуть ли не по 2 раза в день это просто предосторожность)