Добрый день.
Посмотрел бегло Ваш проект.
Пока не понятно следующее в модуле MB110-16D:
1. Режим опроса - MB_ASCII. Это сознательно или не точность.
2. Опрашиваете 2 регистра, хотя для размещения 16 бит достаточно 1-го.
Вид для печати
От пинка Валенка в модуле MB110-16D я все-таки разобрался. (Набираюсь опыта еще с библиотечным опросом).
Намеренно, хочется еще прикрутить ТРМы, а они виснут от RTU опроса.Цитата:
Режим опроса - MB_ASCII. Это сознательно или не точность.
Вообще раньше пользовался стандартным конфигуратором. А сейчас предстоит линию обвешать 26 устройствами (модули и трм), поэтому и пытаюсь перейти на библиотеку.
Ваш проект выглядит интересным вот и на нем и решил остановиться.
Спасибо за ответ.
Кирилл, добрый вечер! Уже год назад использовал ваш диспетчер на одном из проектов, всё до сих пор автономно работает 24/7. Сейчас делаю проект для своего дома, а доступа к наработкам и прошлым проектам нет, потому что поменял место работы. Можете поделиться модулями, которые вы уже написали, кроме тех, что в библиотеке?
mastrik, добрый день.
Я уже писал, что основная цель выкладывания библиотеки - это желание поделиться опытом.
Важен сам подход к организации опроса.
Поэтому чтобы не "захламлять" различными модулями сути я и не выкладываю все что есть. Тем более, что в более сложных модулях, например, частотниках, мне может понадобиться (для моих задач) читать одни регистры, другим совсем другие регистры.
Да, я помню это. И в прошлый раз ничего не просил у вас, тем более, что вы подсказали в каком направлении работать, чтобы формировать собственные запросы на чтение и запись. А теперь я в больнице и прохожу уже 5-й курс химиотерапии, поэтому голова варит плохо, да и железо из дома сюда взять нельзя, а на симуляторе отлаживать работу по модбасу невозможно, хотел пока есть время почитать код ваших модулей, чтобы минимизировать свои ошибки.
как с помощью вашей библиотеки получить данные с плк мастер --> на плк слейв на адрес регистра 256, 512, 514, 768? word
введу в курс дела, ему нужны решения и только конкретика, поэтому в Вашем ответе нет ни чего, чтобы ему помогло. Предлагаю ответить на главный вопрос, программный слейв возможен?
К моему великому сожалению эта штуковина не заработала с библиотекой OwenModbusSlave.
Отдельно обе работают.
Попробовал слэйв для панели сделать через бибку, тк в ранее несколько раз перебивал более 500 переменных в конфигураторе и почти истерику получил.
В этот раз решил библиотеку взять. Так приятно работать стало.
-ПЛК110М2
-На панель подаю через порт RS232.
Опрос веду или с порта "0" или с "2" (без разницы).
-При использовании конфигуратора мастера и бибки слэйв всё работает.
-Слэйв и Мастер Библиотечные вместе не пашут, хотя в порты разные стучатся.
Сейчас проблема не важна, тк надо 6 регистров читать.
Но весной, при расширении пр-ва будут переделки с кучей слейвов и с панелями.
Очень хочется всё сделать бибками, чтоб упростить переделки и заложить нормальную возможность модернизации.
Плюс будет сеть прокинута, и всё на скаду и в облако буду затаскивать.
Может посоветуете чего? (*вникать в дебри сам не успеваю, тк мне и подбирать, и чертить, и собирать, и программировать, и налаживать, и обслуживать приходится.*)
К сожалению, не знаком с библиотекой OwenModbusSlave, поэтому тяжело сказать почему они вместе не заработали.
В целом нужно понимать, что моя библиотека решает один простой вопрос - очередность доступа к последовательному порту.
Почитал документацию, посмотрел пример, но не понял, возможно ли использовать диспетчер для управления модулями используя два слота сети RS485-1 и RS485-2?
утром как раз проверял эту возможность.
Объявил два диспетчера с разными портами и скоростью.
К каждому в PLC_PRG привязал нужные модули.
Работают.
Мучения были только в получении МУ-16Р из МУ-32Р.
теперь нужно их подружить с OwenModbusSlave и я буду счастлив.
И так, родил я в муках модуль fcMB110_4TD (на последнем этапе сильно помогла тема ).
Буду рад предложениям по более удобному, чем битовая маска (2#0001_1111) заданию считываемых входов. На панели то это будет красиво(если надо). Но прога должна быть понятна любому, кто после меня туда влезет.
На fcMB110_8A тоже добавлю выбор считываемых входов, мне кажется это полезным.
Так же мне не нравится использовать WORD для получения диагностической информации. не информативно биты через точку вызывать. Конечно можно так: ErrAI2:= Diag.1, но опять лишние сущности. Фу! У меня и так все проекты в этих призраках, не могу никак избавиться от них.
Идеалом было бы на одно значение использовать одну ячейку памяти и для приёма, и для обработки, и для передачи на панель, и для передачи на скаду. Но пока не разобрался с жонглированием указателями, а "ADR" не даёт нужного, если его в структуру пихать.
На очереди связь с частотником (передача/приём) fcEI_7012, fcE4_8400, fcE3_8100, и модуль ввода/вывода fcMK_8DN4R. Если у кого-то есть наработки, буду рад с ними ознакомиться.
Заметил странное поведение ModBusSlave, заливаю проект onlinechange, стоп, сброс, старт - и функция выдаёт ошибку настроек порта.
Создаю загрузочный проект, перезагружаю - всё работает. В чём может быть проблема?
Тестовый проект во вложении.
Почему-то не меняется время опроса ставлю 500мс и 1000мс, всё равно опрос идёт с частотой 100мс (на глаз).
Второе, что не понял, для чего в опросе модулей используются шаги (step). Ведь всё равно опрос прописан так, что команды опроса следуют друг за другом...
Пробую опросить модуль RL_I (это реле с двумя дискретными входами), в котором используются команды Modbus 05(управление реле), 02(опрос входов), 01(состояние реле). Прописал в опросе шаг1 - 05, шаг2 - 01, шаг3 - 02. В результате работает только Шаг1, остальные игнорятся почему-то.
Может для корректной работы необходимо данный модуль разделить на три? И в каждом использовать нужную функцию по отдельности...
Попробовал опросить каждой функцией отдельно. По отдельности работают. Причём настройки портов и опроса не меняю (500мс) - 02 функция опрашиватся 500мс, а 01 и 05 - 100мс.
Вобщем пока не понимаю как опросить один и тот же модуль разными Modbus функциями. Разделить на три модуля не получается т.к. адрес один и тот же - диспетчер не пропускает...
Возможно есть другой способ опроса... Для опроса по трём функциям сделал в основном цикле такую конструкцию:
В соответсвующей функции опрашиваю модуль также оператором case - передаю из основной программы посредством RL1.FUN.Код: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
Так теперь работает.
Должен меняться. Вы точно меняете PollingTime, а не ValidPollingTime, например?
Как правило опрос в модулях организован следующим образом (для модулей ввода):
1. На 1-м шаге вызываем соответствующую функцию опроса. Когда она завершила работу (Complete=true) анализируем результат и либо повторяем шаг 1 или идем на следующий.
2. На 2-м шаге, если нужно опрашиваем другие регистры этого же модуля, если нужно другой функцией. Когда функция завершила работу (Complete = true) анализируем результат и либо повторяем шаг или идем на следующий.
...
N. На заключительном шаге выполняем различные сервисные функции. В частности: статистика, сообщаем диспетчеру, что опрос завершен.
Да, но судя по коду (в примерах), насколько я понял, эти шаги исполняются один за другим, за одну итерацию - если это так, то смысла в Step не вижу. Это же не оператор Case. Следуя примеру, я так и сделал для описания своего модуля (реле с управлением), использовал Step. В результате модуль опрашивался реже и реже, .пока вообще перестал опрашиваться, причём опрос происходил только по первой описываемой функции, вторая и третья по очереди (были разнесены на разные Step) не опрашивались Read у них висел всё время в False. После чего я описал модуль оператором Case, параметр для оператора передавал из основной программы - так опрос пошёл по всем трём функциям, только пришлось подобрать тайминги выполнения каждой из них, поскольку, к примеру, срабатывание реле не происходило, если обращение функции происходило меньше 1 сек.
Хотя... смысл в Step понятен, но тогда получается, что ещё нужно описать задержки между опросами разных функций. Т.к. мой модуль отказывается опрашиваться...Причём, в моём случае эти задержки различны по времени.
Столкнулся с такой же проблемой при опросе частотника, пишет, но не читает, при чтении выдаёт ошибку таймаута. до того, как концовку переделал, диспетчер ещё после каждого неудачного чтения увеличивал время опроса.
Мне вот такой костыль не подходит, особенно задержки такие страшные, тк желаемый период опроса не более 100мс. если так и не получится в одном модуле и управлять и считывать, то разделю, можно будет поставить 50мс и 200мс соответственно. Но такой себе вариант дробить функцию.
* но диспетчер хитрый, не даёт две функции с одним адресом использовать. попробую это устранить.
Даже разделение функций не помогает.
Если только читать - всё чётко и без ошибок. Если только писать - всё чётко и без ошибок. если и читать и писать, то только пишет, но частые ошибки таймаута, а чтение постоянно висит в ошибке таймаута.
Может подскажете, где искать проблему?
Попробую другой модели частотник помучить, вдруг что-то изменится.
Что значит за одну итерацию?
Мы переходим на следующий Step, только, когда получили ответ, что опрос закончен, т.е. Complete = true.
Если ваш модуль неповоротливый и не может сразу после обработки одного запроса, тут же отвечать на другой, тогда сделайте "пустой" шаг, на котором просто ждите определенное время (100, 200 мс).
А вот параметр для case передавать из основной программы - это идеологически неверно! Модуль сам решает, как опрашивать свои регистры! Зачем еще что-то писать в основной программе!???
Скорее всего или ошибка в запросе чтения или частотник у вас неповоротливый (см. пост выше).
Увеличивает время опроса не диспетчер, а сам модуль (в функции fcModuleBase). Это механизм для устранения отказавших модулей из сети, чтобы сеть не подвисала.
Если не хотите, что бы время опроса для данного модуля при ошибках увеличивалось просто сделайте настройку MaxPollingTime равной pollingTime и все.
Диспетчер специально не допускает 2-х модулей с разными адресами. Можно, конечно, убрать эту проверку из диспетчера, но идеологически правильно делать по-другому. А именно, когда модуль получил право на опрос он сам решает, как опрашивать физический модуль. Например, он может после записи сделать паузу (например, с помощью "пустого" шага), перед опросом.
Можно сделать так, что модуль получив право на опрос один раз пишет, в другой раз читает. И он (модуль!) сам запоминает, что он делал в предыдущий раз - читал или писал.
Спасибо! Помогло!
Несколько часов пробовал разнести функции во вызовам, пришлось в структуру модуля переменную добавить и научиться ей управлять.
Так же пришлось понять, какие команды подавать, чтоб каждый вызов правильно начинался и завершался. По циклам смотрел происходящее, чтоб понять, почему диспетчер клинит. Жаль, что функции нельзя мониторить.
В итоге получил рабочий модуль E4_8400. Осталось другие допилить.
Также добавил "EN" в базовую структуру, отсутствие этого сигнала через обработчик базы заставляет модули прикидываться вечными ждунами. Мне иногда нужно выводить модули из опроса.
У вас очень полезный и гибкий инструмент получился! Осталось до конца его понять, и можно по аналогии (подход) все проги перепиливать. ;)
* вопрос на засыпку: могу ли я менять скорость работы порта при вызове модуля? например одно устройство опрашивать на скорости 9600, другое на 19200 с одного порта?
Тогда стоит попробовать чтение и запсись делать при разных вызовах. У меня работает прекрасно. Частотники со скоростью 9600 опрашиаваются каждые 25мс (общий опрос получается 50мс), работает чётко.
*эксперименты со сменой скорости порта на лету закончились неудачей. Но это не беда. Ведь мы имеем два порта, один можно для быстрых а другой для медленных устройств, типа частотников. С ними мало данных нужно, так что и так успеют опроситься.
Настройка порта происходит на шаге dispOpeningPort в диспетчере, на который (шаг) мы уже более не возвращаемся, побывав там однажды. Если опрашивать модули на разных скоростях, то соответственно нужно, повторно настраивать порт на другую скорость.
Одним словом, такая возможность не предусмотрена в текущей реализации.
И так, методом страшнейших мучений и научного тыка я сделал из модулей fcE4_8400 fcMB110_32DN fcMY110_16P модуль MK110_8DN4R.
Было настоящей пыткой разбираться в коде без комментариев, как понял работу, так и написал комменты в своём модуле. Особо сложно было врубиться в обработчик счётчиков модуля 32ДН.
Когда это победил, получил проблемы с переносом данных из буфера.
Долго искал, предположил, что есть перекрытие областей памяти, немного изменил порядок в структуре модуля и модуль полностью заработал.
Меня учили, что современный код, практически не нуждается в комментариях.
Комментарии нужны были преимущественно тогда, когда писали на ассемблере. В настоящее время есть возможность давать любые имена переменным, поэтому хорошо продуманное именование переменных практически полностью заменяет комментарии.
А вот и нет. Скинул фотку кода программеру знакомому, который у нас в ЦПС работает, на оборонку. Их отдел на Си пишет. Так этот человек ужаснулся "а где комментарии!".
Как бы не были названы переменные, всегда полезно знать, а чего хотел автор тут сделать, почему именно так сделал (часто варианты разные бывают, иногда другие варианты к краху приводят).
Т.к. я задел больную тему, мы минут 10 обсуждали полезность комментариев и необходимость подробной документации к модулям.
Вам то понятно, но другие то откуда знают, что происходит? Это нужно долго и мучительно просматривать связи, документацию на железо, затем тестировать и смотреть, "а что будет?".
Вот листал я темы, как real получить. Этот вездессущий ОВЕН так да сих пор и неудосужился дать нормальное описание. Спасибо хоть супермодератору за видосик для CS3.5, и тот без комментариев к пачке указателей :-( (пока допёрло, что там за жонглирование, время много прошло).
Один только Сазар там пытался этим ТруКодерам растолковать, какие описания должны быть: берём вот это, вот так кладём сюда, вот так потому-что ... , получаем вот это.
Ведь не понятно даже, почему из буфера извлекаются данные с перемешиванием. Видно только, что это работает, значит так надо.
Местами я пишу (цитаты по памяти): "Необходимо заново сформировать буфер", "Чтобы потом не проверять указатели" и т.д. Т.е. какие-то важные места я комментирую.
Это первое.
Второе. Думаю, что ваш товарищ работает в команде и комментарии нужны скорее другим.
Тут я писал для себя. И только потом решил выложить свои труды.
Да, для других комменты.
могу позавидовать вашей памяти!
Я через год открываю какой то проект, и если не написал ранее, что и зачем я сделал, то идёт мучительное разбирательство, (а это что, а нафига, а как это вобще у меня работает, а почему я так сделал, можно же упростить... а, нет, нельзя, всё рушится)
Поймал странный глюк, который нагуглить не смог. Вчера вечером всё работало, а сегодня модуль fcEI_7012(FC1) отказался работать. Судя мо mdlErr - ошибка 251 (mdlDispIsNullError), и вот эту ошибку не нарыл в описании овеновском modbus.lib и syslibcom, и гуглем, и поиском по форуму.
Ладно... объявил fcEI_7012(FC3), туда пихнул целевой адрес, а на FC1 левый. загрузочный проект->перезагрузка = работает скотина! удалил FC1 -> загрузочный проект->перезагрузка = работает скотина!
Что это было я так и не понял. Ведь я ничего не поменял, просто переобъявил под новым именем. НО! вечером работало после перезагрузок, а на следующий день не захотело.
Если это залётная ошибка, то фиг с ней, а вот если такое периодически будет, то меня интегрируют в систему управления.
Вот как этого беднягу:
Этот то заработал (Disp1), а вот Disp0 встрял на модуле MK110 и сидит. Чертовщина. Только что работал.
О, всё само заработало после перезалива и перезагрузки. я только сделал, чтоб MK110 сразу в ожидание встал после загрузки, пустил в опрос чуть позже.
Очень пугает такое.
Ошибка mdlDispIsNullError устанавливается в функции fcModuleDispVerification (она входит в библиотеку) - смотрите вот это место:
IF pDisp = Null THEN
MdlBase.Error := mdlDispIsNullError;
fcModuleDispVerification := FALSE;
RETURN;
END_IF;
И означает, что в модулей не настроен указатель на диспетчер.
Я посмотрел вы инициализируете сеть правильно.
Не знаю как такое могло произойти.
Тут анализируйте свой модуль.
Для уверенности могу сказать, что у меня на десятках объектов 24/7 все пашет идеально.