PDA

Просмотр полной версии : Универсальный диспетчер для Modbus.lib



Спорягин Кирилл
05.09.2016, 11:48
Добрый день, уважаемые коллеги!

Для тех кого по каким-либо причинам не устраивает штатный конфигуратор компания ОВЕН предлагает библиотеку Modbus.lib для организации опроса по одноименному протоколу. Помимо самой библиотеки в разделе "Примеры программ и полезности" (http://www.owen.ru/forum/forumdisplay.php?f=49) доступно много примеров работы с данной библиотекой, как с оборудованием ОВЕН, так и с оборудованием сторонних производителей. Вместе с тем (на мой взгляд!) все предложенные примеры обладают одним общим недостатком - они показывают как опросить одно (или несколько) устройство. Поэтому их организация (примеров) "в лоб" выглядит естественной. Под организацией "в лоб" я понимаю, то что процесс открытия порта, опрос и запись регистров выполнены в одном программном блоке (как правило в PLC_PRG). Попытка использовать данные примеры "как есть" для большого числа опрашиваемых модулей, приведет к разрастанию листинга. Что неудобно.

Предлагаю вашему вниманию надстройку над библиотекой Modbus.lib - свою собственную библиотеку GCModbus.lib. В данной библиотеке каждый модуль сети имеет отдельную сущность, а диспетчеризацией доступа к сети (порту) занимается универсальный диспетчер одномастерной сети.

В варианте библиотеки, который я выкладываю на форуме, реализованы следующие модули ОВЕН:
1. МВ110-32ДН;
2. МВ110-8А;
3. МВ110-8АС;
4. МУ110-32Р;
5. Индикатор СМИ2.

Внимание! Данные модули можно использовать как готовые ФБ, они полностью работоспособны и используются в реальных проектах. Вместе с тем, я хочу подчеркнуть, что основная цель размещения библиотеки - это попытка поделиться опытом. И не желательно использовать библиотеку не разобравшись в деталях реализации (код библиотеки открыт).

Библиотека обладает рядом достоинств:
1. Программирование модуля для нового устройства сети максимально унифицировано;
2. Диспетчер уметь работать с любым модулем сети RS-485;
3. Модули имеют настраиваемый период опроса;
4. Неисправные модули автоматически исключаются из опроса;
5. Отремонтированный модуль автоматически включается в опрос;
6. Предусмотрена возможность повторных попыток опроса, в случае неудачного первичного опроса;
7. Предусмотрена диагностика отсутствия опроса модуля (модуль не получает доступа к сети в течении заданного времени);
8. Предусмотрена возможность работы до 247 модулей одновременно (максимальное количество узлов сети Modbus);
9. В модули встроена статистика времени опроса и времени между опросами.

Библиотека выкладывается в виде проекта (расширение *.pro).
Ранее библиотека была размещена в разделе "Примеры программ и полезности (http://www.owen.ru/forum/showthread.php?t=13585)" (спасибо Николаеву Андрею), но там, мне кажется, "ее никто не брал и не берет".

Подробное описание библиотеки дано в документе "Библиотека GCModbus.lib для контроллеров ОВЕН.pdf".

Постараюсь ответить на вопросы, если они появятся, также буду благодарен за критику (не путать с критиканством!).

Newcomer
05.09.2016, 15:41
Спасибо, добрый человек.

Yegor
05.09.2016, 22:07
Pooling/polling? =)

Когда я городил свой огород вокруг modbus.lib в одном проекте, то делал это прежде всего чтобы вообще уйти от бесполезного (зачастую) понятия "период опроса", к которому принуждает конфигуратор. Как по мне, гораздо проще опрашивать модули сразу один за другим. И если одни модули надо опрашивать чаще других, то достаточно ставить другие через раз [через два, через три...]. В итоге получается абсолютно равномерный опрос, пускай и медленнее в среднем. Если ваша библиотека эту схему не реализует (неясно из слишком подробного описания), то рекомендую. То есть вместо периода модулям назначается приоритет, и по этому приоритету формируется последовательность опроса; опрос выполняется без пауз.

Спорягин Кирилл
06.09.2016, 12:28
Pooling/polling? =)

Верно подметили.



Когда я городил свой огород вокруг modbus.lib в одном проекте, то делал это прежде всего чтобы вообще уйти от бесполезного (зачастую) понятия "период опроса", к которому принуждает конфигуратор. Как по мне, гораздо проще опрашивать модули сразу один за другим. И если одни модули надо опрашивать чаще других, то достаточно ставить другие через раз [через два, через три...]. В итоге получается абсолютно равномерный опрос, пускай и медленнее в среднем. Если ваша библиотека эту схему не реализует (неясно из слишком подробного описания), то рекомендую. То есть вместо периода модулям назначается приоритет, и по этому приоритету формируется последовательность опроса; опрос выполняется без пауз.
Основная причина ухода от конфигуратора для меня была в двух причинах:
1. Организовать групповые запросы для увеличения скорости опроса;
2. Сделать проект кроссплатформенным.
Понятие период опроса мне кажется естественным и понятным.

Спорягин Кирилл
06.09.2016, 12:29
)) Yegor, видимо период опроса тут имеет смысловое наполнение "по возможности, но не ранее чем ...."
Я вот типа того придерживаюсь ))

Верно. Фактически опрос совершается именно так "по возможности, но не ранее чем".

Yegor
06.09.2016, 17:34
Понятие период опроса мне кажется естественным и понятным.Естественное и понятное оно только в случае с одним устройством. Дальше оно перестаёт быть, собственно, "периодом".

energvk
06.09.2016, 17:54
Ну почему? Если например модуль МВ8А опрашивать чаще чем раз 3-5 секунд нет смысла,то период опроса в данном случае актуален. Или нет?

Yegor
06.09.2016, 19:05
Ну почему? Если например модуль МВ8А опрашивать чаще чем раз 3-5 секунд нет смысла,то период опроса в данном случае актуален. Или нет?http://www.owen.ru/forum/showthread.php?t=21940&p=219544&viewfull=1#post219544

mastrik
15.09.2016, 10:57
Кирилл, спасибо за то что поделились трудами - это как бальзам на душу!
А модули аналогового вывода вы не используете в своих задачах?

Спорягин Кирилл
15.09.2016, 12:08
Кирилл, спасибо за то что поделились трудами - это как бальзам на душу!
А модули аналогового вывода вы не используете в своих задачах?

Спасибо за теплые слова.
Пока не было проектов с модулями АО. Но трудностей встроить их в библиотеку быть не должно.

mastrik
15.09.2016, 13:34
Модуль простой, 6 последовательных регистров со значениями интовыми и столько же "безопасных" значений, которые ставятся, если превышен сетевой таймаут, только их каждый цикл обновлять нельзя, там память имеет ресурс.
Прочитал вашу документацию и залип только в одном месте - правильно сформировать буфер на отправку значений.
Неужели будет просто:
FOR i:=1 TO 6 DO
pData := ADR(Mdl.AO[i]); (*mdl с новым типом для этого модуля, у которого есть массив из 6 интов под аналоговый выход АО*)
Mdl.pDisp^.SendBuffer[i-1] := pData^;
END_FOR;
?

Спорягин Кирилл
15.09.2016, 13:47
Модуль простой, 6 последовательных регистров со значениями интовыми и столько же "безопасных" значений, которые ставятся, если превышен сетевой таймаут, только их каждый цикл обновлять нельзя, там память имеет ресурс.

Такие вещи, как безопасные значения, обычно конфигурируются отдельно.
Но если Вы хотите в своем коде это сделать, то лучше на первом скане записать безопасные значения, а далее работать только с текущими.




Прочитал вашу документацию и залип только в одном месте - правильно сформировать буфер на отправку значений.
Неужели будет просто:
FOR i:=1 TO 6 DO
pData := ADR(Mdl.AO[i]); (*mdl с новым типом для этого модуля, у которого есть массив из 6 интов под аналоговый выход АО*)
Mdl.pDisp^.SendBuffer[i-1] := pData^;
END_FOR;
?

Еще нужно добавить:
pData := pData + 1;
Mdl.pDisp^.SendBuffer[i] := pData^;

Иначе получается, что Вы только первый байт от INT кладете в буфер.

mastrik
15.09.2016, 15:03
Такие вещи, как безопасные значения, обычно конфигурируются отдельно.
Но если Вы хотите в своем коде это сделать, то лучше на первом скане записать безопасные значения, а далее работать только с текущими.

Так и запланировал сразу.




Еще нужно добавить:
pData := pData + 1;
Mdl.pDisp^.SendBuffer[i] := pData^;

Иначе получается, что Вы только первый байт от INT кладете в буфер.

Тогда с правильными индексами:
FOR i:=1 TO 6 DO
pData := ADR(Mdl.ao[i]);
Mdl.pDisp^.SendBuffer[(i-1)*2] := pData^;
pData := pData + 1;
Mdl.pDisp^.SendBuffer[(i-1)*2+1] := pData^;
END_FOR;

Проверю на неделе как работает и буду дописывать для 16р и для 220.3м (у которого вагон и маленькая тележка измеряемых параметров), потом могу выложить сюда, если интересно

Может сразу подскажете longи и floatы справа налево будут писаться? 4-й байт первым и 1-й байт последним в буфер?

Спорягин Кирилл
15.09.2016, 15:30
Проверю на неделе как работает и буду дописывать для 16р и для 220.3м (у которого вагон и маленькая тележка измеряемых параметров), потом могу выложить сюда, если интересно


У меня реализовано модулей больше, чем я выложил. Тут важен сам подход к организации опроса.



Может сразу подскажете longи и floatы справа налево будут писаться? 4-й байт первым и 1-й байт последним в буфер?

Для real должно быть: 3, 2, 1, 0.

Vitorgan
20.10.2016, 17:56
Уважаемый Кирилл, очень хочется воспользоваться вашей библиотекой.
Возникло несколько вопросов, во первых я должен пересохранить .pro как .lib, интересует что делать с функцией Initialization и программой PLC_PRG (в библиотеке)

Как я понимаю я должен в своем проекте создать программу на подобие вашей PLC_PRG, и в ней прописать
27146

Например хочу опросить 2 модуля МВ-110 8А.

И создаю global_Variables
27147

С номером порта Rs-485 понять тоже ничего не моу, какой ComPort я должен выставить, чтобы открывать Rs-485 (на ПЛК 160)

Вообще правильной ли я иду дорогой? заранее благодарен за любую подсказку

Спорягин Кирилл
20.10.2016, 18:19
Возникло несколько вопросов, во первых я должен пересохранить .pro как .lib, интересует что делать с функцией Initialization и программой PLC_PRG (в библиотеке)

Вовсе не обязательно пересохрянять как библиотеку. Можно использовать блоки как проект. Например, взять прикрепленный, переименовать его в соответствии с вашими требованиями, убрать (или не убирать) неиспользуемые блоки и добавить свою логику.
Так, например, я свою библиотеку использую как проект, т.е. она не вынесена у меня в отдельную библиотеку, а блоки просто находятся в проекте. Набор данных блоков по смыслу - библиотека.




Как я понимаю я должен в своем проекте создать программу на подобие вашей PLC_PRG, и в ней прописать
27146

Например хочу опросить 2 модуля МВ-110 8А.

И создаю global_Variables

В целом все верно делаете.



С номером порта Rs-485 понять тоже ничего не моу, какой ComPort я должен выставить, чтобы открывать Rs-485 (на ПЛК 160)


Это нужно посмотреть в паспорте ПЛК. Данной моделью никогда не пользовался. Привожу номера портов для ПЛК110 и ПЛК100:
- ПЛК110: 0 - RS485-1; 1 - RS232; 2 - RS485-2; 3 - не исп.; 4 - RS232-Debug
- ПЛК100, 150, 154: 0 - RS485; 1 - RS232; 2 - не исп.; 3 - не исп.; 4 - RS232-Debug.

Но подчеркиваю, что настоятельно рекомендуется разобраться с деталями реализации.

Vitorgan
20.10.2016, 18:33
Да посмотрел, и почитал пдф файл, понял что ком порт ставлю 0, и не обращаю внимания на красную надпись, но у меня ready постоянно в Invalid 16#FE

27150

Спорягин Кирилл
20.10.2016, 19:13
Ready - булевая переменная. Очень странно, что она у Вас принимает значение 16#FE. Похоже, что у Вас "съехали" указатели.
Но без проекта трудно, что-то конкретное сказать.

