PDA

Просмотр полной версии : Вопрос по библиотеке Modbus.lib



a_gricaj
17.09.2016, 20:45
Здравствуйте!

Решил попробовать эту библиотеку для организации сетевого обмена. Модули у меня МДВВ.
Подключил два модуля - читать их получается, а вот записать в регистры нет.
Блок MB_WR_REGS выдает ошибку 3:
26432

Мой код:
Раздел описания:

FUNCTION_BLOCK Comm
VAR_INPUT
END_VAR
VAR_OUTPUT
END_VAR
VAR
ModbusAdrDi11,ModbusAdrDi12: MB_RD_HOLD_REGS;
ModbusAdrDo11,ModbusAdrDo12:MB_WR_REGS;

BufferIN: ARRAY[0..255] OF BYTE;
BufferOUT: ARRAY[0..255] OF BYTE;
cmpl: BOOL;
port_opened: BYTE := 0;
Init: BOOL;
Settings:COMSETTINGS;
com_num: PORTS:=0;
enabl: BOOL;

Error, ErrorDI11,ErrorDO11,ErrorDI12,ErrorDO12: INT;
TimeOut: TIME:=T#100ms;
Exception: BYTE;
DataSize: WORD;
master1: BYTE:= 1;

WordAdr11,WordAdr12:WORD;

COM_SERVICE1: COM_SERVICE;

END_VAR

код:


IF port_opened=0
THEN
Settings.Port:=com_num;
Settings.dwBaudRate:=115200;
Settings.byParity:=0;
Settings.dwTimeout:=0;
Settings.byStopBits:=0;
Settings.dwBufferSize:=0;
Settings.dwScan:=0;
END_IF

COM_SERVICE1(Enable:=(port_opened=0) , Settings:=Settings , Task:=OPEN_TSK );


IF COM_SERVICE1.ready THEN port_opened:=2; END_IF
IF port_opened=2 THEN

CASE master1 OF
0:
ModbusAdrDi11(
Enable:=enabl ,
Mode:=MB_RTU ,
DevAddr:=11 ,
FirstAddr:=51 ,
Quantity:=1,
ComHandle:=Settings.Port ,
TimeOut:=TimeOut ,
Buffer:=BufferIN ,
Complete=>cmpl ,
Exception=>ErrorDI11 ,
ByteCnt=>DataSize );

IF cmpl
THEN
IF ErrorDI11=0
THEN
WordAdr11:=BYTE_TO_WORD(BUFFERIN[1]) OR SHL(BYTE_TO_WORD(BUFFERIN[0]),8);
END_IF
master1:=1;
END_IF

1:
ModbusAdrDi12(
Enable:=enabl ,
Mode:=MB_RTU ,
DevAddr:=12 ,
FirstAddr:=51 ,
Quantity:=1,
ComHandle:=Settings.Port ,
TimeOut:=TimeOut ,
Buffer:=BufferIN ,
Complete=>cmpl ,
Exception=>ErrorDI12 ,
ByteCnt=>DataSize );

IF cmpl THEN
IF ErrorDI12=0
THEN
WordAdr12:=BYTE_TO_WORD(BUFFERIN[1]) OR SHL(BYTE_TO_WORD(BUFFERIN[0]),8);
END_IF
master1:=2;
END_IF

2: ModbusAdrDO11(
Enable:= enabl,
Mode:= MB_RTU,
DevAddr:= 11,
FirstAddr:= 50,
Quantity:= 1,
ComHandle:= Settings.Port,
TimeOut:= TimeOut,
Buffer:= BufferOUT,
Complete=> cmpl,
Exception=> ErrorDO11,
RegCnt=> DataSize);

IF cmpl THEN
master1:=0;
END_IF
END_CASE

IF enabl = FALSE THEN
enabl := TRUE;
END_IF(*
IF ErrorDI11<> 0 OR ErrorDI12<> 0 OR ErrorDO11<> 0 OR ErrorDO12<> 0 THEN
enabl := FALSE;
END_IF
*)
END_IF


Что я делаю неправильно, и как записать байт в регистр мдвв??
Объясните пожалуйста зачем в блоке MB_WR_REGS вход buffer имеет тип данных ARRAY[0..255] OF BYTE;

KSergey
17.09.2016, 21:34
Доброй ночи!
Попробуйте записать 1000 в регистр 00 (выход1). По-моему 50 регистр - чтение маски выходов.

a_gricaj
17.09.2016, 21:37
Доброй ночи!
Попробуйте записать 1000 в регистр 00 (выход1). По-моему 50 регистр - чтение маски выходов.

Доброй ночи, в мдвв 51 регистр чтение маски входов, а 50 запись маски выходов - ну, вроде так в документации на мдвв.... ща еще раз проверю...

a_gricaj
17.09.2016, 21:42
Доброй ночи, в мдвв 51 регистр чтение маски входов, а 50 запись маски выходов - ну, вроде так в документации на мдвв.... ща еще раз проверю...

Чуть чуть бред написал так как из документации: "Запись в регистры осуществляется командой 16 (0х10), чтение – командами 03 или 04 (прибор
поддерживает обе команды)." А регистр 50 - выходы....

KSergey
17.09.2016, 21:43
Примечания
1. Запись в регистры осуществляется командой 16 (0х10), чтение – командами 03 или 04 (прибор
поддерживает обе команды).
2. Обнуление счетчиков делается записью 0 в регистры хранения результатов счета.
3. В регистрах битовых масок значений входов и выходов старший бит соответствует входу или выходу с
наибольшим номером: (бит, равный 1, соответствует состоянию выхода «Включено» и входа «Замкнут»).

Пункт 3. СОСТОЯНИЕ выхода.
Всё же попробуйте 00-07.

a_gricaj
17.09.2016, 21:58
26433
Я уже не знаю как записывать правильно.... думаю проблема с записью на вход buffer ARRAY[0..255] OF BYTE;

KSergey
17.09.2016, 22:17
Попробуйте
BufferOUT[0]:=1;
BufferOUT[1]:=0;
Должен первый выход включиться, если 50-й регистр на запись.

