Вы хотите сказать, что у меня может включиться дискретный выход который я не включаю????
Вид для печати
Будьте внимательны! Если Вы будете не правильно пользоваться библиотекой, то такое возможно.
Рекомендую прочесть вот этот пост.
Перед каждым вызовом я пишу значение в буфер:
или я неправильно делаю???Код: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: ......
правильно???Код: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: ......
С точки зрения того, что теперь буфер не изменяется в процессе вызова ФБ 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: ......
Уже лучше.
Но что Ваш код будет делать если модуль не ответил или ответил ошибкой, т.е. если ErrorDO67 <> 0?
Если хотя бы один модуль будет иметь Exception <> 0 тогда сформируется общая ошибка по сети (с задержкой 1 - 2 сек) - и отключение всех исполнительных механизмов на всех модулях, а на самом модуле сетевой там аут 2 секунды.
Если ошибка уйдет тогда ее буду сбрасывать со скады...
Или тут я тоже намудрил???
Я обычно пытаюсь еще раз достучаться до модуля. И только в случае повторной неудачи считаю, что модуль отказал.
Для того, чтобы отослать повторный запрос достаточно ведь просто остаться на этом же шаге, но взвести еще раз Enable.
Чтобы это происходило автоматически я на вход Enable подаю not Read (применительно к Вашему коду будет Enable := not ModbusAdrDO67.Read).
И учтите, что в случае ошибки Вы скорее всего не записал в модуль DOByteAdr67, но тем не менее пишите OldDOByteAdr67 := DOByteAdr67.
Но в целом так как Вы предлагаете тоже можно.
Важное замечание к самому себе. Остаться нужно не на том же шаге, а на той же паре шагов! Т.е. заново сформировать буфер (еще раз отсылаю к этому посту)!
Все остальное без изменений.
Смысл в том, что буфер надо сформировать только один раз и не перезаписывать его в каждом цикле, пока функциональный блок не отработал.
А снимать флаг, судя по исходникам библиотеки, не обязательно сразу после вызова ф.б., это касается и ф.б. чтения и ф.б. записи.
Если вернуться к коду автора темы, то необязательно ему буфер формировать в отдельном шаге, раз он использует промежуточную переменную. Можно обойтись такой конструкцией в одном шаге:
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;
Всё, теперь понятно. Вот в прошлый раз неправильно понял оказывается. Спасибо за пояснение.
скорее, это я некорректно написал в прошлый раз, но главное, что разобрались в итоге ...
Может кто подскажет что не так. Пытаюсь опрашивать ТРМ212 с плк150, данные считываю, запись никак не проходит.2:
ТРМ212 настроен на работу по статической уставке или работает по графику уставки?
ТРМ Настроен на работу по статической уставке. Если работаю через конфигуратор то запись проходит.
какой код ошибки возвращает запись?
код ошибки 3
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
SPbuffer - массива байт или слов?
а SPbuffer[1] чему равен?
чему равны нижняя и верхняя границы уставки в приборе?
P.s. можете приложить лог обмена при записи?
приложите объявление блока Wr_Modbus
Прикладываю3:
хорошо, запишите принудительно в SPbuffer[1] := 0;
смещения десятичной точки как настроено в ТРМ?
Границы +10...70, смещение на 1 разряд.
P.S. Все заработало, видимо в границах диапазона была проблема.
Спасибо большое.
Еще вопрос. При опросе уставки и измеренного значения ТРМ212 приходят периодически неправильные показания. Ранее на форуме писали что надо корректировать библиотеку, но это не дало результатов.
могу рекоммендовать фаильтровать данные на входе. RS допускает потерю, коллизию 0.3% пакетов.
кстати, если Вы не поставите условие записи уставки в коде, что приложили и будете его вызывать циклично, Вы в скором времени потрёте память прибора
Спасибо. условие записи сделал. Ошибки при чтении идут постоянно дело наверно не в коллизиях.
изначально пропустил настройку порта
Settings.dwTimeout:=20; - сделайте равный нулю, так пойдёт лучше. на практике с таймаутом возникают ошибки, нужна тонкая настройка, с нулём будет лучше.
также советую в вашем коде, между запросами сделать шаги паузы на 10 мс, например
step_pause(IN := TRUE , pt:= t#10ms);
IF step_pause.Q THEN
state := следующий шаг;
step_pause(IN :=FALSE);
END_IF
для RTU это поможет исключить необходимые тайминги времени между фреймами.
Вы только с ТРМ-ами настраиваете обмен?
Таймаут убрал,но не помогло. Проблема была в том что надо читать из буфера по флагу Complete. Помимо ТРМ три модуля ввода аналоговых и один дискретный вывода.
кто гарантирует что драйвер девайса работает идеально, т.е. с задержками не заметными программисту плк?
на своём опыте встречал и энергоанализаторы и считыватели магнитных карт ( aka RFID ) которые.. хммм, зачем то физически удерживали шину 485ого чуть ли не до 30 мс после таймаута фрейма(согласно протоколу). упс, такая реализация, говорили они. а выявить это только на осцилографе можно было.
я лишь стараюсь донести мысль о том, что такое может иметь место. и осознание необходимости "ручной" задержки, иногда идёт во благо всей системе
по второму пункту - лучше использовать с ними ASCII, имхо.
Почему при попытке чтения регистров с помощью MB_RD_HOLD_REGS при опросе более 46 регистров начинают идти ошибки?