Vitorgan
20.10.2016, 20:09
Вот ваша библиотека, с некоторыми моими добавками, Все та же ошибка. Посмотрите пожалуйста

Спорягин Кирилл
21.10.2016, 10:17
Вот ваша библиотека, с некоторыми моими добавками, Все та же ошибка. Посмотрите пожалуйста

Посмотрел. Исправьте при инициализации диспетчера 11520 на 115200 и все заработает.

Спорягин Кирилл
21.10.2016, 10:23
Единственное, что мне не понятно, это то что в проекте Вы пытаетесь занять порт RS485-1 как для мастера, так и для слейва.
Это осознано или ошибка?

Спорягин Кирилл
21.10.2016, 10:34
И еще. Вы сеть инициализируете дважды.
Первый раз после if FirstScan пишите Disp0.pModule[1] := adr();
А затем вызываете функцию Initialization(). Где делаете ровно тоже самое.
Это не приводит к ошибке, но лучше оставить инициализацию в одном месте.

Vitorgan
21.10.2016, 10:53
Ох спасибо вам большое! А можно про порт поподробнее?

В Плк.прг сделал так

IF FirstScan THEN
Initialization();

FirstScan := FALSE;
END_IF;

Спорягин Кирилл
21.10.2016, 11:08
А можно про порт поподробнее? END_IF;
При инициализации сети мастера (DispatcherModbus), вы задаете ComPort=0 (т.е. как я понимаю RS485-1).
И при конфигурации слейва (в конфигураторе) у вас используется RS485-1.
Т.е. вы на один порт пытаетесь повесить и опрос мастером сети модулей МВ110-8А и через этот же порт сделать контроллер слейвом для панели и скада.
Так у вас ничего не получится. Будут ошибки в обоих сетях.

Перенесите опрос панели на порт RS232.



В Плк.прг сделал так

IF FirstScan THEN
Initialization();

FirstScan := FALSE;
END_IF;

Да, лучше так.

Vitorgan
21.10.2016, 11:37
Про порты понял, не использую их, просто когда TCP не было висели) поудалял там где не нужно. Спасибо за то, что указали на ошибки)

Кирилл, подскажите пожалуйста, сейчас добавил еще 2 8АС, у 8А ошибок modbusErrCnt =0, а у 8АС набигает за 10 минут штук под 200-300 на одном, а на другом около 100, Что лучше уменьшать скорость на всех модулях, или же играться с PollingTime и Timeout?

И еще вопрос, pollingStatistic - как я понимаю статистика времени опроса, а readingStatistic -статистика времени чтения?

Спорягин Кирилл
21.10.2016, 11:59
Кирилл, подскажите пожалуйста, сейчас добавил еще 2 8АС, у 8А ошибок modbusErrCnt =0, а у 8АС набигает за 10 минут штук под 200-300 на одном, а на другом около 100, Что лучше уменьшать скорость на всех модулях, или же играться с PollingTime и Timeout?

Попробуйте увеличить FramingTime у диспетчера.
Но в целом, как я понимаю некоторый процент ошибок в сети RS-485 - это норма. Точнее это вопрос, которым я еще собираюсь заняться - написать в службу технической поддержки. Но я тоже наблюдаю, что у меня периодически проскакивают ошибки сети для разных модулей.



И еще вопрос, pollingStatistic - как я понимаю статистика времени опроса, а readingStatistic -статистика времени чтения?

PollingStatistic - это статистика между опросами модуля. В идеале PollingStatistic.Middle должно быть равно PollingTime, т.е. как только истекло время периода опроса, так сразу модуль получил доступ к сети.
ReadingStatistic - это статистика времени, которое модуль тратит на чтение (опрос). Другими словами - это то время, которое модуль занимает порт.

Спорягин Кирилл
21.10.2016, 12:16
Да и еще для увеличения скорости опроса (я так понимаю, что это главная задача), уменьшайте Timeout. Я проводил эксперименты, и могу сказать, что если модуль не ответил за 50мс, то он не ответит уже и ждать дольше нет смысла.
Я обычно выставляю Timeout = 50мс, MaxAttempts (максимальное количество попыток опроса одного модуля) = 2 или 3.

Vitorgan
21.10.2016, 13:21
Понял Вас, спасибо учту, сейчас добавил МУ 110 16Р -2 шт, работают всего 6 модулей) занимаемся 8ДФ, с ними сложней, му по примеру важего 32Р были сделаны. Спасибо за данный диспетчер, даже сейчас уже видим что скорость по сравнению с Конфигуратор, небо и земля.

Vitorgan
21.10.2016, 14:00
Кирилл, а подскажите пожалуйста, каким образом лучше организовать показ ошибок, на подобии ласт еррор, использовать base.Error?

Спорягин Кирилл
21.10.2016, 19:09
Кирилл, а подскажите пожалуйста, каким образом лучше организовать показ ошибок, на подобии ласт еррор, использовать base.Error?

Да. В переменной Base.Error лежит код ошибки.

spectrum48k
22.10.2016, 21:33
Основная причина ухода от конфигуратора -- он глюченный и не проверяет ответы по принадлежности именно к адресу опрошенного модуля. разработчики так и не скинули щедро скрин, опровергающий эту гипотезу, потдтвержденную практическими экспериментами с плк серии 150

Vitorgan
22.10.2016, 22:38
Отпишусь.
После полного вникания в работу modbus.lib и данного диспетчера, удалось опрашивать все нужные мне модули, их 8 шт. 8а, 8ас, 8дф, 16р - 2 шт.
Далее в течении 1 часа, были настроены циклы, таймауты, pollingStatistic.Middle был максимально приближен к PollingTime.

В данный момент полностью удовлетворены работой диспетчера, пока полностью выполняет возложенные на него функции, надеюсь все так и останется.
Спорягину Кирилл огромное спасибо за своевременную помощь, и вообще за сам Диспетчер)
За 3 часа работы ни одной ошибки.

Спорягин Кирилл
24.10.2016, 12:52
Отпишусь.
После полного вникания в работу modbus.lib и данного диспетчера, удалось опрашивать все нужные мне модули, их 8 шт. 8а, 8ас, 8дф, 16р - 2 шт.
Далее в течении 1 часа, были настроены циклы, таймауты, pollingStatistic.Middle был максимально приближен к PollingTime.

В данный момент полностью удовлетворены работой диспетчера, пока полностью выполняет возложенные на него функции, надеюсь все так и останется.
Спорягину Кирилл огромное спасибо за своевременную помощь, и вообще за сам Диспетчер)
За 3 часа работы ни одной ошибки.

Рад помочь...

Vitrogan, еще хотел обратить ваше внимание на вот этот пост (http://www.owen.ru/forum/showthread.php?t=21940&page=14&p=219033&viewfull=1#post219033). В части 2 особенно.
Важно при использовании модулей вывода.
Вы переделывали модуль МУ110-32Р на МУ110-16Р. Убедитесь, что вы заново формируете буфер в случае ошибки при первичном опросе и MaxAttempts>1. В противном случае изредка (когда проходит ошибка) на модуле вывода вы можете выставлять некий произвольный набор выходов, чего явно не ждете.
В модуле МУ110-32Р повторное формирование буфера реализовано с помощью возврата на шаг 1 при ошибке (см. код ниже).



IF tmpWriteError = 0 THEN
Mdl.WriteStep := CompleteWriteStep;
ELSE
fcModuleAddAttempt(MdlBase := Mdl.Base);
IF Mdl.Base.CurrentAttempt > Mdl.Base.MaxAttempts THEN
Mdl.WriteStep := CompleteWriteStep;
ELSE
Mdl.WriteStep := 1; (* необходимо заново сформировать буфер *)
END_IF;
END_IF;


И два слова в защиту штатного конфигуратора.
У меня есть проект, где работает штатный конфигуратор и опрашивает 12 модулей. Опрос проходит весьма шустро.
В случае использования штатного конфигуратора при опросе модулей с большим объемом данных обмена (МВ110-8А, например) желательно использовать прием со string переменными (см. тут (http://www.owen.ru/forum/showthread.php?t=21799&highlight=string)).
Хотя, конечно, когда разберешься с modbus.lib, уже проще работать со своим кодом.

Vitorgan
25.10.2016, 13:31
Кирилл, проверили, все так же организовали, через возврат на 1 шаг.
По-поводу 1 пункта в теме "Конфигуратор Vs modbus.lib":
Эх, Попался бы тот пост нам на глаза пораньше). Как только пустились- ошибок нет, все работает, но у аналоговых чтение происходит 200-230мс, а у дискретных 60-70мс, зная на что они способны, начали разбираться, оказалось что цикл программы "опроса модулей" (у вас в примере он PLC.PRG) в задаче больше 15 мс, начали уменьшать до 5мс, аналоговые модули АС чтение 40-60 мс, дискретные 16-20мс. Вот вопрос, можно ли еще уменьшать цикл, если он в статистики 1,5 мс работает, если например FramingTime 5 мс. До минимума цикл задачи опустить, поставить 2 мс?

Спорягин Кирилл
25.10.2016, 16:14
Кирилл, проверили, все так же организовали, через возврат на 1 шаг.
По-поводу 1 пункта в теме "Конфигуратор Vs modbus.lib":
Эх, Попался бы тот пост нам на глаза пораньше). Как только пустились- ошибок нет, все работает, но у аналоговых чтение происходит 200-230мс, а у дискретных 60-70мс, зная на что они способны, начали разбираться, оказалось что цикл программы "опроса модулей" (у вас в примере он PLC.PRG) в задаче больше 15 мс, начали уменьшать до 5мс, аналоговые модули АС чтение 40-60 мс, дискретные 16-20мс. Вот вопрос, можно ли еще уменьшать цикл, если он в статистики 1,5 мс работает, если например FramingTime 5 мс. До минимума цикл задачи опустить, поставить 2 мс?

FramingTime - это пауза, которую диспетчер держит после опроса очередного модуля, прежде чем дать разрешение на опрос следующему модулю. Часто данная пауза необходима, чтобы модули успевали разбирать сетевые посылки.
Можно уменьшить цикл выполнения программы опроса, но, возможно, тогда придется увеличить FramingTime, чтобы "медленные" модули успевали обрабатывать сетевые посылки.
В целом, 40-60 мс на аналоговые и 16-20 мс на дискретные модули нормальный результат.

Vitorgan
25.10.2016, 18:36
Понял Вас, лучший враг хорошего)