a_gricaj
17.09.2016, 22:21
Попробуйте
BufferOUT[0]:=1;
BufferOUT[1]:=0;
Должен первый выход включиться, если 50-й регистр на запись.

В таком случае все выходы отключены, Error скакает с 0 на 255 и обратно....

А 50 точно, вот:
5.1.2 Работа по протоколу ModBus
Работа по протоколу ModBus может идти в режимах ASCII или RTU, в зависимости от
заданного значения параметра Prot.
Скважность ШИМ записывается в регистры, соответствующие каждому из дискретных ВЭ.
Запись осуществляется командой 16 (0x10), чтение – командами 3 (0x03) или 4 (0x04). Список
регистров протокола ModBus приведен в Приложении В (таблица В.4).
Посылка групповой команды включения/выключения ВЭ осуществляется в регистр с
номером 50 (0x32). В регистр записывается значение от 0 до 255, каждый бит значения
соответствует состоянию дискретного ВЭ прибора. Единичное значение бита соответствует
состоянию «Включено» для ВЭ.

KSergey
17.09.2016, 22:32
За 50-й извиняюсь.
Посылка групповой команды включения/выключения ВЭ осуществляется в регистр с
номером 50 (0x32).
Как вариант, закрывать блоки после успешного чтения-записи:
if cmpl then
..
ModbusAdrD...(Enable:=false);
master1:=..;
end_if;

a_gricaj
17.09.2016, 22:47
За 50-й извиняюсь.
Посылка групповой команды включения/выключения ВЭ осуществляется в регистр с
номером 50 (0x32).
Как вариант, закрывать блоки после успешного чтения-записи:
if cmpl then
..
ModbusAdrD...(Enable:=false);
master1:=..;
end_if;

непомогло, все выходы отключены.....
вот еще заметил:
26434

KSergey
17.09.2016, 23:12
Может быть выполнить работу с Com-портом не в ФБ, а в отдельной PRG с собственным циклом? Проще отслеживать будет.