Спорягин Кирилл
08.11.2016, 12:43
Набрал статистику опроса модулей ОВЕН. Посмотреть можно тут (http://www.owen.ru/forum/showthread.php?t=25519&p=226486#post226486).

westwind
07.03.2017, 11:08
Извиняюсь за глупый вопрос, можно ли в двух словах разницу Вашей библиотеки и ModulsOwenLib?
... а, не сообразил сразу, что она для v2.

Спорягин Кирилл
09.03.2017, 11:04
Извиняюсь за глупый вопрос, можно ли в двух словах разницу Вашей библиотеки и ModulsOwenLib?
... а, не сообразил сразу, что она для v2.

Добрый день, westwind.
Да, действительно, моя библиотека реализована для CDS v2, а библиотека ModulsOwenLib для CDS v3. И это их отличает.
Но это не главное. Библиотека ModulsOwenLib (подобно библиотеке Modbus.lib для CDS v2) дает инструмент для опроса отдельных модулей, но не решает вопроса диспетчеризации опроса.
В представленной библиотеке ключевое место занимает именно диспетчер.

ancintrus
30.05.2017, 14:32
Добрый день Кирилл.
Пытаюсь собрать модуль МВ110-16D из 32D. Опрос модуля идет, но висит ошибка 2. Подскажите пожалуйста в чем проблема.

Спорягин Кирилл
31.05.2017, 12:10
Добрый день Кирилл.
Пытаюсь собрать модуль МВ110-16D из 32D. Опрос модуля идет, но висит ошибка 2. Подскажите пожалуйста в чем проблема.

Добрый день.
Посмотрел бегло Ваш проект.
Пока не понятно следующее в модуле MB110-16D:
1. Режим опроса - MB_ASCII. Это сознательно или не точность.
2. Опрашиваете 2 регистра, хотя для размещения 16 бит достаточно 1-го.

ancintrus
31.05.2017, 12:51
От пинка Валенка в модуле MB110-16D я все-таки разобрался. (Набираюсь опыта еще с библиотечным опросом).


Режим опроса - MB_ASCII. Это сознательно или не точность.
Намеренно, хочется еще прикрутить ТРМы, а они виснут от RTU опроса.
Вообще раньше пользовался стандартным конфигуратором. А сейчас предстоит линию обвешать 26 устройствами (модули и трм), поэтому и пытаюсь перейти на библиотеку.
Ваш проект выглядит интересным вот и на нем и решил остановиться.
Спасибо за ответ.

Спорягин Кирилл
31.05.2017, 14:52
Намеренно, хочется еще прикрутить ТРМы, а они виснут от RTU опроса.


На сколько мне известно ТРМы поддерживают только протокол ОВЕН. Его придется самостоятельно реализовывать. Диспетчер при этом можно использовать из библиотеки.

mastrik
19.09.2017, 21:04
Кирилл, добрый вечер! Уже год назад использовал ваш диспетчер на одном из проектов, всё до сих пор автономно работает 24/7. Сейчас делаю проект для своего дома, а доступа к наработкам и прошлым проектам нет, потому что поменял место работы. Можете поделиться модулями, которые вы уже написали, кроме тех, что в библиотеке?

Спорягин Кирилл
22.09.2017, 11:39
mastrik, добрый день.

Я уже писал, что основная цель выкладывания библиотеки - это желание поделиться опытом.
Важен сам подход к организации опроса.
Поэтому чтобы не "захламлять" различными модулями сути я и не выкладываю все что есть. Тем более, что в более сложных модулях, например, частотниках, мне может понадобиться (для моих задач) читать одни регистры, другим совсем другие регистры.

mastrik
27.09.2017, 20:37
mastrik, добрый день.

Я уже писал, что основная цель выкладывания библиотеки - это желание поделиться опытом.
Важен сам подход к организации опроса.
Поэтому чтобы не "захламлять" различными модулями сути я и не выкладываю все что есть. Тем более, что в более сложных модулях, например, частотниках, мне может понадобиться (для моих задач) читать одни регистры, другим совсем другие регистры.

Да, я помню это. И в прошлый раз ничего не просил у вас, тем более, что вы подсказали в каком направлении работать, чтобы формировать собственные запросы на чтение и запись. А теперь я в больнице и прохожу уже 5-й курс химиотерапии, поэтому голова варит плохо, да и железо из дома сюда взять нельзя, а на симуляторе отлаживать работу по модбасу невозможно, хотел пока есть время почитать код ваших модулей, чтобы минимизировать свои ошибки.

fantozes
19.04.2018, 12:28
как с помощью вашей библиотеки получить данные с плк мастер --> на плк слейв на адрес регистра 256, 512, 514, 768? word

Спорягин Кирилл
23.04.2018, 23:23
как с помощью вашей библиотеки получить данные с плк мастер --> на плк слейв на адрес регистра 256, 512, 514, 768? word

Универсальный диспетчер занимается вопросом очередности доступа к порту. Для получения данных с мастера на слейв, необходимо понимать какие функции поддерживает то и другое устройство и использовать необходимый ФБ из библиотеки Modbus.lib.

capzap
24.04.2018, 06:49
Универсальный диспетчер занимается вопросом очередности доступа к порту. Для получения данных с мастера на слейв, необходимо понимать какие функции поддерживает то и другое устройство и использовать необходимый ФБ из библиотеки Modbus.lib.

введу в курс дела (http://www.owen.ru/forum/showthread.php?t=28632&p=275807&viewfull=1#post275807), ему нужны решения и только конкретика, поэтому в Вашем ответе нет ни чего, чтобы ему помогло. Предлагаю ответить на главный вопрос, программный слейв возможен?

fantozes
26.04.2018, 05:21
Вообще - да.

расскажите пожалуйста как?

Alexlyu
27.02.2019, 15:14
К моему великому сожалению эта штуковина не заработала с библиотекой OwenModbusSlave.
Отдельно обе работают.
Попробовал слэйв для панели сделать через бибку, тк в ранее несколько раз перебивал более 500 переменных в конфигураторе и почти истерику получил.
В этот раз решил библиотеку взять. Так приятно работать стало.
-ПЛК110М2
-На панель подаю через порт RS232.
Опрос веду или с порта "0" или с "2" (без разницы).
-При использовании конфигуратора мастера и бибки слэйв всё работает.
-Слэйв и Мастер Библиотечные вместе не пашут, хотя в порты разные стучатся.
Сейчас проблема не важна, тк надо 6 регистров читать.

Но весной, при расширении пр-ва будут переделки с кучей слейвов и с панелями.
Очень хочется всё сделать бибками, чтоб упростить переделки и заложить нормальную возможность модернизации.
Плюс будет сеть прокинута, и всё на скаду и в облако буду затаскивать.

Может посоветуете чего? (*вникать в дебри сам не успеваю, тк мне и подбирать, и чертить, и собирать, и программировать, и налаживать, и обслуживать приходится.*)

Спорягин Кирилл
27.02.2019, 16:08
К сожалению, не знаком с библиотекой OwenModbusSlave, поэтому тяжело сказать почему они вместе не заработали.

В целом нужно понимать, что моя библиотека решает один простой вопрос - очередность доступа к последовательному порту.

Sergeba
02.12.2019, 01:37
Почитал документацию, посмотрел пример, но не понял, возможно ли использовать диспетчер для управления модулями используя два слота сети RS485-1 и RS485-2?

Alexlyu
03.12.2019, 11:48
утром как раз проверял эту возможность.
Объявил два диспетчера с разными портами и скоростью.
К каждому в PLC_PRG привязал нужные модули.
Работают.
Мучения были только в получении МУ-16Р из МУ-32Р.
теперь нужно их подружить с OwenModbusSlave и я буду счастлив.

Спорягин Кирилл
03.12.2019, 13:18
Почитал документацию, посмотрел пример, но не понял, возможно ли использовать диспетчер для управления модулями используя два слота сети RS485-1 и RS485-2?

Конечно, можно.
Как правильно сказано выше, просто объявите 2 диспетчера. Для каждого порта свой.

Спорягин Кирилл
03.12.2019, 13:18
Почитал документацию, посмотрел пример, но не понял, возможно ли использовать диспетчер для управления модулями используя два слота сети RS485-1 и RS485-2?

Случайно продублировался пост.

Alexlyu
06.12.2019, 10:40
И так, родил я в муках модуль fcMB110_4TD (на последнем этапе сильно помогла тема (https://owen.ru/forum/showthread.php?t=15752&page=4&highlight=modbus+real+float) ).
Буду рад предложениям по более удобному, чем битовая маска (2#0001_1111) заданию считываемых входов. На панели то это будет красиво(если надо). Но прога должна быть понятна любому, кто после меня туда влезет.
На fcMB110_8A тоже добавлю выбор считываемых входов, мне кажется это полезным.
Так же мне не нравится использовать WORD для получения диагностической информации. не информативно биты через точку вызывать. Конечно можно так: ErrAI2:= Diag.1, но опять лишние сущности. Фу! У меня и так все проекты в этих призраках, не могу никак избавиться от них.
Идеалом было бы на одно значение использовать одну ячейку памяти и для приёма, и для обработки, и для передачи на панель, и для передачи на скаду. Но пока не разобрался с жонглированием указателями, а "ADR" не даёт нужного, если его в структуру пихать.
На очереди связь с частотником (передача/приём) fcEI_7012, fcE4_8400, fcE3_8100, и модуль ввода/вывода fcMK_8DN4R. Если у кого-то есть наработки, буду рад с ними ознакомиться.
Заметил странное поведение ModBusSlave, заливаю проект onlinechange, стоп, сброс, старт - и функция выдаёт ошибку настроек порта.
Создаю загрузочный проект, перезагружаю - всё работает. В чём может быть проблема?
Тестовый проект во вложении.

Sergeba
07.12.2019, 02:23
Конечно, можно.


Почему-то не меняется время опроса ставлю 500мс и 1000мс, всё равно опрос идёт с частотой 100мс (на глаз).
Второе, что не понял, для чего в опросе модулей используются шаги (step). Ведь всё равно опрос прописан так, что команды опроса следуют друг за другом...

Пробую опросить модуль RL_I (это реле с двумя дискретными входами), в котором используются команды Modbus 05(управление реле), 02(опрос входов), 01(состояние реле). Прописал в опросе шаг1 - 05, шаг2 - 01, шаг3 - 02. В результате работает только Шаг1, остальные игнорятся почему-то.

Может для корректной работы необходимо данный модуль разделить на три? И в каждом использовать нужную функцию по отдельности...

Попробовал опросить каждой функцией отдельно. По отдельности работают. Причём настройки портов и опроса не меняю (500мс) - 02 функция опрашиватся 500мс, а 01 и 05 - 100мс.

Вобщем пока не понимаю как опросить один и тот же модуль разными Modbus функциями. Разделить на три модуля не получается т.к. адрес один и тот же - диспетчер не пропускает...

Sergeba
07.12.2019, 15:05
Возможно есть другой способ опроса... Для опроса по трём функциям сделал в основном цикле такую конструкцию:


CASE i OF
0: (*функция 01*)
IF RL1.FUN<>1 THEN
T1:=TIME();
END_IF
RL1.FUN:=1;
IF (TIME()-T1)>T#200ms THEN i:=1; END_IF (*время адержки перехода на следующую функцию*)
1: (*функция 02*)
IF RL1.FUN<>2 THEN
T2:=TIME();
END_IF
RL1.FUN:=2;
IF (TIME()-T2)>T#500ms THEN i:=2; END_IF (*время задержки перехода на следующую функцию*)
2: IF V<>V_bak THEN (*функция 05*)
V_bak:=V;
RL1.wrDO:= NOT RL1.wrDO;
T3:=TIME();
RL1.FUN:=5;
END_IF
IF (TIME()-T3)>T#1s THEN i:=0; END_IF (*время задержки перехода на следующую функцию*)
END_CASE
В соответсвующей функции опрашиваю модуль также оператором case - передаю из основной программы посредством RL1.FUN.
Так теперь работает.

Спорягин Кирилл
09.12.2019, 09:08
Почему-то не меняется время опроса ставлю 500мс и 1000мс, всё равно опрос идёт с частотой 100мс (на глаз).


Должен меняться. Вы точно меняете PollingTime, а не ValidPollingTime, например?




Второе, что не понял, для чего в опросе модулей используются шаги (step). Ведь всё равно опрос прописан так, что команды опроса следуют друг за другом...


Как правило опрос в модулях организован следующим образом (для модулей ввода):
1. На 1-м шаге вызываем соответствующую функцию опроса. Когда она завершила работу (Complete=true) анализируем результат и либо повторяем шаг 1 или идем на следующий.
2. На 2-м шаге, если нужно опрашиваем другие регистры этого же модуля, если нужно другой функцией. Когда функция завершила работу (Complete = true) анализируем результат и либо повторяем шаг или идем на следующий.
...
N. На заключительном шаге выполняем различные сервисные функции. В частности: статистика, сообщаем диспетчеру, что опрос завершен.

Sergeba
09.12.2019, 09:39
2. На 2-м шаге, если нужно опрашиваем другие регистры этого же модуля, если нужно другой функцией. Когда функция завершила работу (Complete = true) анализируем результат и либо повторяем шаг или идем на следующий.


Да, но судя по коду (в примерах), насколько я понял, эти шаги исполняются один за другим, за одну итерацию - если это так, то смысла в Step не вижу. Это же не оператор Case. Следуя примеру, я так и сделал для описания своего модуля (реле с управлением), использовал Step. В результате модуль опрашивался реже и реже, .пока вообще перестал опрашиваться, причём опрос происходил только по первой описываемой функции, вторая и третья по очереди (были разнесены на разные Step) не опрашивались Read у них висел всё время в False. После чего я описал модуль оператором Case, параметр для оператора передавал из основной программы - так опрос пошёл по всем трём функциям, только пришлось подобрать тайминги выполнения каждой из них, поскольку, к примеру, срабатывание реле не происходило, если обращение функции происходило меньше 1 сек.

Хотя... смысл в Step понятен, но тогда получается, что ещё нужно описать задержки между опросами разных функций. Т.к. мой модуль отказывается опрашиваться...Причём, в моём случае эти задержки различны по времени.

Alexlyu
09.12.2019, 11:05
Возможно есть другой способ опроса... Для опроса по трём функциям сделал в основном цикле такую конструкцию:


CASE i OF
0: (*функция 01*)
IF RL1.FUN<>1 THEN
T1:=TIME();
END_IF
RL1.FUN:=1;
IF (TIME()-T1)>T#200ms THEN i:=1; END_IF (*время адержки перехода на следующую функцию*)
1: (*функция 02*)
IF RL1.FUN<>2 THEN
T2:=TIME();
END_IF
RL1.FUN:=2;
IF (TIME()-T2)>T#500ms THEN i:=2; END_IF (*время задержки перехода на следующую функцию*)
2: IF V<>V_bak THEN (*функция 05*)
V_bak:=V;
RL1.wrDO:= NOT RL1.wrDO;
T3:=TIME();
RL1.FUN:=5;
END_IF
IF (TIME()-T3)>T#1s THEN i:=0; END_IF (*время задержки перехода на следующую функцию*)
END_CASE
В соответсвующей функции опрашиваю модуль также оператором case - передаю из основной программы посредством RL1.FUN.
Так теперь работает.



Столкнулся с такой же проблемой при опросе частотника, пишет, но не читает, при чтении выдаёт ошибку таймаута. до того, как концовку переделал, диспетчер ещё после каждого неудачного чтения увеличивал время опроса.
Мне вот такой костыль не подходит, особенно задержки такие страшные, тк желаемый период опроса не более 100мс. если так и не получится в одном модуле и управлять и считывать, то разделю, можно будет поставить 50мс и 200мс соответственно. Но такой себе вариант дробить функцию.
* но диспетчер хитрый, не даёт две функции с одним адресом использовать. попробую это устранить.

Alexlyu
09.12.2019, 13:56
Даже разделение функций не помогает.
Если только читать - всё чётко и без ошибок. Если только писать - всё чётко и без ошибок. если и читать и писать, то только пишет, но частые ошибки таймаута, а чтение постоянно висит в ошибке таймаута.
Может подскажете, где искать проблему?
Попробую другой модели частотник помучить, вдруг что-то изменится.

Спорягин Кирилл
10.12.2019, 10:46
Да, но судя по коду (в примерах), насколько я понял, эти шаги исполняются один за другим, за одну итерацию - если это так, то смысла в Step не вижу. Это же не оператор Case. Следуя примеру, я так и сделал для описания своего модуля (реле с управлением), использовал Step. В результате модуль опрашивался реже и реже, .пока вообще перестал опрашиваться, причём опрос происходил только по первой описываемой функции, вторая и третья по очереди (были разнесены на разные Step) не опрашивались Read у них висел всё время в False. После чего я описал модуль оператором Case, параметр для оператора передавал из основной программы - так опрос пошёл по всем трём функциям, только пришлось подобрать тайминги выполнения каждой из них, поскольку, к примеру, срабатывание реле не происходило, если обращение функции происходило меньше 1 сек.

Хотя... смысл в Step понятен, но тогда получается, что ещё нужно описать задержки между опросами разных функций. Т.к. мой модуль отказывается опрашиваться...Причём, в моём случае эти задержки различны по времени.

Что значит за одну итерацию?
Мы переходим на следующий Step, только, когда получили ответ, что опрос закончен, т.е. Complete = true.
Если ваш модуль неповоротливый и не может сразу после обработки одного запроса, тут же отвечать на другой, тогда сделайте "пустой" шаг, на котором просто ждите определенное время (100, 200 мс).

А вот параметр для case передавать из основной программы - это идеологически неверно! Модуль сам решает, как опрашивать свои регистры! Зачем еще что-то писать в основной программе!???

Спорягин Кирилл
10.12.2019, 11:01
Столкнулся с такой же проблемой при опросе частотника, пишет, но не читает, при чтении выдаёт ошибку таймаута. до того, как концовку переделал, диспетчер ещё после каждого неудачного чтения увеличивал время опроса.

Скорее всего или ошибка в запросе чтения или частотник у вас неповоротливый (см. пост выше).
Увеличивает время опроса не диспетчер, а сам модуль (в функции fcModuleBase). Это механизм для устранения отказавших модулей из сети, чтобы сеть не подвисала.
Если не хотите, что бы время опроса для данного модуля при ошибках увеличивалось просто сделайте настройку MaxPollingTime равной pollingTime и все.




Мне вот такой костыль не подходит, особенно задержки такие страшные, тк желаемый период опроса не более 100мс. если так и не получится в одном модуле и управлять и считывать, то разделю, можно будет поставить 50мс и 200мс соответственно. Но такой себе вариант дробить функцию.
* но диспетчер хитрый, не даёт две функции с одним адресом использовать. попробую это устранить.

Диспетчер специально не допускает 2-х модулей с разными адресами. Можно, конечно, убрать эту проверку из диспетчера, но идеологически правильно делать по-другому. А именно, когда модуль получил право на опрос он сам решает, как опрашивать физический модуль. Например, он может после записи сделать паузу (например, с помощью "пустого" шага), перед опросом.
Можно сделать так, что модуль получив право на опрос один раз пишет, в другой раз читает. И он (модуль!) сам запоминает, что он делал в предыдущий раз - читал или писал.

Спорягин Кирилл
10.12.2019, 11:03
Даже разделение функций не помогает.
Если только читать - всё чётко и без ошибок. Если только писать - всё чётко и без ошибок. если и читать и писать, то только пишет, но частые ошибки таймаута, а чтение постоянно висит в ошибке таймаута.
Может подскажете, где искать проблему?
Попробую другой модели частотник помучить, вдруг что-то изменится.

Ответил в предыдущих 2-х постах.

Alexlyu
10.12.2019, 17:36
Ответил в предыдущих 2-х постах.

Спасибо! Помогло!
Несколько часов пробовал разнести функции во вызовам, пришлось в структуру модуля переменную добавить и научиться ей управлять.
Так же пришлось понять, какие команды подавать, чтоб каждый вызов правильно начинался и завершался. По циклам смотрел происходящее, чтоб понять, почему диспетчер клинит. Жаль, что функции нельзя мониторить.

В итоге получил рабочий модуль E4_8400. Осталось другие допилить.
Также добавил "EN" в базовую структуру, отсутствие этого сигнала через обработчик базы заставляет модули прикидываться вечными ждунами. Мне иногда нужно выводить модули из опроса.

У вас очень полезный и гибкий инструмент получился! Осталось до конца его понять, и можно по аналогии (подход) все проги перепиливать. ;)

* вопрос на засыпку: могу ли я менять скорость работы порта при вызове модуля? например одно устройство опрашивать на скорости 9600, другое на 19200 с одного порта?

Sergeba
10.12.2019, 22:20
* вопрос на засыпку: могу ли я менять скорость работы порта при вызове модуля? например одно устройство опрашивать на скорости 9600, другое на 19200 с одного порта?

Хороший вопрос!

Sergeba
12.12.2019, 02:08
Если ваш модуль неповоротливый и не может сразу после обработки одного запроса, тут же отвечать на другой, тогда сделайте "пустой" шаг, на котором просто ждите определенное время (100, 200 мс).


Не получается сделать задержку. Испольую Time(), но время не сохраняется. Пробовал в описании типа функции задать переменную и в неё передавать время - тоже 0.

Alexlyu
12.12.2019, 10:13
Не получается сделать задержку. Испольую Time(), но время не сохраняется. Пробовал в описании типа функции задать переменную и в неё передавать время - тоже 0.

Тогда стоит попробовать чтение и запсись делать при разных вызовах. У меня работает прекрасно. Частотники со скоростью 9600 опрашиаваются каждые 25мс (общий опрос получается 50мс), работает чётко.

*эксперименты со сменой скорости порта на лету закончились неудачей. Но это не беда. Ведь мы имеем два порта, один можно для быстрых а другой для медленных устройств, типа частотников. С ними мало данных нужно, так что и так успеют опроситься.

Спорягин Кирилл
12.12.2019, 10:20
Не получается сделать задержку. Испольую Time(), но время не сохраняется. Пробовал в описании типа функции задать переменную и в неё передавать время - тоже 0.

Это уже собственно к диспетчеру не имеет отношения. Но попробуйте просто стандартный таймер TON использовать. Проблем быть не должно.

Спорягин Кирилл
12.12.2019, 10:23
* вопрос на засыпку: могу ли я менять скорость работы порта при вызове модуля? например одно устройство опрашивать на скорости 9600, другое на 19200 с одного порта?

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

Alexlyu
12.12.2019, 18:37
И так, методом страшнейших мучений и научного тыка я сделал из модулей fcE4_8400 fcMB110_32DN fcMY110_16P модуль MK110_8DN4R.
Было настоящей пыткой разбираться в коде без комментариев, как понял работу, так и написал комменты в своём модуле. Особо сложно было врубиться в обработчик счётчиков модуля 32ДН.
Когда это победил, получил проблемы с переносом данных из буфера.
Долго искал, предположил, что есть перекрытие областей памяти, немного изменил порядок в структуре модуля и модуль полностью заработал.

Спорягин Кирилл
13.12.2019, 11:55
Было настоящей пыткой разбираться в коде без комментариев...

Меня учили, что современный код, практически не нуждается в комментариях.
Комментарии нужны были преимущественно тогда, когда писали на ассемблере. В настоящее время есть возможность давать любые имена переменным, поэтому хорошо продуманное именование переменных практически полностью заменяет комментарии.

Alexlyu
13.12.2019, 12:17
Меня учили, что современный код, практически не нуждается в комментариях.
Комментарии нужны были преимущественно тогда, когда писали на ассемблере. В настоящее время есть возможность давать любые имена переменным, поэтому хорошо продуманное именование переменных практически полностью заменяет комментарии.

А вот и нет. Скинул фотку кода программеру знакомому, который у нас в ЦПС работает, на оборонку. Их отдел на Си пишет. Так этот человек ужаснулся "а где комментарии!".
Как бы не были названы переменные, всегда полезно знать, а чего хотел автор тут сделать, почему именно так сделал (часто варианты разные бывают, иногда другие варианты к краху приводят).
Т.к. я задел больную тему, мы минут 10 обсуждали полезность комментариев и необходимость подробной документации к модулям.

Вам то понятно, но другие то откуда знают, что происходит? Это нужно долго и мучительно просматривать связи, документацию на железо, затем тестировать и смотреть, "а что будет?".
Вот листал я темы, как real получить. Этот вездессущий ОВЕН так да сих пор и неудосужился дать нормальное описание. Спасибо хоть супермодератору за видосик для CS3.5, и тот без комментариев к пачке указателей :-( (пока допёрло, что там за жонглирование, время много прошло).
Один только Сазар там пытался этим ТруКодерам растолковать, какие описания должны быть: берём вот это, вот так кладём сюда, вот так потому-что ... , получаем вот это.
Ведь не понятно даже, почему из буфера извлекаются данные с перемешиванием. Видно только, что это работает, значит так надо.

Спорягин Кирилл
13.12.2019, 12:27
Местами я пишу (цитаты по памяти): "Необходимо заново сформировать буфер", "Чтобы потом не проверять указатели" и т.д. Т.е. какие-то важные места я комментирую.
Это первое.
Второе. Думаю, что ваш товарищ работает в команде и комментарии нужны скорее другим.
Тут я писал для себя. И только потом решил выложить свои труды.

Alexlyu
13.12.2019, 12:38
Местами я пишу (цитаты по памяти): "Необходимо заново сформировать буфер", "Чтобы потом не проверять указатели" и т.д. Т.е. какие-то важные места я комментирую.
Это первое.
Второе. Думаю, что ваш товарищ работает в команде и комментарии нужны скорее другим.
Тут я писал для себя. И только потом решил выложить свои труды.
Да, для других комменты.
могу позавидовать вашей памяти!
Я через год открываю какой то проект, и если не написал ранее, что и зачем я сделал, то идёт мучительное разбирательство, (а это что, а нафига, а как это вобще у меня работает, а почему я так сделал, можно же упростить... а, нет, нельзя, всё рушится)

Alexlyu
13.12.2019, 17:51
Поймал странный глюк, который нагуглить не смог. Вчера вечером всё работало, а сегодня модуль fcEI_7012(FC1) отказался работать. Судя мо mdlErr - ошибка 251 (mdlDispIsNullError), и вот эту ошибку не нарыл в описании овеновском modbus.lib и syslibcom, и гуглем, и поиском по форуму.
Ладно... объявил fcEI_7012(FC3), туда пихнул целевой адрес, а на FC1 левый. загрузочный проект->перезагрузка = работает скотина! удалил FC1 -> загрузочный проект->перезагрузка = работает скотина!
Что это было я так и не понял. Ведь я ничего не поменял, просто переобъявил под новым именем. НО! вечером работало после перезагрузок, а на следующий день не захотело.
Если это залётная ошибка, то фиг с ней, а вот если такое периодически будет, то меня интегрируют в систему управления.
https://vignette.wikia.nocookie.net/masseffect/images/6/60/%D0%A4%D0%B8%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D 1%8F_%D0%B2%D1%81%D1%82%D1%80%D0%B5%D1%87%D0%B0_%D 0%A8%D0%B5%D0%BF%D0%B0%D1%80%D0%B4%D0%B0_%D1%81_%D 0%94%D1%8D%D0%B2%D0%B8%D0%B4%D0%BE%D0%BC_%D0%B8_%D 0%90%D1%80%D1%87%D0%B5%D1%80%D0%BE%D0%BC.png/revision/latest?cb=20131229060131&path-prefix=ru

Этот то заработал (Disp1), а вот Disp0 встрял на модуле MK110 и сидит. Чертовщина. Только что работал.
О, всё само заработало после перезалива и перезагрузки. я только сделал, чтоб MK110 сразу в ожидание встал после загрузки, пустил в опрос чуть позже.
Очень пугает такое.

Спорягин Кирилл
13.12.2019, 22:00
Поймал странный глюк, который нагуглить не смог. Вчера вечером всё работало, а сегодня модуль fcEI_7012(FC1) отказался работать. Судя мо mdlErr - ошибка 251 (mdlDispIsNullError), и вот эту ошибку не нарыл в описании овеновском modbus.lib и syslibcom, и гуглем, и поиском по форуму.


Ошибка mdlDispIsNullError устанавливается в функции fcModuleDispVerification (она входит в библиотеку) - смотрите вот это место:
IF pDisp = Null THEN
MdlBase.Error := mdlDispIsNullError;
fcModuleDispVerification := FALSE;
RETURN;
END_IF;
И означает, что в модулей не настроен указатель на диспетчер.

Я посмотрел вы инициализируете сеть правильно.
Не знаю как такое могло произойти.




Этот то заработал (Disp1), а вот Disp0 встрял на модуле MK110 и сидит. Чертовщина. Только что работал.
О, всё само заработало после перезалива и перезагрузки. я только сделал, чтоб MK110 сразу в ожидание встал после загрузки, пустил в опрос чуть позже.
Очень пугает такое.

Тут анализируйте свой модуль.

Для уверенности могу сказать, что у меня на десятках объектов 24/7 все пашет идеально.

Alexlyu
16.12.2019, 10:45
Тут анализируйте свой модуль.

Да, так и оказалось.
Пришлось нумеровать каждый уровень "IF", открытие, закрытие. Один шаг оказался на уровень выше других.
Теперь всё чётко. модуль МК110_8ДН4Р работает нормально.

Sergeba
19.12.2019, 21:25
У меня тоже странный глюк. В примере везде переменная Step объявлена как int. Я привык экономить по возможности - поменял int на byte. Таким описанием воспользовался более чем на десятке модулей. Вдруг, во время тестирования наблюдаю. что один из модулей. который ранее работал перестал отвечать на запросы. Проверил его modpull - всё работает, а в проекте не отвечает... Вдруг обращаю внимание, что переменная step равна нулю!!! Хотя в описании, как в примере задано начальное значение - единица! Из-за этого нуля не выполняются шаги описываемые функцией модуля. Что только не делал... Перезаливал проект, перегружал контроллер - всё равно - ноль. Тут у меня уже начался взрыв мозга... Поменял описание на int... Всё нормально заработало...Что это было? Остальные модули работают без проблем - в описании byte.

P.S. Во всех модулях шагов максимум 6.

Спорягин Кирилл
20.12.2019, 14:22
У меня тоже странный глюк. В примере везде переменная Step объявлена как int. Я привык экономить по возможности - поменял int на byte. Таким описанием воспользовался более чем на десятке модулей. Вдруг, во время тестирования наблюдаю. что один из модулей. который ранее работал перестал отвечать на запросы. Проверил его modpull - всё работает, а в проекте не отвечает... Вдруг обращаю внимание, что переменная step равна нулю!!! Хотя в описании, как в примере задано начальное значение - единица! Из-за этого нуля не выполняются шаги описываемые функцией модуля. Что только не делал... Перезаливал проект, перегружал контроллер - всё равно - ноль. Тут у меня уже начался взрыв мозга... Поменял описание на int... Всё нормально заработало...Что это было? Остальные модули работают без проблем - в описании byte.

P.S. Во всех модулях шагов максимум 6.

Если вы дозагружали ПЛК, т.е. заливали не полный проект, а внесенные изменения, то необходимо повторять процедуру инициализации указателей (она происходит на первом скане, а первого скана после дозагрузки не происходит).
Я обычно это делаю перезагрузкой питания. Скорее всего в этом дело.

Sergeba
22.12.2019, 13:49
Если вы дозагружали ПЛК, т.е. заливали не полный проект, а внесенные изменения,

Когда меняю описание переменных или добавляю новые, всегда делаю полную заливку. Ну да ладно, больше таких глюков не было.

Sergeba
30.12.2019, 00:17
Использую ПЛК110. Опрос организовал на RS485-1 (15 устройств) и RS485-2 (29 устройств). Смотрю результаты опроса в Base, есть параметр NoPollingErrCnt, так на линии 2 этот счётчик на всех модулях увеличивается с разной скоростью - минимум раз в 5 сек. На линии 1 счётчик на нуле и не меняется. Не пойму в чём проблема со второй линией? Могу всё переподключить на первую линию, но тогда на ней будет 44 устройства, что, боюсь, негативно может сказаться на быстродействии всей сети.

Спорягин Кирилл
30.12.2019, 09:14
Использую ПЛК110. Опрос организовал на RS485-1 (15 устройств) и RS485-2 (29 устройств). Смотрю результаты опроса в Base, есть параметр NoPollingErrCnt, так на линии 2 этот счётчик на всех модулях увеличивается с разной скоростью - минимум раз в 5 сек. На линии 1 счётчик на нуле и не меняется. Не пойму в чём проблема со второй линией? Могу всё переподключить на первую линию, но тогда на ней будет 44 устройства, что, боюсь, негативно может сказаться на быстродействии всей сети.

Счетчик NoPollingErrCnt увеличивается на 1 каждый раз когда за контрольное время (NoPollingTime) модуль не получил доступа к сети. Такое может быть, если в очереди много модулей и все хотят опроса. Кажется по умолчанию NoPollingTime = 1с. Увеличьте это время и счетчик NoPollingErrCnt перестанет увеличиваться.

Sergeba
31.12.2019, 22:55
Увеличьте это время и счетчик NoPollingErrCnt перестанет увеличиваться.

Убрал из циклического опроса 8 модулей - сделал опрос по условию - всё нормализовалось, сейчас счётчик не увеличивается.

NoPollingTime тоже влияет - у меня стоит 3сек. Пробовал уменьшить до 2 сек - опять начал увеличиваться NoPollingErrCnt - оставил 3 сек.

Ещё не понятно. Посмотрел модуль статистики контроллера - у меня постоянно показывает перегрузку процессора. В настройках минимальное время цикла - 1мс, по факту в модуле статистики наблюдаю 2-3мс. Решил поменять в настройках на 5мс... Перегрузки процессора нет, но по всем модулям начал счётчик
NoPollingErrCnt опять увеличиваться и наблюдается затороможенность всей системы. Реакция на различные действия увеличилась на порядок. Откатил обратно на 1мс.

Ещё проблемка. Решил увеличить скорость опроса в сетке. Максимальная, которую поддерживает самый медленный модуль - 38400. Сейчас установлено 9600. Поднял. Несколько модулей одного типа отвалились - ошибка Modbus превышение времени ответа... Подключаю сетку к ПК через USB-свисток - программой Modbus Pull - работают модули, опрос идёт... Откатил скорость на промежуточную - 19200 - опрос пошёл. Так и не смог запустить на скорости 38400, оставил 19200.

Нет ли у Вас версии диспетчера для Codesys V3? Задолбал мой старичок (ПЛК110)... Есть ПЛК304, но модули через конфигурацию работают отвратительно - постоянные отвалы, пропуски опроса (на тех же линиях, где сейчас пробовал Ваш диспетчер на ПЛК110).

Спорягин Кирилл
09.01.2020, 11:12
Убрал из циклического опроса 8 модулей - сделал опрос по условию - всё нормализовалось, сейчас счётчик не увеличивается.

Интересно, сколько же у вас модулей на сети?
Смотрели ли вы статистику опроса модулей (https://owen.ru/forum/showthread.php?t=25519&p=226486#post226486).
Может у вас быстрее и не получиться?




Ещё не понятно. Посмотрел модуль статистики контроллера - у меня постоянно показывает перегрузку процессора. В настройках минимальное время цикла - 1мс, по факту в модуле статистики наблюдаю 2-3мс. Решил поменять в настройках на 5мс... Перегрузки процессора нет, но по всем модулям начал счётчик
NoPollingErrCnt опять увеличиваться и наблюдается затороможенность всей системы. Реакция на различные действия увеличилась на порядок. Откатил обратно на 1мс.


Если вы увеличиваете время цикла ПЛК, то вы неизбежно увеличиваете общее время опроса всех модулей, так как для опроса любого модуля на любой скорости нужно как минимум 3 цикла. Об этом я писал вот тут (https://owen.ru/forum/showthread.php?t=21940&page=14&p=219033&viewfull=1#post219033).




Ещё проблемка. Решил увеличить скорость опроса в сетке. Максимальная, которую поддерживает самый медленный модуль - 38400. Сейчас установлено 9600. Поднял. Несколько модулей одного типа отвалились - ошибка Modbus превышение времени ответа... Подключаю сетку к ПК через USB-свисток - программой Modbus Pull - работают модули, опрос идёт... Откатил скорость на промежуточную - 19200 - опрос пошёл. Так и не смог запустить на скорости 38400, оставил 19200.


Тут проблема скорее в различных характеристиках модулей.
Происходит, видимо, следующее. Послан запрос на модуль 1. Он быстрый. Он очень быстро ответил. Контроллер разобрал ответ и послал запрос на модуль 2. Он медленный. И когда ПЛК уже послал запрос на модуль 2 (т.е. ему) он еще разбирает посылку для модуля 1. Поэтому посылку себе он пропускает. Возникают таймауты. Общая скорость опроса в сети падает.
В этом случае можно увеличить настройку FramingTime в диспетчере. Это как раз пауза между посылками. Для устранения подобных проблем. Или же увеличьте общее время цикла ПЛК. Пауза возникнет сама собой.





Нет ли у Вас версии диспетчера для Codesys V3? Задолбал мой старичок (ПЛК110)... Есть ПЛК304, но модули через конфигурацию работают отвратительно - постоянные отвалы, пропуски опроса (на тех же линиях, где сейчас пробовал Ваш диспетчер на ПЛК110).

Нет под 3-ю версию не писал. Но я думаю, что если просто перенести код 2-го КДС в 3-й, то должно заработать.

Sergeba
13.01.2020, 00:53
Интересно, сколько же у вас модулей на сети?

Нет под 3-ю версию не писал. Но я думаю, что если просто перенести код 2-го КДС в 3-й, то должно заработать.

Модулей на одном порту 29, на втором 15.

Сейчас в 3-м КДС "накидал" опрос по документации ОВЕНа . Позже попробую перенести Ваш проект т.к. мой старичок ПЛК110 сдох в конце концов... На связь перестл выходить и судя по светодиодам вошёл в цикл перезагрузки...

Валенок
13.01.2020, 09:19
циклическая перезагрузка и выход из строя как то связаны ?

Sergeba
15.01.2020, 00:31
циклическая перезагрузка и выход из строя как то связаны ?

Предложите вариант выхода из цикла? Пробовал перешивать с помощью кабеля и перемычки - не помогло.

Sergeba
18.01.2020, 11:54
выключить, стоп, включить - непомогает?

Это самое первое что пробовал. Индикация подтверждает переключение тумблера, но результата нет. Да и заливка чистой прошивки должна была восстановить работу т.к. насколько я понял при прошивки очищается вся память и заливаются новые файлы с настройками (сетевые и т.д.). Но всё тоже самое - пытается стартовать, начинает моргать сетевой (LAN) светодиод, всё гаснет и по новой. На ПК даже не успевает определить USB подключение (обычно сразу пиликал и в диспетчере появлялось новое USB-устройство).

Sergeba
18.01.2020, 21:09
непонял какой тумблер когда говорили о старом, но раз плк БЕЗ программы чудит - в ремонт.

у меня ПЛК110 М01. Сказали что это какой-то промежуточный между ПЛК110 и ПЛК110 М02. Он уже идёт с тумблером, как на М02

Валенок
18.01.2020, 21:13
Тогда еще короче : плк БЕЗ программы чудит - в ремонт

Sergeba
18.01.2020, 21:51
если просто перенести код 2-го КДС в 3-й, то должно заработать.

Уточните, с библиотеками. В проекте подключаются две библиотеки GCTimers и GCCommon. Они используются в диспетчере? Нужно ли и как их перенести в CDS3?

Вроде бы разобрался... GCCommon специально для ПЛК110, т.е. для ПЛК307 не нужна, а вторая нужна.

Всё перенёс, пока в работе не пробовал. Немного отличается использование библиотеки ComService.

Ещё проблема... в CDS3 на "Enable := NOT Mdl.pDisp^.ReadInpRegs.Read" ругается, посмотрел библиотеку Modbus... там нет переменной READ... Как задавать Enable для опроса? Read это локальная переменная, странно что к ней есть доступ... Могу ли я использовать для этих целей Complete?

Спорягин Кирилл
20.01.2020, 12:36
Ещё проблема... в CDS3 на "Enable := NOT Mdl.pDisp^.ReadInpRegs.Read" ругается, посмотрел библиотеку Modbus... там нет переменной READ... Как задавать Enable для опроса? Read это локальная переменная, странно что к ней есть доступ... Могу ли я использовать для этих целей Complete?

Поясню по Enable.

Все блоки из библиотеки Modbus.lib активируются по переднему фронту переменной Enable.
Если посмотреть реализации, которые предлагают в примерах от разработчика библиотеки Modbus.lib, там можно встретить такие конструкции.
Шаг Х
Блок1(Enable := true);
if Блок1.Complete then
Блок1(Enable := false);
end_if;

Так пишется, чтобы, когда мы в следующий раз попали на шаг Х снова появился фронт на входе Enable.
На мой взгляд, так некрасиво.

Вызов

Шаг Х
Блок1(Enable := not Блок1.Read);

позволяет формировать фронт, не дублируя вызов Блока1.
Так при первом заходе на шаг Х (Read = false) и мы сформировали фронт на входе Enable.
При втором заходе Read = true и мы записали в Enabel ложь. А значит, когда в следующий раз мы попадем на шаг Х, то снова появиться фронт на входе Enable.

Sergeba
20.01.2020, 14:08
позволяет формировать фронт, не дублируя вызов Блока1.
Так при первом заходе на шаг Х (Read = false) и мы сформировали фронт на входе Enable.
При втором заходе Read = true и мы записали в Enabel ложь. А значит, когда в следующий раз мы попадем на шаг Х, то снова появиться фронт на входе Enable.

Ок, я понял. В отсутствии Read что я могу использовать?

Прочитал Ваш ответ в той теме...Попробую скомпилировать с Read.

Спорягин Кирилл
20.01.2020, 15:07
Евгений Кислов, указывает, что Read ("читаю") в CDS3 имеет имя xBusy, т.е. "занят".

Евгений Кислов
20.01.2020, 15:18
xBusy - это в стандартных компонентах (в дереве проекта) и нашей новой библиотеке OwenCommunication.
В библиотеке Modbus (версия 3.5.4.3) нужная локальная переменная называется m_xReqSend - это аналог Read из библиотеки Modbus для Codesys V2.3.

Sergeba
25.01.2020, 20:13
нужная локальная переменная называется m_xReqSend - это аналог Read из библиотеки Modbus для Codesys V2.3.

Не получается... Опрос не идёт. Ошибка modbus - TimeOutError. Похоже эта переменная не даёт опросить модуль.

Отбой! Заработало. Handle по другому нужно прописывать:

CDS2: ComHandle := Mdl.pDisp^.Settings.Port,
CDS3: ComHandle := Mdl.pDisp^.COM_SERVICE1.Handle,

Sergeba
25.01.2020, 21:15
не пробовали обычным способом работать с модбас?


Первое что сделал - через конфигуратор - ОТСТОЙ. Модули валятся, связь не восстанавливается, через костыли (нашёл на форуме) нашёл возможность их переподключать, но из-за частых отключений бывает теряются передаваемые комманды, иногда отваливается так, что не восстанавливается. Повторюсь - ОТСТОЙ.

Второе - был свободный ПЛК110 - на нём собрал "Универсальный диспетчер" - заработало, с огрехами. но на порядок стабильнее. Но вот незадача - крякнул ПЛК...

Третье - написал на ПЛК307 на бибке, без диспетчера... Работает, тоже с огрехами, не уверен в надёжности - долго не проверял (но заметил, что система стала отзываться медленнее, чем через конфигуртор) т.к. вспомнил про "Универсальный диспетчер" - решил его прикрутить...чем и занимаюсь сейчас.

Sergeba
26.01.2020, 00:20
Это пока не Ваше, прекратите насиловать себя

Зачем так утверждать? Универсальный диспетчер у меня запустился на ПЛК110, сейчас переношу его на ПЛК307. Не сразу всё получается, но у кого сразу получалось? Сейчас уже почти добил - работает на одном порту, пытаюсь разобраться, почему не заводится второй порт...
А конфигуратор - УВОЛЬТЕ!!! Вот его делали люди с кривыми руками и не доделав бросили... Кое как работают модули, но совсем отвратно работает в конфигураторе режим Modbus TCP Slave. От него меня вылечила соответсвующая библиотека, которую мне порекомендовал Евгений Кислов, за что ему большое спасибо.

Sergeba
26.01.2020, 00:45
нужная локальная переменная называется m_xReqSend - это аналог Read из библиотеки Modbus для Codesys V2.3.

Не во всех функциях Modbus есть эта переменная... Ещё есть другая - m_xIsReqSend

Не пойму, опять наблюдаю такую картину на первом порту всё идеально, на втором все модули считают NoPollingErrCnt... Ставлю NoPollingTime = T#7s, подсчёт ошибок прекращается. Неужели опрос идёт по 7 сек на модуль? Хотя, вижу что показания обновляются примерно раз в 2,5сек. Такое впечатление, что таймер неправильно считает секунды...Среднее время цикла основной программы в Мониторе около 0,8мс

Добавил основную программу обработки данных. Средний опрос подскочил до 9,5сек. Пришлось поставить NoPollingTime = T#10s. Действительно, отклик модулей стал медленным, по сравнению с конфигуратором... Поставил в Task цикл = 1мс, до этого было 5мс. По факту в мониторе средний цикл около 3мс, среднее время опроса модулей сократилось до 6,8сек - всё равно много, по ощущениям через конфигуратор скорость опроса 1,5-2 сек.

Запустил вариант программы с модулями через конфигуратор. Средний цикл в Task = 5.9мс, при этом опрос модулей около 1,5 сек.

Плюс у диспетчера - опрос модулей безупречен, но медленный. Через конфигуратор скорость опроса в 4 раза быстрее, но периодически отваливаются модули, переподключаются с помощью "костылей", из-за этого есть вероятность пропуска команды.

Спорягин Кирилл
27.01.2020, 13:16
Отвечу в общем.
На CDS V2 на любом порту опрос прекрасно работает.
Очень странно, что на CDS V3 опрос зависит от порта.

Sergeba
27.01.2020, 14:09
Отвечу в общем.
На CDS V2 на любом порту опрос прекрасно работает.
Очень странно, что на CDS V3 опрос зависит от порта.

Когда время поднял до 10сек - тоже ошибки прекратились...
Я так понимаю, опрос через конфигуратор как то имеет бОльший приоритет и обрабатывается отдельным циклом? Пробовал опрос в диспетчере вытащить в отдельный Task и назначить приоритет выше - опрос увеличился на 2-3 сек.
Минимум чего я добился - средний опрос 6,8сек. Для относительно быстрых систем это не приемлимо... А так - работает идеально. модули не отваливаются...

Sergeba
27.01.2020, 23:45
Вы бы хоть проект выложили, ну явно же косяк где то, ни кто не будет ждать даже секунду при опросе модуля/лей,тут бы весь форум был завален подобными жалобами

Ок, вот проект. Убрал из него обработку данных. Оставил только опрос с диспетчеризацией

Sergeba
01.03.2020, 21:05
Продолжение истории.
ПЛК307 пока забросил по причине ну очень медленной обработки... В сервисном центре ОВЕН поменяли мне мой старый ПЛК110 М01 на новый ПЛК110 М02... Как говориться "шило на мыло".
Обновил таргет, заливаю проект, который уже работал на старом ПЛК110. Вроде бы всё работает... но смотрю, у меня есть шесть температурных модулей, из них выдаёт температуру только один, хотя на старом ПЛК все работали... Там ничего сложного - функция 04. Постоянно по остальным идёт таймаут - ошибка. Подключаюсь компом - нет модулей, только один отзывается... Цепляюсь к каждому, отключив от общей сети - чудно - у всех модулей, кроме одного адрес сбросился к 1. Меняю адреса, подключаю ПЛК307 - всё работает, переподключаю на ПЛК110 - опять сбиваются адреса на температурных датчиках. ЧТО ЗА ХРЕНЬ???

Sergeba
02.03.2020, 14:05
так если у датчиков сбились - то это проблема датчиков, что у них сбиваюцца

Ну да, настроенные через конфигуратор ПЛК307, ПЛК110 не сбиваются, и под универсальным диспетчером на старом ПЛК110 не сбивались, а на новом ПЛК110 начали сбиваться, где проблема у датчиков? Думаю это проблема обработки функции 04 из библиотеки на новом ПЛК110.

Валенок
02.03.2020, 20:33
Вы формулируйте как-нибудь более понятно : что сбивается, в чем оно выражается и т.п. В вышеизложенном лично я пока вижу только проблемы самих датчиков. Ваши межстрочные мысли мне неведомы.

Порты на mo2 да, с траблами, но это никоим образом не может привести к сбою на внешних девайсах.

Если считаете что проблема с 4й функцией какой-то либы - ищите автора либы или копайте ее код коли он доступен.
Правда непонятно каким образом функция имеет отношение к порту. Это как цвет ботинок к работе трамвая.

Спорягин Кирилл
03.03.2020, 12:01
Ну да, настроенные через конфигуратор ПЛК307, ПЛК110 не сбиваются, и под универсальным диспетчером на старом ПЛК110 не сбивались, а на новом ПЛК110 начали сбиваться, где проблема у датчиков? Думаю это проблема обработки функции 04 из библиотеки на новом ПЛК110.

Попробуйте использовать функции из библиотеки Modbus.lib и опрашивать в лоб. Например, через case.
Дело в том (я уже много раз на это указывал), что диспетчер решает одну простую задачу - управляет очередностью доступа модулей к порту.
Поэтому, если где-то, что-то Вы, пишете не туда, то это от диспетчера не должно зависеть, как и от устройства (ПЛК3хх, ПЛК1хх и т.д.). Т.е., предположительно, проблема в некорректном вызове функций из библиотеки Modbus.lib.

Sergeba
04.03.2020, 20:19
каким образом функция имеет отношение к порту. Это как цвет ботинок к работе трамвая.

Я и не писал ничего про порты, почитайте моё сообщение внимательно. У меня на новом ПЛК при использовании функции 04 сбивается адрес слэйв-устройства - все адреса на них становятся 1 (почему то кроме одного из этих устройств). Я грешу не на диспетчер, а на сам ПЛК110 М02. Прошивка или таргет так повлиял не знаю. Вывод сделал такой, поскольку данный проект не сбивая адреса работает на ПЛК307 в двух вариантах - под диспетчером и под конфигуратором, также не сбиваются адреса на старом ПЛК110 М01. на новом ПЛК110 М02, под конфигуратором адреса не сбиваются, а под диспетчером сбиваются сразу. Текст программ, функций везде один и тот же. Делаю вывод, что на новом ПЛК110 М02 некорректно обрабатывается функция 04 из библиотеки, причём на некоторых устройствах, что приводит к тому, что эти устройства теряют свои адреса в сети. Получается, что ПЛК посылает какой-то широковещательный сигнал, после чего эти слэйвы становятся недоступными по старым адресам, и у них у всех присваивается адрес 1 (еденица).

Sergeba
04.03.2020, 20:23
Т.е., предположительно, проблема в некорректном вызове функций из библиотеки Modbus.lib.

Ошибки в коде программы нет, думаю есть проблема с функцией 04 в данной библиотеке в совокупности с ПЛК110 М02. Вот код получения данных этого модуля:


IF Mdl.Step = 1 THEN
Mdl.pDisp^.ReadInpRegs(Enable := NOT Mdl.pDisp^.ReadInpRegs.Read,
Mode := MB_RTU,
DevAddr := Mdl.Base.Adress,
FirstAddr := StartRegister,
Quantity:=RegisterCount, (*количество регистров*)
ComHandle := Mdl.pDisp^.Settings.Port,
TimeOut := Mdl.Base.TimeOut,
Buffer:= Mdl.pDisp^.ReciveBuffer);
IF Mdl.pDisp^.ReadInpRegs.Complete THEN
tmpReadError :=Mdl.pDisp^.ReadInpRegs.Exception;
IF tmpReadError =0 THEN
Mdl.reAI:=Mdl.pDisp^.ReciveBuffer[1]+Mdl.pDisp^.ReciveBuffer[0]*256;
Mdl.Step:=Mdl.Step +1;
ELSE
fcModuleAddAttempt(MdlBase := Mdl.Base);
IF Mdl.Base.CurrentAttempt > Mdl.Base.MaxAttempts THEN
Mdl.Step := CompleteStep;
END_IF
END_IF
END_IF
END_IF

Жаль. табуляция не сохраняется в сообщении

Sergeba
05.03.2020, 01:19
В
Если предположить существование этой дичи - то это не проблема диспетчера. И не проблема ПЛК. Это сами слейвы - полное гавно. Это стоп-кран у каждого кресла в самолете. Выкиньте эти слейвы в помойку.


Это не новый проект, эти устройства работают в сети уже 7 лет. Причина того,что начались проблемы - это выход из строя ПЛК фирмы Insyte, после чего начались попытки пересадить сетку на ПЛК Овен. Почему я их должен выбрасывать? Отработав без проблем 7 лет с другим ПЛК, и заменив его на новый ПЛК Овен они начали глючить? Сомневаюсь. Больше похоже что глючит новый ПЛК и его надо, как Вы выражаетесь - "выбосить это полное гавно в помойку"

Или Вы тоже напишите, что "у Всех не глючит, а у Вас глючит..." Да форум полный сообщений о той или иной проблеме Овна и решения этих проблем через различные костыли. Я надеялся, что подняв эту тему кто подскажет как решить данную проблему или в каком направлении копать, а выбросить "полное говно" я всегда успею. Кстати, в переходный период сеть ещё работала от Scada, установленной на компе и ничего не глючило и адреса не слетали. Так что делайте вывод про ПЛК Овен или Овно...

Спорягин Кирилл
05.03.2020, 09:49
Это не новый проект, эти устройства работают в сети уже 7 лет. Причина того,что начались проблемы - это выход из строя ПЛК фирмы Insyte, после чего начались попытки пересадить сетку на ПЛК Овен. Почему я их должен выбрасывать? Отработав без проблем 7 лет с другим ПЛК, и заменив его на новый ПЛК Овен они начали глючить? Сомневаюсь. Больше похоже что глючит новый ПЛК и его надо, как Вы выражаетесь - "выбосить это полное гавно в помойку"

Или Вы тоже напишите, что "у Всех не глючит, а у Вас глючит..." Да форум полный сообщений о той или иной проблеме Овна и решения этих проблем через различные костыли. Я надеялся, что подняв эту тему кто подскажет как решить данную проблему или в каком направлении копать, а выбросить "полное говно" я всегда успею. Кстати, в переходный период сеть ещё работала от Scada, установленной на компе и ничего не глючило и адреса не слетали. Так что делайте вывод про ПЛК Овен или Овно...

Попробуйте, использовать функции из библиотеки Modbus не через диспетчер, а в лоб.
Сохранится ли тогда проблема со сменой адресов?
Нужно все же удалять все лишнее, чтобы найти проблему.

ленивый
09.05.2020, 22:50
Использовал диспетчер на ПЛК160[M02]. Понравилось. (Потому что.. см. nickname) :)



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

Реализовал изменение свойств порта (скорость, стоп-биты, четность) в диспетчере и параметров опроса устройств (период опроса, таймаут).
Свойства меняются с панели СП310, но это непринципиально.

Изменения в коде несложные, если интересно, могу поделиться.

mega2411
05.09.2023, 05:23
Здравствуйте форумчане. есть у кого данная библиотека GCCommon.lib . "Гугл в помощь" не помог

Спорягин Кирилл
07.09.2023, 11:44
Здравствуйте форумчане. есть у кого данная библиотека GCCommon.lib . "Гугл в помощь" не помог

Она же есть в архиве GCModbus.rar в первом сообщении.

* GC - GiproCement (Гипроцемент)

Easy_Enemy
03.10.2023, 23:29
Надеюсь, тема, не померла) Проект - великолепный! Не хватает немного воображения на "нестандартные пакеты". В частности, бывает двухбайтовый пакет, у которого может быть первый бит пустой, во втором бите лежать одни данные, другие данные могут лежать сразу во втором и третьем одновременно, потом опять пустота... и тд. Не вполне понимаю, как проще обрабатывать такие пакеты (простите тупого), причем, на каждое устройство может быть по 8-9 таких пакетов "вразнобой", то есть, каждый индивидуален. Я так понимаю, придется запрашивать все данные на каждое устройство по очереди или есть некий более простой способ обработки определенного бита (пары, тройки склеенных битов)?..
В качестве примера, регистр из модуля управления кондиционерами дайкин

Регистр номер 32001. Структура

бит 15 - ---
бит 12-14 - fan speed
бит 11 - ---
бит 8-10 - fan direction
бит 7 - thermo status
бит 6 - heater status
бит 5 - fan status
бит 4 - ---
бит 3 - ---
бит 2 - forced off status
бит 1 - ---
бит 0 - On/off status

Немного пугает вот это вот) и это не шаблонный регистр, они почти все разные..

melky
03.10.2023, 23:56
а напрямую к дайкину подключиться не?

а что вам тут непонятно? старшим байтов вперед, читаете весь регистр, обозвав его СЛОВОМ (WORD) и дав ему имя BitDaikin, потом BitDaikin.0, BitDaikin.3 и так далее.

Если надо сразу три бита, то делаете маску типа BitDaikin & 0x7000 (пример для 12-14 битов) сдвиг на сколько там 12 кажется вправо и получите число от 0 до 7 ваш фан спид.
Собственно синтаксис смотрите, все операции присутствуют в CodeSys

Easy_Enemy
04.10.2023, 00:14
а напрямую к дайкину подключиться не?

Напрямую - не. Есть шлюз из системы дайкин (DIII-net) в модбас рту. Он в себя собирает все данные со всех кондеев и руляет ими. Сами кондеи не знают ничего, кроме д3-нет (старые модельки, хоть и промышленные).
а что вам тут непонятно? старшим байтов вперед, читаете весь регистр, обозвав его СЛОВОМ (WORD) и дав ему имя BitDaikin, потом BitDaikin.0, BitDaikin.3 и так далее.


Если надо сразу три бита, то делаете маску типа BitDaikin & 0x7000 (пример для 12-14 битов) сдвиг на сколько там 12 кажется вправо и получите число от 0 до 7 ваш фан спид.
Собственно синтаксис смотрите, все операции присутствуют в CodeSys

Вот это не вполне понятно было. То есть мы просто "клеим" (стыкуем) сколько нам нужно бит вместе? Надеялся, что, все же, есть некое средство "выемки" конкретного бита из пакета (на примере какого-нить MasterOPC). Я-то напишу все это ручками, да не всегда хочется изобретать колесо..

Но спасибо за просвещение, уже голова не работает, много систем, много геморроя..

Easy_Enemy
08.10.2023, 17:27
Если надо сразу три бита, то делаете маску типа BitDaikin & 0x7000 (пример для 12-14 битов) сдвиг на сколько там 12 кажется вправо и получите число от 0 до 7 ваш фан спид.
Собственно синтаксис смотрите, все операции присутствуют в CodeSys

Изучил тему с работой с битами, и, наконец, смогу правильно сформировать вопрос)

Почему настолько целесообразно работать с масками и смещениями (поглядел в модули других участников, что, собственно и помогло в написании задач под себя, но, вижу, что маски время от времени мелькают), ведь есть такой, вполне себе симпатичный инструмент, как EXTRACT? Ведь после получения всех данных, в случае, когда регистр набит кучей разнокалиберной информации, и она нам нужна (пусть не вся, но более 1-2) мы же уже заранее знаем, к какому номеру бита нам обратиться и, если, данные хранятся в 2+ битах, то мы просто клеим их в некоторую переменную. Или это слишком ресурсоемко, в отличие от обработки масками? Возможно это будет еще кому-то полезно при написании своих модулей

kondor3000
08.10.2023, 18:03
Изучил тему с работой с битами, и, наконец, смогу правильно сформировать вопрос)

Почему настолько целесообразно работать с масками и смещениями (поглядел в модули других участников, что, собственно и помогло в написании задач под себя, но, вижу, что маски время от времени мелькают), ведь есть такой, вполне себе симпатичный инструмент, как EXTRACT? Ведь после получения всех данных, в случае, когда регистр набит кучей разнокалиберной информации, и она нам нужна (пусть не вся, но более 1-2) мы же уже заранее знаем, к какому номеру бита нам обратиться и, если, данные хранятся в 2+ битах, то мы просто клеим их в некоторую переменную. Или это слишком ресурсоемко, в отличие от обработки масками? Возможно это будет еще кому-то полезно при написании своих модулей

Зачем вам экстракт, если любой бит можно распаковать ( упаковать) через точку прямо в программе?

Easy_Enemy
08.10.2023, 19:52
Зачем вам экстракт, если любой бит можно распаковать ( упаковать) через точку прямо в программе?

Вот да, в частности, ж, есть еще unpack.. Почему же маски до сих пор в ходу? Настолько быстрее обработка? Или экономия загруженности железа?

kondor3000
08.10.2023, 21:05
Вот да, в частности, ж, есть еще unpack.. Почему же маски до сих пор в ходу? Настолько быстрее обработка? Или экономия загруженности железа?

Дело не в экономии, а в удобстве. Экстрактов нужно 16 шт. для 16 битов, анпаков 2 шт., это лишние и ненужные блоки в программе, они занимают место и вообще не нужны.
Работа с битами через точку намного удобнее, компактнее и проще во всём и на любом языке.

Easy_Enemy
16.11.2023, 23:10
Как ни странно, приведя в пример шлюз дайкин - из 50+ устройств исключительно с ним больше всего приключений. В данный момент - не хочет опрашиваться в цикле. В чем суть - есть 5 регистров на чтение, 5 на запись. 7 файнкойлов. Каждый последующий койл хранит для себя данные, начиная от первого и +6 регистров. То есть, фактически, сводится к написанию 10 циклов For с параметром регистра StartRegister1 + ((CurrentCon-1)*6). Но, по каким-то причинам, данный шлюз так опрашиваться не хотит.. То есть, если мы пишем следующую конструкцию, то все данные у нас - нулевые. При этом - ошибок нет. В буфере мы видим наши данные, ошибки не копятся, ибо модуль ответил и все ок.
IF Mdl.ExecStep = 1 THEN
FOR CurrentCon:=1 TO 7 DO

Mdl.pDisp^.GetInputRegs(Enable:= NOT Mdl.pDisp^.GetInputRegs.Read,
Mode:= MB_RTU,
DevAddr:= Mdl.Base.Adress,
FirstAddr:= StartRegister1 + ((CurrentCon-1)*6),
Quantity:= RegisterCount,
ComHandle:= Mdl.pDisp^.Settings.Port,
TimeOut:= Mdl.Base.TimeOut,
Buffer:= Mdl.pDisp^.ReciveBuffer);

IF Mdl.pDisp^.GetInputRegs.Complete THEN
tmpReadError := Mdl.pDisp^.GetInputRegs.Exception;
IF tmpReadError = 0 THEN

pData := ADR(Mdl.dwDaikinRegisterRead); (*просто переменная, типа Слово, для текущего значения текущего кондея*)
pData^ := Mdl.pDisp^.ReciveBuffer[1];
pData := pData + 1;
pData^ := Mdl.pDisp^.ReciveBuffer[0];
Mdl.RCurTemp[CurrentCon]:=Mdl.dwDaikinRegisterRead; (* Пихаем полученные данные в объявленный массив из интов *)

ELSE

fcModuleAddAttempt(MdlBase := Mdl.Base);

IF Mdl.Base.CurrentAttempt > Mdl.Base.MaxAttempts THEN
Mdl.ExecStep := CompleteExecStep;
END_IF;
END_IF;
END_IF;
END_FOR;
Mdl.ExecStep:=Mdl.ExecStep+1;
END_IF;

Однако, если мы убираем цикл, опрашивая один регистр, на примере:
CurrentCon:=1;
IF Mdl.ExecStep = 1 THEN
Mdl.pDisp^.GetInputRegs(Enable:= NOT Mdl.pDisp^.GetInputRegs.Read,
Mode:= MB_RTU,
DevAddr:= Mdl.Base.Adress,
FirstAddr:= StartRegister1 + ((CurrentCon-1)*6),
Quantity:= RegisterCount,
ComHandle:= Mdl.pDisp^.Settings.Port,
TimeOut:= Mdl.Base.TimeOut,
Buffer:= Mdl.pDisp^.ReciveBuffer);

IF Mdl.pDisp^.GetInputRegs.Complete THEN
tmpReadError := Mdl.pDisp^.GetInputRegs.Exception;
IF tmpReadError = 0 THEN

pData := ADR(Mdl.dwDaikinRegisterRead);
pData^ := Mdl.pDisp^.ReciveBuffer[1];
pData := pData + 1;
pData^ := Mdl.pDisp^.ReciveBuffer[0];
Mdl.RCurTemp[CurrentCon]:=Mdl.dwDaikinRegisterRead;
CurrentCon:=CurrentCon+1;
Mdl.ExecStep:=Mdl.ExecStep+1;

ELSE

fcModuleAddAttempt(MdlBase := Mdl.Base);
IF Mdl.Base.CurrentAttempt > Mdl.Base.MaxAttempts THEN
Mdl.ExecStep := CompleteExecStep;
END_IF;
END_IF;
END_IF;
END_FOR;
END_IF;

(*Далее опрос следующего кондиционера на те же данные *)
IF Mdl.ExecStep = 1 THEN
CurrentCon:=2;
...

То после этого начинает все отличнейше работать. И можно было бы забить на циклы в целом, и на каждый регистр скопировать данный блок, но, исходя из того, что, в общей сложности 10 регистров * 7 койлов получается 70 блоков. Да и неаккуратно как-то.. Ткните, пожалуйста носом, что не так..

1exan
17.11.2023, 04:44
Как ни странно, приведя в пример шлюз дайкин - из 50+ устройств исключительно с ним больше всего приключений. В данный момент - не хочет опрашиваться в цикле. В чем суть - есть 5 регистров на чтение, 5 на запись. 7 файнкойлов. Каждый последующий койл хранит для себя данные, начиная от первого и +6 регистров. То есть, фактически, сводится к написанию 10 циклов For с параметром регистра StartRegister1 + ((CurrentCon-1)*6). Но, по каким-то причинам, данный шлюз так опрашиваться не хотит.. То есть, если мы пишем следующую конструкцию, то все данные у нас - нулевые. При этом - ошибок нет. В буфере мы видим наши данные, ошибки не копятся, ибо модуль ответил и все ок.
IF Mdl.ExecStep = 1 THEN
FOR CurrentCon:=1 TO 7 DO

Mdl.pDisp^.GetInputRegs(Enable:= NOT Mdl.pDisp^.GetInputRegs.Read,
Mode:= MB_RTU,
DevAddr:= Mdl.Base.Adress,
FirstAddr:= StartRegister1 + ((CurrentCon-1)*6),
Quantity:= RegisterCount,
ComHandle:= Mdl.pDisp^.Settings.Port,
TimeOut:= Mdl.Base.TimeOut,
Buffer:= Mdl.pDisp^.ReciveBuffer);

IF Mdl.pDisp^.GetInputRegs.Complete THEN
tmpReadError := Mdl.pDisp^.GetInputRegs.Exception;
IF tmpReadError = 0 THEN

pData := ADR(Mdl.dwDaikinRegisterRead); (*просто переменная, типа Слово, для текущего значения текущего кондея*)
pData^ := Mdl.pDisp^.ReciveBuffer[1];
pData := pData + 1;
pData^ := Mdl.pDisp^.ReciveBuffer[0];
Mdl.RCurTemp[CurrentCon]:=Mdl.dwDaikinRegisterRead; (* Пихаем полученные данные в объявленный массив из интов *)

ELSE

fcModuleAddAttempt(MdlBase := Mdl.Base);

IF Mdl.Base.CurrentAttempt > Mdl.Base.MaxAttempts THEN
Mdl.ExecStep := CompleteExecStep;
END_IF;
END_IF;
END_IF;
END_FOR;
Mdl.ExecStep:=Mdl.ExecStep+1;
END_IF;

Однако, если мы убираем цикл, опрашивая один регистр, на примере:
CurrentCon:=1;
IF Mdl.ExecStep = 1 THEN
Mdl.pDisp^.GetInputRegs(Enable:= NOT Mdl.pDisp^.GetInputRegs.Read,
Mode:= MB_RTU,
DevAddr:= Mdl.Base.Adress,
FirstAddr:= StartRegister1 + ((CurrentCon-1)*6),
Quantity:= RegisterCount,
ComHandle:= Mdl.pDisp^.Settings.Port,
TimeOut:= Mdl.Base.TimeOut,
Buffer:= Mdl.pDisp^.ReciveBuffer);

IF Mdl.pDisp^.GetInputRegs.Complete THEN
tmpReadError := Mdl.pDisp^.GetInputRegs.Exception;
IF tmpReadError = 0 THEN

pData := ADR(Mdl.dwDaikinRegisterRead);
pData^ := Mdl.pDisp^.ReciveBuffer[1];
pData := pData + 1;
pData^ := Mdl.pDisp^.ReciveBuffer[0];
Mdl.RCurTemp[CurrentCon]:=Mdl.dwDaikinRegisterRead;
CurrentCon:=CurrentCon+1;
Mdl.ExecStep:=Mdl.ExecStep+1;

ELSE

fcModuleAddAttempt(MdlBase := Mdl.Base);
IF Mdl.Base.CurrentAttempt > Mdl.Base.MaxAttempts THEN
Mdl.ExecStep := CompleteExecStep;
END_IF;
END_IF;
END_IF;
END_FOR;
END_IF;

(*Далее опрос следующего кондиционера на те же данные *)
IF Mdl.ExecStep = 1 THEN
CurrentCon:=2;
...

То после этого начинает все отличнейше работать. И можно было бы забить на циклы в целом, и на каждый регистр скопировать данный блок, но, исходя из того, что, в общей сложности 10 регистров * 7 койлов получается 70 блоков. Да и неаккуратно как-то.. Ткните, пожалуйста носом, что не так..

Не получится использовать цикл FOR, т.к. опрос каждого регистра занимает некоторое время, а вы пытаетесь за ОДИН программный цикл ПЛК опросить сразу ВСЕ регистры.
Во втором случае у вас счётчик CurrentCon инкрементируется только после завершения предыдущего запроса, что конечно правильно

Easy_Enemy
17.11.2023, 18:08
Не получится использовать цикл FOR, т.к. опрос каждого регистра занимает некоторое время, а вы пытаетесь за ОДИН программный цикл ПЛК опросить сразу ВСЕ регистры.
Во втором случае у вас счётчик CurrentCon инкрементируется только после завершения предыдущего запроса, что конечно правильно

Да, там, по документации получается, что-то типа 2 по 2,5 мс на чтение/формирование ответа и по 20мс на запрос-ответ, просто странно как-то.. фактически же одно и тоже, мы ничего лишнего не обрабатываем между перемещением к следующему регистру.. уж не на 45 мс.. При этом, мы же ждем обработку данных (IF Mdl.pDisp^.GetInputRegs.Complete THEN), или я что-то путаю? В довесок - при опросе через цикл - у нас прям все данные - нули и, если я правильно понимаю, даже, если шлюз не успевает ответить - как минимум первое значение мы же должны были получить?..

Ну и, с точки зрения опыта - есть, может быть, у кого-то мысли, как сделать правильно в данной ситуации?.. Получается, железка довольно медленная, информации с нее - много. Опрос получается нереально долгим.. Уже придется делить не то, что "сейчас - чтение, в следующее обращение - запись", а, прям "один цикл - один кондей"

Пробовал переиначить, выбросив FOR, использовав IF CurrentCon <> 7 ... CurrentCon:=CurrentCon+1; в конце обработки данных, что, по-сути около-одно и тоже, с другой стороны - не понимаю, чем использование "следующего шага" отличается настолько, что с ним все преображается..

kondor3000
17.11.2023, 19:17
Да, там, по документации получается, что-то типа 2 по 2,5 мс на чтение/формирование ответа и по 20мс на запрос-ответ, просто странно как-то.. фактически же одно и тоже, мы ничего лишнего не обрабатываем между перемещением к следующему регистру.. уж не на 45 мс.. При этом, мы же ждем обработку данных (IF Mdl.pDisp^.GetInputRegs.Complete THEN), или я что-то путаю? В довесок - при опросе через цикл - у нас прям все данные - нули и, если я правильно понимаю, даже, если шлюз не успевает ответить - как минимум первое значение мы же должны были получить?..

Ну и, с точки зрения опыта - есть, может быть, у кого-то мысли, как сделать правильно в данной ситуации?.. Получается, железка довольно медленная, информации с нее - много. Опрос получается нереально долгим.. Уже придется делить не то, что "сейчас - чтение, в следующее обращение - запись", а, прям "один цикл - один кондей"

Пробовал переиначить, выбросив FOR, использовав IF CurrentCon <> 7 ... CurrentCon:=CurrentCon+1; в конце обработки данных, что, по-сути около-одно и тоже, с другой стороны - не понимаю, чем использование "следующего шага" отличается настолько, что с ним все преображается..

Может пример вам поможет, как считать 280 регистров с 7 блоков за 30-80 ms. Чтение и запись надо разнести по шагам CASE.
https://owen.ru/forum/showthread.php?t=10555&page=987
https://owen.ru/forum/showthread.php?t=10555&page=988#9876

Easy_Enemy
17.11.2023, 19:38
Может пример вам поможет, как считать 350 регистров с 7 блоков за 30-80 ms. Чтение и запись надо разнести по шагам CASE.
https://owen.ru/forum/showthread.php?t=10555&page=987
https://owen.ru/forum/showthread.php?t=10555&page=988#9876

Насколько я понял, тут общение происходит через входы/выходы самого плк? По ним не было проблем, тоже довольно шустрый, в моей случае -160М02, управляет парогенератором, воздушными заслонками и частью вентиляции. Без нареканий. Как и овеновские модули, кстати - по модбас - никаких нареканий в нестабильности работы. А вот дайкиновская железяка (на секундочку - за 4.800 евро) прям расстроила.. Тогда, примем, как факт невозможность опроса в цикле..

Спасибо за помощь!

kondor3000
17.11.2023, 19:40
Насколько я понял, тут общение происходит через входы/выходы самого плк? По ним не было проблем, тоже довольно шустрый, в моей случае -160М02, управляет парогенератором, воздушными заслонками и частью вентиляции. Без нареканий. Как и овеновские модули, кстати - по модбас - никаких нареканий в нестабильности работы. А вот дайкиновская железяка (на секундочку - за 4.800 евро) прям расстроила.. Тогда, примем, как факт невозможность опроса в цикле..

Спасибо за помощь!

Опрос 7 модулей МВ110-8АС по Модбас, с помощью String через структуру. Через String можно ещё и записывать (если надо)

Валенок
17.11.2023, 20:02
.. . Тогда, примем, как факт невозможность опроса в цикле..
Просто Вы немного неправильно понимаете термин "цикл". Точнее - у вас в голове совместилось понятие цикла плк и цикла опроса. Про case вам выше говорили.