a_gricaj
17.09.2016, 23:20
Может быть выполнить работу с Com-портом не в ФБ, а в отдельной PRG с собственным циклом? Проще отслеживать будет.
Как здесь (пост № 154 http://www.owen.ru/forum/showthread.php?t=21940&page=16&highlight=modbus.lib) ???????

Тогда вопрос как все правильно разнести если у меня 54 модуля МДВВ, примерно по 27 на каждый из портов RS485 контроллера ПЛК 110-220.60

KSergey
17.09.2016, 23:42
Мне кажется, разнести в любом случае. Во-первых: сократится периодичность опроса каждого модуля по отдельности, а во-вторых: если я не ошибаюсь, то советуют использовать репитеры после каждых 32 приборов на RS-485.

a_gricaj
17.09.2016, 23:57
Мне кажется, разнести в любом случае. Во-первых: сократится периодичность опроса каждого модуля по отдельности, а во-вторых: если я не ошибаюсь, то советуют использовать репитеры после каждых 32 приборов на RS-485.

Ну репитер думаю мне не нужен, так как все модули будут рядышком возле контроллера по 27 шт на каждый из двух портов контроллера, а вот как разнести правильно программно опрос: например если брать 27 модулей на одном порту, это получается 27 слов - чтение входов и 27 байт - запись выходов, которые кстати не получается еще и записать.
Может правильно разнести так:
1 функциональный блок инициализация порта RS485-1;
2 функциональный блок инициализация порта RS485-2;
3 функциональный блок чтение модулей на порте RS485-1 - 27 слов;
4 функциональный блок чтение модулей на порте RS485-2 - 27 слов;
5 функциональный блок запись в модули на порте RS485-1 - 27 байт;
6 функциональный блок запись в модули на порте RS485-2 - 27 байт;

а есть же еще два порта RS232, на них же тоже можно наверное вешать преобразователь RS232<=>RS485 и тоже опрашивать модули???
Как тут поступить????????????????????????????????????????

KSergey
18.09.2016, 00:09
Был проект на ПЛК-110.60, где использовались модули МВ110-32ДН, МУ110-8Р и МВ110-8АС, общим количеством 13 штук. Все на одном порту RS-485. Опрос организовал через конфигуратор. Работает нормально, но там было не критично время задержки. Примерно раз в секунду данные обновляются. Здесь же все модули дискретные, поэтому всё зависит от поставленной задачи, а так, скорость обмена будет нормальной.
64 регистра в общем вышло.
И да, запись производится тоже словами, а не байтами, там просто в одном байте управление, а второй всегда нулю равен.

a_gricaj
18.09.2016, 00:14
Был проект на ПЛК-110.60, где использовались модули МВ110-32ДН, МУ110-8Р и МВ110-8АС, общим количеством 13 штук. Все на одном порту RS-485. Опрос организовал через конфигуратор. Работает нормально, но там было не критично время задержки. Примерно раз в секунду данные обновляются. Здесь же все модули дискретные, поэтому всё зависит от поставленной задачи, а так, скорость обмена будет нормальной.

Секунда очень много, на модули заведены датчики скорости - дает импульс на вход, количество импульсов считается, за секунду примерно - импульсов пять нужно успеть считать......, а счетчики в самих модулях это еще хуже.....

capzap
18.09.2016, 08:06
Секунда очень много, на модули заведены датчики скорости - дает импульс на вход, количество импульсов считается, за секунду примерно - импульсов пять нужно успеть считать......, а счетчики в самих модулях это еще хуже.....

Вас почему всех так тянет спросить способ совершить невозможное? Пять импульсов в секунду это минимум потребуется сделать 10 запросов в секунду,а это 100мс из них на запрос уходит примерно 20мс, так возможно опросить всего пять модулей, ну даже пускай десять,этого все равно не достаточно

a_gricaj
18.09.2016, 09:05
Вас почему всех так тянет спросить способ совершить невозможное? Пять импульсов в секунду это минимум потребуется сделать 10 запросов в секунду,а это 100мс из них на запрос уходит примерно 20мс, так возможно опросить всего пять модулей, ну даже пускай десять,этого все равно не достаточно

Сеть собирал не я - мне нужно переделать после другого программиста, а она собрана повторюсь 54 шт мдвв. Мне нужно "вытянуть" максимум по просу. Ну может 5 секунд я и загнул конечно. Вот и спрашиваю совет, как правильно все организовать.,
Подскажите пожалуйста как правильно записать байт в 50 регистр МДВВ (см. посты выше).

KSergey
18.09.2016, 11:26
Секунда очень много, на модули заведены датчики скорости - дает импульс на вход, количество импульсов считается, за секунду примерно - импульсов пять нужно успеть считать......, а счетчики в самих модулях это еще хуже.....

Похоже, всё таки придётся со счётчиками работать, если точность нужна.

a_gricaj
18.09.2016, 11:56
Похоже, всё таки придётся со счётчиками работать, если точность нужна.
Счетчиков потребуется примерно пол сотни, а это дополнительная нагрузка на обмен, все таки дополнительно читать еще 50 регистров, придется жертвовать точностью в сторону скорости.

Я уже реализовал подобный объект, правда управление без контроллера с МастерСкада и модулей 23 шт. и не МДВВ, а МВ. Счетчики не использовал - то в принцпе устраивает, да импульсы иногда пропускает - но не критично.

Так себе думаю, получается все 54 модуля нужно разделить на 4 порта ( RS-485-1, RS-485-2, RS-232+преобразователь, DebugRS-232+преобразователь) - итого 13 модулей на порт - 13 слов - входа, и 13 байт - выходов. Все это дело опрашивать с помощью библиотеки Modbus.lib, так как http://www.owen.ru/forum/showthread.php?t=21940&highlight=modbus.lib и с конфигуратором похоже лучше не связываться.
Осталось разобраться с modbus.lib. В тойже теме пост № 149 человек написал: "А затем выясняется: что для N количества модулей необходимо вынести открытие порта в одну задачу, обращение к N устройствам еще в несколько, а обработку полученных данных в другую задачу."
Вот у меня отсюда и вопрос - как же тогда правильно программно организовать опрос.????
Кто нибуть вообще пол сотни МДВВ опрашивал?????

capzap
18.09.2016, 13:05
Сеть собирал не я - мне нужно переделать после другого программиста, а она собрана повторюсь 54 шт мдвв. Мне нужно "вытянуть" максимум по просу. Ну может 5 секунд я и загнул конечно. Вот и спрашиваю совет, как правильно все организовать.,
Подскажите пожалуйста как правильно записать байт в 50 регистр МДВВ (см. посты выше).

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

KSergey
18.09.2016, 13:07
Такого количества не было, но, я думаю, правильно будет использовать отдельный PRG, в которой один раз открывать порт, а внутри этой программы уже использовать ФБ обращения к приборам. На входе ФБ можно выставить номер прибора и команду Enable, на выходе - результат обработки и Complete. По приходу Complete от предыдущего блока, включать Enable последующего. Записывать выходы можно по изменению, для экономии трафика. Как-то так.

a_gricaj
18.09.2016, 16:15
Ну вроде работает и чтение и запись - два модуля на столе.
А как избавится от вот этого:
26437

Причем эта ошибка (меняет постоянно свое значение с 0 на 255 и обратно) не мешает - выхода включаются.
Мой код


IF port_opened=0
THEN
Settings.Port:=com_num;
Settings.dwBaudRate:=115200;
Settings.byParity:=0;
Settings.dwTimeout:=0;
Settings.byStopBits:=0;
Settings.dwBufferSize:=0;
Settings.dwScan:=0;
END_IF

COM_SERVICE1(Enable:=(port_opened=0) , Settings:=Settings , Task:=OPEN_TSK );


IF COM_SERVICE1.ready THEN port_opened:=2; END_IF
IF port_opened=2 THEN

CASE master1 OF
0:
ModbusAdrDi11(
Enable:=enabl ,
Mode:=MB_RTU ,
DevAddr:=11 ,
FirstAddr:=51 ,
Quantity:=1,
ComHandle:=Settings.Port ,
TimeOut:=TimeOut ,
Buffer:=Buffer,
Complete=>cmpl ,
Exception=>ErrorDI11 ,
ByteCnt=>DataSize );

IF cmpl
THEN
IF ErrorDI11=0
THEN
DIWordAdr11:=BYTE_TO_WORD(BUFFER[1]) OR SHL(BYTE_TO_WORD(BUFFER[0]),8);
END_IF
master1:=1;
END_IF


1:
ModbusAdrDi11(
Enable:=enabl ,
Mode:=MB_RTU ,
DevAddr:=12 ,
FirstAddr:=51 ,
Quantity:=1,
ComHandle:=Settings.Port ,
TimeOut:=TimeOut ,
Buffer:=Buffer ,
Complete=>cmpl ,
Exception=>ErrorDI12 ,
ByteCnt=>DataSize );

IF cmpl
THEN
IF ErrorDI11=0
THEN
DIWordAdr12:=BYTE_TO_WORD(BUFFER[1]) OR SHL(BYTE_TO_WORD(BUFFER[0]),8);
END_IF
master1:=2;
END_IF

2: (*&#231;&#224;&#239;&#232;&#241;&#252;*)
Buffer[0]:=0;
Buffer[1]:=DOByteAdr11;
ModbusAdrDO11(
Enable:= enabl,
Mode:= MB_RTU,
DevAddr:= 11,
FirstAddr:= 50,
Quantity:= 1,
ComHandle:= Settings.Port,
TimeOut:= TimeOut,
Buffer:= Buffer,
Complete=> cmpl,
Exception=> ErrorDO11,
RegCnt=> DataSize);

IF cmpl
THEN
master1:=3;
END_IF


3:
Buffer[0]:=0;
Buffer[1]:=DOByteAdr12;
ModbusAdrDO12(
Enable:= enabl,
Mode:= MB_RTU,
DevAddr:= 12,
FirstAddr:= 50,
Quantity:= 1,
ComHandle:= Settings.Port,
TimeOut:= TimeOut,
Buffer:= Buffer,
Complete=> cmpl,
Exception=> ErrorDO12,
RegCnt=> DataSize);
(*&#229;&#241;&#235;&#232; &#243;&#241;&#242;&#224;&#237;&#238;&#226;&#235;&#229;&#237; &#239;&#240;&#232;&#231;&#237;&#224;&#234; &#231;&#224;&#226;&#229;&#240;&#248;&#229;&#237;&#232;&#255; &#238;&#239;&#229;&#240;&#224;&#246;&#232;&#232;, &#242;&#238; *)
IF cmpl
THEN
master1:=0;
END_IF

END_CASE


IF enabl = FALSE THEN enabl := TRUE;
END_IF

END_IF

DOByteAdr11.7:=DIWordAdr11.0;

a_gricaj
18.09.2016, 21:18
Где хотябы почитать про эту ошибку подскажите пожалуйста???

a_gricaj
18.09.2016, 23:35
Такого количества не было, но, я думаю, правильно будет использовать отдельный PRG, в которой один раз открывать порт, а внутри этой программы уже использовать ФБ обращения к приборам. На входе ФБ можно выставить номер прибора и команду Enable, на выходе - результат обработки и Complete. По приходу Complete от предыдущего блока, включать Enable последующего. Записывать выходы можно по изменению, для экономии трафика. Как-то так.

Новое PRG, точно поможет? где-то читал что не поможет....

Только, что сделал FB котором: открытие порта, далее чтение из 21 модуля, потом запись в 21 модуль. Тайм-аут 10мс. Но ФИЗИЧЕСКИ подключены к порту только два модуля. И залил код "DO:=DI" ну если есть вход сразу включается выход. Так вот задержка между включением светодиода на входе до включения реле на выходе примерно 1 сек.
Думаю, что если сейчас 19 модулей работают по тайм-ауту, а это 19 модулей*2 кол. обращений*10=380 мс плюс там еще какие то задержки. Если все это уберется, то может все будет и нормально - завтра буду на объекте - попробую....

А по изменению это идея, достаточно перед записью сравнить старое значение байта с новым и если они равны тогда перейти на следующий шаг CASE, так?

capzap
19.09.2016, 07:20
проверять нужно чтением лога запросов/ответов, а не домыслами
Интересно, как Вы будете определять изменение входов в модулях

KSergey
19.09.2016, 07:23
проверять нужно чтением лога запросов/ответов, а не домыслами
Интересно, как Вы будете определять изменение входов в модулях

Запись по изменению, а не чтение.

KSergey
19.09.2016, 07:29
Новое PRG, точно поможет? где-то читал что не поможет....

Только, что сделал FB котором: открытие порта, далее чтение из 21 модуля, потом запись в 21 модуль. Тайм-аут 10мс. Но ФИЗИЧЕСКИ подключены к порту только два модуля. И залил код "DO:=DI" ну если есть вход сразу включается выход. Так вот задержка между включением светодиода на входе до включения реле на выходе примерно 1 сек.
Думаю, что если сейчас 19 модулей работают по тайм-ауту, а это 19 модулей*2 кол. обращений*10=380 мс плюс там еще какие то задержки. Если все это уберется, то может все будет и нормально - завтра буду на объекте - попробую....

А по изменению это идея, достаточно перед записью сравнить старое значение байта с новым и если они равны тогда перейти на следующий шаг CASE, так?

Да, если нужно изменить выход, то case:=case+1, если нет, то case:=0.
Сейчас на работе. Если найду модуль, то попробую разобраться с записью. Я подозреваю, что 255 - это ошибка таймаута.
Модуля вывода нет, но 255 - это таймаут.

Спорягин Кирилл
19.09.2016, 09:43
Счетчиков потребуется примерно пол сотни, а это дополнительная нагрузка на обмен, все таки дополнительно читать еще 50 регистров, придется жертвовать точностью в сторону скорости.

Я уже реализовал подобный объект, правда управление без контроллера с МастерСкада и модулей 23 шт. и не МДВВ, а МВ. Счетчики не использовал - то в принцпе устраивает, да импульсы иногда пропускает - но не критично.

Так себе думаю, получается все 54 модуля нужно разделить на 4 порта ( RS-485-1, RS-485-2, RS-232+преобразователь, DebugRS-232+преобразователь) - итого 13 модулей на порт - 13 слов - входа, и 13 байт - выходов. Все это дело опрашивать с помощью библиотеки Modbus.lib, так как http://www.owen.ru/forum/showthread.php?t=21940&highlight=modbus.lib и с конфигуратором похоже лучше не связываться.
Осталось разобраться с modbus.lib. В тойже теме пост № 149 человек написал: "А затем выясняется: что для N количества модулей необходимо вынести открытие порта в одну задачу, обращение к N устройствам еще в несколько, а обработку полученных данных в другую задачу."
Вот у меня отсюда и вопрос - как же тогда правильно программно организовать опрос.????
Кто нибуть вообще пол сотни МДВВ опрашивал?????

A_gricaj, я не могу понять, Вы вроде бы даете в одном из своих сообщений ссылку на тему "Универсальный диспетчер Modbus" (http://www.owen.ru/forum/showthread.php?t=25112), но после этого спрашиваете, как организовать опрос. В указанной теме очень подробно описан один из способов.
Сможете ли Вы быстро опросить 54 модуля вопрос сложный. У меня в существующих проектах до 19 модулей при этом цикл опроса от 30 мс до 1500 мс (т.е. часть модулей опрашивается с периодом 30 мс, другие с периодом 1500 мс). 54, конечно, поболее, но я думаю, что в 1 секунду уложитесь, если разведете по разным портам, а запись будете осуществлять по изменению. Тут главная проблема в том, что некоторые модули долго отвечают. Так, например, модуль МУ110-16Р на скорости 57600 для установки своих 16 выходов требует порядка 15 мс, в то время как теоретически обмен одним регистром должен занимать примерно 2-3 мс.
Поэтому главная загвоздка в том, как быстро отвечают модули МДВВ. От этого и будет зависеть время полного цикла опроса.

Спорягин Кирилл
19.09.2016, 09:54
Обратите внимание, еще на вот эту таблицу (http://www.owen.ru/forum/showthread.php?t=21940&page=5&p=179837&viewfull=1#post179837). Из нее хорошо, видно, что есть некоторая задержка в том, как отвечают модули. Это видно по разнице между опросами 4, 16, 32 и 48 байт. Так на скорости 115200 опрос 16 байт занимает 8 мс, а 32 байт - 10 мс. Из чего можно сказать, что опрос 16 байт на скорости 115200 примерно 2 мс (сходится с теоретическим расчетом). Но вот первые 16 байт он почему-то опрашивает аж 8 мс. В этом времени главная составляющая - это задержка от слейва - т.е. время, которое тот думает перед отправкой ответа.

Гарчев Евгений
19.09.2016, 13:46
Ну вроде работает и чтение и запись - два модуля на столе.
А как избавится от вот этого:
26437

Причем эта ошибка (меняет постоянно свое значение с 0 на 255 и обратно) не мешает - выхода включаются.
[/CODE]
ф.б. на запись отрабатывает не за один цикл, поэтому буфер на отправку необходимо формировать однократно перед вызовом этого ф.б. После вызова ф.б. необходимо сразу же снять флаг запуска в следующем действии (ModbusAdrDO11(enable:=false); ) и потом уже ждать завершения его работы.

Гарчев Евгений
19.09.2016, 13:54
А по изменению это идея, достаточно перед записью сравнить старое значение байта с новым и если они равны тогда перейти на следующий шаг CASE, так?

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

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

Отдельная PRG не поможет.

жекон
19.09.2016, 15:11
Теоретически понятно , а вот практически у меня в голове пока не вырисовалось)))

energvk
19.09.2016, 17:37
ф.б. на запись отрабатывает не за один цикл, поэтому буфер на отправку необходимо формировать однократно перед вызовом этого ф.б. После вызова ф.б. необходимо сразу же снять флаг запуска в следующем действии (ModbusAdrDO11(enable:=false); ) и потом уже ждать завершения его работы.

А вот это интересное замечание. Я не знал про такой нюанс.

capzap
19.09.2016, 17:56
А вот это интересное замечание. Я не знал про такой нюанс.

может и это (http://www.owen.ru/forum/showthread.php?t=25120&p=219494&viewfull=1#post219494) заинтересует

a_gricaj
19.09.2016, 19:52
Да, если нужно изменить выход, то case:=case+1, если нет, то case:=0.
Сейчас на работе. Если найду модуль, то попробую разобраться с записью. Я подозреваю, что 255 - это ошибка таймаута.
Модуля вывода нет, но 255 - это таймаут.

Да, скорее всего это таймаут, при подключенных всех 23 модуля на (одном порте) все ушло...

a_gricaj
19.09.2016, 20:32
A_gricaj, я не могу понять, Вы вроде бы даете в одном из своих сообщений ссылку на тему "Универсальный диспетчер Modbus" (http://www.owen.ru/forum/showthread.php?t=25112), но после этого спрашиваете, как организовать опрос. В указанной теме очень подробно описан один из способов.
Сможете ли Вы быстро опросить 54 модуля вопрос сложный. У меня в существующих проектах до 19 модулей при этом цикл опроса от 30 мс до 1500 мс (т.е. часть модулей опрашивается с периодом 30 мс, другие с периодом 1500 мс). 54, конечно, поболее, но я думаю, что в 1 секунду уложитесь, если разведете по разным портам, а запись будете осуществлять по изменению. Тут главная проблема в том, что некоторые модули долго отвечают. Так, например, модуль МУ110-16Р на скорости 57600 для установки своих 16 выходов требует порядка 15 мс, в то время как теоретически обмен одним регистром должен занимать примерно 2-3 мс.
Поэтому главная загвоздка в том, как быстро отвечают модули МДВВ. От этого и будет зависеть время полного цикла опроса.

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

Поэтому сделал я FB на Сase для каждого порта. Сделал запись по изменению. На один порт поцепил все модуля с второстепенными сигналами, получилось 23 модуля МДВВ (остальные по 10 на оставшиеся порты буду цеплять), скорость 115200.
Время задержки (на глаз) от момента подачи на вход сигнала до включения на выходе реле меньше секунды, хотя она и ощутима.В общем пока нормально, теперь я так понял нужно еще с этим разбираться
ф.б. на запись отрабатывает не за один цикл, поэтому буфер на отправку необходимо формировать однократно перед вызовом этого ф.б. После вызова ф.б. необходимо сразу же снять флаг запуска в следующем действии (ModbusAdrDO11(enable:=false); ) и потом уже ждать завершения его работы.

Хотя теперь не понятно почему ушли ошибки...

a_gricaj
19.09.2016, 20:43
ф.б. на запись отрабатывает не за один цикл, поэтому буфер на отправку необходимо формировать однократно перед вызовом этого ф.б. После вызова ф.б. необходимо сразу же снять флаг запуска в следующем действии (ModbusAdrDO11(enable:=false); ) и потом уже ждать завершения его работы.
Скажите я правильно вас понял:


45:IF OldDOByteAdr33=DOByteAdr33 THEN master1:=0;
ELSE
Buffer[0]:=0;
Buffer[1]:=DOByteAdr33;
ModbusAdrDO33(
Enable:= enabl,
Mode:= MB_RTU,
DevAddr:= 33,
FirstAddr:= 50,
Quantity:= 1,
ComHandle:= Settings.Port,
TimeOut:= TimeOut,
Buffer:= Buffer,
Complete=> cmpl,
Exception=> ErrorDO33,
RegCnt=> DataSize);
ModbusAdrDO33.enable:=FALSE;
IF cmpl
THEN
OldDOByteAdr33:=DOByteAdr33;
master1:=0;
END_IF
END_IF

energvk
19.09.2016, 23:27
может и это (http://www.owen.ru/forum/showthread.php?t=25120&p=219494&viewfull=1#post219494) заинтересует

Да, спасибо) Это я уже видел и принял к сведению.

capzap
20.09.2016, 07:17
Это я уже видел и принял к сведению.

судя по этой теме, этого не видно. В исходниках не возможно не заметить, как используется буфер и переменная enable

a_gricaj
20.09.2016, 08:27
судя по этой теме, этого не видно. В исходниках не возможно не заметить, как используется буфер и переменная enable

Вы хотите сказать, что у меня может включиться дискретный выход который я не включаю????

energvk
20.09.2016, 08:55
судя по этой теме, этого не видно. В исходниках не возможно не заметить, как используется буфер и переменная enable

Я видел не в этой теме, а ранее, в той, на которую вы мне ссылку указали))

Спорягин Кирилл
20.09.2016, 09:27
Вы хотите сказать, что у меня может включиться дискретный выход который я не включаю????

Будьте внимательны! Если Вы будете не правильно пользоваться библиотекой, то такое возможно.
Рекомендую прочесть вот этот пост (http://www.owen.ru/forum/showthread.php?t=21940&page=14&p=219033&viewfull=1#post219033).

a_gricaj
20.09.2016, 10:25
Будьте внимательны! Если Вы будете не правильно пользоваться библиотекой, то такое возможно.
Рекомендую прочесть вот этот пост (http://www.owen.ru/forum/showthread.php?t=21940&page=14&p=219033&viewfull=1#post219033).

Перед каждым вызовом я пишу значение в буфер:

29:IF OldDOByteAdr67=DOByteAdr67 THEN master1:=30;
ELSE
Buffer[0]:=0;
Buffer[1]:=DOByteAdr67;
ModbusAdrDO67(
Enable:= enabl,
Mode:= MB_RTU,
DevAddr:= 67,
FirstAddr:= 50,
Quantity:= 1,
ComHandle:= Settings.Port,
TimeOut:= TimeOut,
Buffer:= Buffer,
Complete=> cmpl,
Exception=> ErrorDO67,
RegCnt=> DataSize);

IF cmpl
THEN
OldDOByteAdr67:=DOByteAdr67;
master1:=30;
END_IF
END_IF
30: ......

или я неправильно делаю???

Спорягин Кирилл
20.09.2016, 10:28
Перед каждым вызовом я пишу значение в буфер:

Подход не правильный. Правильно так:
1. Сформировали буфер на шаге Х. Перешли на шаг Х+1.
2. На шаге Х+1 вызвали нужный ФБ из библиотеки Modbus.lib.

a_gricaj
20.09.2016, 10:33
Подход не правильный. Правильно так:
1. Сформировали буфер на шаге Х. Перешли на шаг Х+1.
2. На шаге Х+1 вызвали нужный ФБ из библиотеки Modbus.lib.



28: Buffer[0]:=0;
Buffer[1]:=DOByteAdr67;
master1:=29;
29:IF OldDOByteAdr67=DOByteAdr67 THEN master1:=30;
ELSE
ModbusAdrDO67(
Enable:= enabl,
Mode:= MB_RTU,
DevAddr:= 67,
FirstAddr:= 50,
Quantity:= 1,
ComHandle:= Settings.Port,
TimeOut:= TimeOut,
Buffer:= Buffer,
Complete=> cmpl,
Exception=> ErrorDO67,
RegCnt=> DataSize);

IF cmpl
THEN
OldDOByteAdr67:=DOByteAdr67;
master1:=30;
END_IF
END_IF
30: ......

правильно???

Спорягин Кирилл
20.09.2016, 10:43
правильно???

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

Но обращаю Ваше внимание, что есть потенциальная ошибка.
Если DOByteAdr67 <> OldDOByteAdr67 мы вызвали блок. Блок послал запрос в линию. Теперь предположим, что пока блок ждет ответ у Вас DOByteAdr67 стало равно OldDOByteAdr67. То Ваш код перейдет на шаг 30 не дождавшись ответа. Что явно не хорошо.

a_gricaj
20.09.2016, 11:01
С точки зрения того, что теперь буфер не изменяется в процессе вызова ФБ modbus правильно.

Но обращаю Ваше внимание, что есть потенциальная ошибка.
Если DOByteAdr67 <> OldDOByteAdr67 мы вызвали блок. Блок послал запрос в линию. Теперь предположим, что пока блок ждет ответ у Вас DOByteAdr67 стало равно OldDOByteAdr67. То Ваш код перейдет на шаг 30 не дождавшись ответа. Что явно не хорошо.

Значит наверное так?


28: IF OldDOByteAdr67=DOByteAdr67
THEN master1:=31;
ELSE
Buffer[0]:=0;
Buffer[1]:=DOByteAdr67;
master1:=29;
END_IF
29: ModbusAdrDO67(
Enable:= enabl,
Mode:= MB_RTU,
DevAddr:= 67,
FirstAddr:= 50,
Quantity:= 1,
ComHandle:= Settings.Port,
TimeOut:= TimeOut,
Buffer:= Buffer,
Complete=> cmpl,
Exception=> ErrorDO67,
RegCnt=> DataSize);

IF cmpl
THEN
OldDOByteAdr67:=DOByteAdr67;
master1:=31;
END_IF

31: ......

Спорягин Кирилл
20.09.2016, 11:10
Уже лучше.
Но что Ваш код будет делать если модуль не ответил или ответил ошибкой, т.е. если ErrorDO67 <> 0?

a_gricaj
20.09.2016, 11:20
Уже лучше.
Но что Ваш код будет делать если модуль не ответил или ответил ошибкой, т.е. если ErrorDO67 <> 0?

Если хотя бы один модуль будет иметь Exception <> 0 тогда сформируется общая ошибка по сети (с задержкой 1 - 2 сек) - и отключение всех исполнительных механизмов на всех модулях, а на самом модуле сетевой там аут 2 секунды.
Если ошибка уйдет тогда ее буду сбрасывать со скады...
Или тут я тоже намудрил???

Спорягин Кирилл
20.09.2016, 11:30
Я обычно пытаюсь еще раз достучаться до модуля. И только в случае повторной неудачи считаю, что модуль отказал.
Для того, чтобы отослать повторный запрос достаточно ведь просто остаться на этом же шаге, но взвести еще раз Enable.
Чтобы это происходило автоматически я на вход Enable подаю not Read (применительно к Вашему коду будет Enable := not ModbusAdrDO67.Read).

И учтите, что в случае ошибки Вы скорее всего не записал в модуль DOByteAdr67, но тем не менее пишите OldDOByteAdr67 := DOByteAdr67.

Но в целом так как Вы предлагаете тоже можно.

Спорягин Кирилл
20.09.2016, 12:46
Важное замечание к самому себе. Остаться нужно не на том же шаге, а на той же паре шагов! Т.е. заново сформировать буфер (еще раз отсылаю к этому посту (http://www.owen.ru/forum/showthread.php?t=21940&page=14&p=219033&viewfull=1#post219033))!
Все остальное без изменений.

a_gricaj
21.09.2016, 07:54
Важное замечание к самому себе. Остаться нужно не на том же шаге, а на той же паре шагов! Т.е. заново сформировать буфер (еще раз отсылаю к этому посту (http://www.owen.ru/forum/showthread.php?t=21940&page=14&p=219033&viewfull=1#post219033))!
Все остальное без изменений.

СПС за консультацию

energvk
22.09.2016, 10:54
ф.б. на запись отрабатывает не за один цикл, поэтому буфер на отправку необходимо формировать однократно перед вызовом этого ф.б. После вызова ф.б. необходимо сразу же снять флаг запуска в следующем действии (ModbusAdrDO11(enable:=false); ) и потом уже ждать завершения его работы.


А вот это интересное замечание. Я не знал про такой нюанс.

А к чтению из модуля это замечание относится?

Гарчев Евгений
22.09.2016, 18:33
Смысл в том, что буфер надо сформировать только один раз и не перезаписывать его в каждом цикле, пока функциональный блок не отработал.
А снимать флаг, судя по исходникам библиотеки, не обязательно сразу после вызова ф.б., это касается и ф.б. чтения и ф.б. записи.

Гарчев Евгений
22.09.2016, 18:38
Если вернуться к коду автора темы, то необязательно ему буфер формировать в отдельном шаге, раз он использует промежуточную переменную. Можно обойтись такой конструкцией в одном шаге:
if enabl then
Buffer[0]:=0;
Buffer[1]:=DOByteAdr67;
end_if
ModbusAdrDO67(
Enable:= enabl,
Mode:= MB_RTU,
DevAddr:= 67,
FirstAddr:= 50,
Quantity:= 1,
ComHandle:= Settings.Port,
TimeOut:= TimeOut,
Buffer:= Buffer,
Complete=> cmpl,
Exception=> ErrorDO67,
RegCnt=> DataSize);
enabl:=FALSE;

energvk
22.09.2016, 18:47
Всё, теперь понятно. Вот в прошлый раз неправильно понял оказывается. Спасибо за пояснение.

Гарчев Евгений
22.09.2016, 18:50
скорее, это я некорректно написал в прошлый раз, но главное, что разобрались в итоге ...

Andrew_Stranger
07.08.2018, 14:14
Может кто подскажет что не так. Пытаюсь опрашивать ТРМ212 с плк150, данные считываю, запись никак не проходит. IF COM_SERVICE1.ready=FALSE THEN

com_num:=0;

Settings.Port:=com_num;
Settings.dwBaudRate:=115200;
Settings.byParity:=0;
Settings.dwTimeout:=20;
Settings.byStopBits:=2;
Settings.dwBufferSize:=0;
Settings.dwScan:=0;

COM_SERVICE1(Enable:=TRUE , Settings:=Settings , Task:=OPEN_TSK );
com_ready:=FALSE;
ELSE
COM_SERVICE1.Enable:=FALSE;
com_ready:=TRUE;
END_IF


IF com_ready THEN

CASE master1 OF

0:
get1_modbus(
Enable:=TRUE ,
Mode:=MB_RTU ,
DevAddr:=5 ,
FirstAddr:=4104 ,
Quantity:=10,
ComHandle:=com_settings.Port ,
TimeOut:=t#200ms ,
Buffer:=Buffer ,
Complete=>cmpl ,
Exception=>err ,
ByteCnt=>DataSize );

IF err=0 THEN
x:=BYTE_TO_WORD(BUFFER[1]) OR SHL(BYTE_TO_WORD(BUFFER[0]),8);

ptr_PV:=ADR(PV);
ptr_PV^:=buffer[5];
ptr_PV:=ptr_PV+1;
ptr_PV^:=buffer[4];
ptr_PV:=ptr_PV+1;
ptr_PV^:=buffer[3];
ptr_PV:=ptr_PV+1;
ptr_PV^:=buffer[2];

ptr_SP:=ADR(SP);
ptr_SP^:=buffer[17];
ptr_SP:=ptr_SP+1;
ptr_SP^:=buffer[16];
ptr_SP:=ptr_SP+1;
ptr_SP^:=buffer[15];
ptr_SP:=ptr_SP+1;
ptr_SP^:=buffer[14];

END_IF
IF cmpl THEN
master1:=2;
END_IF


2:
get1_modbus(
Enable:=FALSE ,
Mode:=MB_RTU ,
DevAddr:=5 ,
FirstAddr:=4104 ,
Quantity:=10,
ComHandle:=com_settings.Port ,
TimeOut:=t#200ms ,
Buffer:=Buffer ,
Complete=>cmpl ,
Exception=>err ,
ByteCnt=>DataSize );

master1:=3;

3: SPbuffer[0]:=10;
master1:=4;

4:
Wr_Modbus
(
Enable:=TRUE ,
Mode:=MB_RTU ,
DevAddr:=5 ,
FirstAddr:=4 ,
Quantity:= 1,
ComHandle:=com_settings.Port ,
TimeOut:=t#200ms ,
Complete=>cmpl ,
Exception=>err,
Buffer:=SPbuffer,
);

IF cmpl THEN
master1:=5;
END_IF

5:

Wr_Modbus
(
Enable:=FALSE ,
Mode:=MB_RTU ,
DevAddr:=5 ,
FirstAddr:=4 ,
Quantity:= 1,
ComHandle:=com_settings.Port ,
TimeOut:=t#200ms ,
Complete=>cmpl ,
Exception=>err,
Buffer:=SPbuffer,
);

master1:=0;
END_CASE;

END_IF

Трофимов Артем
07.08.2018, 14:37
ТРМ212 настроен на работу по статической уставке или работает по графику уставки?

Andrew_Stranger
07.08.2018, 14:44
ТРМ Настроен на работу по статической уставке. Если работаю через конфигуратор то запись проходит.

Трофимов Артем
07.08.2018, 14:47
какой код ошибки возвращает запись?

Andrew_Stranger
07.08.2018, 14:55
код ошибки 3

Трофимов Артем
07.08.2018, 14:57
03 — Значение, содержащееся в поле данных запроса, является недопустимой величиной. стандартный код ошибки протокола. покажите какие данные пишите и как формируете буфер на запись ,что то я его не увидел в коде

Andrew_Stranger
07.08.2018, 15:31
03 — Значение, содержащееся в поле данных запроса, является недопустимой величиной. стандартный код ошибки протокола. покажите какие данные пишите и как формируете буфер на запись ,что то я его не увидел в коде

3: SPbuffer[0]:=10;
master1:=4;

4:
Wr_Modbus
(
Enable:=TRUE , (* разрешение работы блока *)
Mode:=MB_RTU , (*режим передачи*)
DevAddr:=5 , (*адрес*)
FirstAddr:=4 ,
Quantity:= 1,
ComHandle:=com_settings.Port , (*номер COM-порта*)
TimeOut:=t#200ms , (*Таймаут T#50ms*)
Complete=>cmpl , (* скопировать признак завершения операции *)
Exception=>err, (* скопировать регистр ошибок *)
Buffer:=SPbuffer,
);

IF cmpl THEN
master1:=5;
END_IF

Трофимов Артем
07.08.2018, 15:38
SPbuffer - массива байт или слов?
а SPbuffer[1] чему равен?
чему равны нижняя и верхняя границы уставки в приборе?
P.s. можете приложить лог обмена при записи?
приложите объявление блока Wr_Modbus

Andrew_Stranger
07.08.2018, 16:01
ПрикладываюPROGRAM PLC_PRG
VAR
get1_modbus: MB_RD_HOLD_REGS; (*функция 03 - чтение параметра типа INT*)
Wr_Modbus:MB_WR_REGS;
Settings:COMSETTINGS;
com_num: PORTS:=0;
Buffer, SPbuffer: ARRAY[0..255] OF BYTE; (* байтовый буфер данных *)
cmpl: BOOL;
port_opened: BYTE := 0;
Init: BOOL;

(* признак инициализации пользовательской программы *)

com_settings:COMSETTINGS; (* настройки последовательного порта *)
com_number: PORTS; (*0 - RS-485, 1 - RS-232*)
COM_SERVICE1: COM_SERVICE;
com_ready: BOOL;

enabl: BOOL; (*состояние работы блока*)
err: INT; (*номер ошибки*)
TimeOut: TIME:=T#200ms; (*таймаут*)
Exception: BYTE;
DataSize: WORD;
master1: BYTE;
t: DWORD;
A: WORD := 0;
x:WORD; (*считанное значение*)
x1: WORD; (*переменная для записи по сети*)
x2: WORD; (*переменная для записи по сети*)
x3: WORD; (*переменная для записи по сети*)
PV: REAL; (*считанное значение*)
SP:REAL;
ptr_PV:POINTER TO BYTE;
ptr_SP:POINTER TO BYTE;
P:POINTER TO BYTE;
SP1_old,SP1:WORD;
SPb:WORD;
RTM1w:R_TRIG;
END_VAR

Трофимов Артем
07.08.2018, 16:03
хорошо, запишите принудительно в SPbuffer[1] := 0;
смещения десятичной точки как настроено в ТРМ?

Andrew_Stranger
07.08.2018, 16:07
Границы +10...70, смещение на 1 разряд.
P.S. Все заработало, видимо в границах диапазона была проблема.
Спасибо большое.

Andrew_Stranger
08.08.2018, 11:11
Еще вопрос. При опросе уставки и измеренного значения ТРМ212 приходят периодически неправильные показания. Ранее на форуме писали что надо корректировать библиотеку, но это не дало результатов.

Трофимов Артем
08.08.2018, 11:27
могу рекоммендовать фаильтровать данные на входе. RS допускает потерю, коллизию 0.3% пакетов.
кстати, если Вы не поставите условие записи уставки в коде, что приложили и будете его вызывать циклично, Вы в скором времени потрёте память прибора

Andrew_Stranger
08.08.2018, 13:00
Спасибо. условие записи сделал. Ошибки при чтении идут постоянно дело наверно не в коллизиях.

Трофимов Артем
08.08.2018, 13:19
изначально пропустил настройку порта
Settings.dwTimeout:=20; - сделайте равный нулю, так пойдёт лучше. на практике с таймаутом возникают ошибки, нужна тонкая настройка, с нулём будет лучше.
также советую в вашем коде, между запросами сделать шаги паузы на 10 мс, например

step_pause(IN := TRUE , pt:= t#10ms);
IF step_pause.Q THEN
state := следующий шаг;
step_pause(IN :=FALSE);
END_IF

для RTU это поможет исключить необходимые тайминги времени между фреймами.
Вы только с ТРМ-ами настраиваете обмен?

Andrew_Stranger
08.08.2018, 16:23
Таймаут убрал,но не помогло. Проблема была в том что надо читать из буфера по флагу Complete. Помимо ТРМ три модуля ввода аналоговых и один дискретный вывода.

Трофимов Артем
08.08.2018, 19:42
Откровенная дичь

Complete поднимается после выдержки нужной паузы. Дополнительная - онанизм.
Если же конкретный девайс не может в силу возможностей вычленить пакеты и ему нужно что дополнительное, то нужно говорить не

, а нужно пояснить именно этот девайс хиловат и ему это нужно.

кто гарантирует что драйвер девайса работает идеально, т.е. с задержками не заметными программисту плк?
на своём опыте встречал и энергоанализаторы и считыватели магнитных карт ( aka RFID ) которые.. хммм, зачем то физически удерживали шину 485ого чуть ли не до 30 мс после таймаута фрейма(согласно протоколу). упс, такая реализация, говорили они. а выявить это только на осцилографе можно было.
я лишь стараюсь донести мысль о том, что такое может иметь место. и осознание необходимости "ручной" задержки, иногда идёт во благо всей системе

по второму пункту - лучше использовать с ними ASCII, имхо.

Andrew_Stranger
13.08.2018, 11:18
Почему при попытке чтения регистров с помощью MB_RD_HOLD_REGS при опросе более 46 регистров начинают идти ошибки?