Цитата Сообщение от A.Simonov Посмотреть сообщение
Добрый день.
Без кода не очень понятно что и как у вас реализовано.
Но вообще, если успешность запроса зависит от числа запрашиваемых байт...
Так может slave не поддерживает групповой опрос? и каждый параметр нужно отдельно опрашивать?

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

пользуюсь я кодом, который в примере на сайте выложен в свободном доступе
немного модифицированный но вряд ли это что то меняет.
пример кода:
Код:
PROGRAM PLC_PRG
VAR
	get1_modbus: MB_RD_HOLD_REGS;    (*функция 03 - чтение параметра типа INT*)
	get2_modbus: MB_RD_INP_REGS;		(*функция 04 - чтение трех параметров типа INT*)
	get3_modbus: MB_RD_HOLD_REGS;	(*функция 03 - чтение параметра типа Float*)

	Buffer: ARRAY[0..255] OF BYTE;		(* байтовый буфер данных *)
     	cmpl: BOOL;
	port_opened:  BYTE := 0;
	Init: BOOL;								(* признак инициализации пользовательской программы *)
	Settings:COMSETTINGS;				(* настройки последовательного порта *)
      	com_num: PORTS:=0;				(*0 - RS-485, 1 - RS-232*)
	enabl: BOOL;							(*состояние работы блока*)
	err: INT;								(*номер ошибки*)
	TimeOut: TIME:=T#250ms;				(*таймаут*)
	Exception: BYTE;
	DataSize: WORD;
	master1: BYTE:= 2;

	t: DWORD; 					(*переменная для организации счетчика*)
	A: WORD := 0;					(*счетчик*)
	x:WORD;						(*считанное значение*)
	x1: INT;						(*переменная для записи по сети*)
	x2: INT;						(*переменная для записи по сети*)
	x3: INT;						(*переменная для записи по сети*)
	d:  REAL;						(*считанное значение*)
	ptr_D:POINTER TO BYTE;

	COM_SERVICE1: COM_SERVICE;
	x_1: INT;
	delay: TON;
END_VAR
--------------------------------------------

(*Организуем счетчик, что бы передавать эти данные по сети*)
t:=t+1;
IF (t MOD 1000)=0 THEN
	A := A + 1;
		IF A > 9999 THEN
			A := 0;
		END_IF
END_IF
delay(PT:=T#1S);
(*Устанавливаем настройки COM-порта*)
IF port_opened=0 THEN
		Settings.Port:=com_num;               (*номер COM-порта*)
		Settings.dwBaudRate:=19200;    (*скорость*)
		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  );
(*Если COM-порт открыт, то переходим к приему и передачи данных *)
IF COM_SERVICE1.ready THEN
	port_opened:=2;
END_IF

IF port_opened=2 THEN (*Удачно проинициализировали*)

CASE master1 OF

0: (* функция 03 инт  - ФБ считывает значение параметра  типа int из прибора с адресом 2 в регистр с номером 8 по протоколу Modbus-ASCII*)
get1_modbus(
	Enable:=enabl ,			(* разрешение работы блока *)
	Mode:=MB_RTU ,		(*режим передачи*)
	DevAddr:=2 ,				(*адрес*)
	FirstAddr:=8 ,				(*номер регистра*)
	Quantity:=1,				(*количество регистров*)
	ComHandle:=Settings.Port , (*номер COM-порта*)
	TimeOut:=TimeOut , 		(*Таймаут T#50ms*)
	Buffer:=Buffer ,			(* буфер данных *)
	Complete=>cmpl ,		(* скопировать признак завершения операции *)
	Exception=>err ,			(* скопировать регистр ошибок *)
	ByteCnt=>DataSize );		(*кол-во считанных байтов *)
(*если установлен признак завершения операции, то *)
enabl:=FALSE;
delay(IN:=TRUE);

IF cmpl THEN
	IF err=0 THEN (*Если нет ошибок, то получаем данные из буфера типа INT*)
		x:=BYTE_TO_WORD(BUFFER[1]) OR SHL(BYTE_TO_WORD(BUFFER[0]),8);
	END_IF
enabl:=TRUE;
	(*master1:=1; переходим к выполнению следующего ФБ*)
END_IF

1: (* функция 03 флоат - ФБ считывает значение параметра  типа int из прибора с адресом 2 в регистр с номаром 10 по протоколу Modbus-ASCII *)
get3_modbus(
	Enable:=enabl ,			(* разрешение работы блока *)
	Mode:=MB_RTU ,		(*режим передачи*)
	DevAddr:=2 ,				(*адрес*)
	FirstAddr:=10 ,				(*номер регистра*)
	Quantity:=2,				(*количество регистров*)
	ComHandle:=Settings.Port ,(*номер COM-порта*)
	TimeOut:=TimeOut , 		(*Таймаут T#50ms*)
	Buffer:=Buffer ,			(* буфер данных *)
	Complete=>cmpl ,		(* скопировать признак завершения операции *)
	Exception=>err ,			(* скопировать регистр ошибок *)
	ByteCnt=>DataSize );		(*кол-во считанных байтов *)

enabl:=FALSE;
delay(IN:=TRUE);

(*если установлен признак завершения операции, то *)
IF cmpl THEN
	(*master1:=2; переходим к выполнению следующего ФБ*)
	IF err=0 THEN (*Если нет ошибок, то получаем  данные из буфера типа FLOAT*)
		ptr_D:=ADR(d);
		ptr_D^:=buffer[1];
		ptr_D:=ptr_D+1;
		ptr_D^:=buffer[0];
		ptr_D:=ptr_D+1;
		ptr_D^:=buffer[3];
		ptr_D:=ptr_D+1;
		ptr_D^:=buffer[2];
	END_IF
enabl:=TRUE;
END_IF

2: (* функция 04 инт - ФБ считывает значения трех параметров типа Int из прибора с адресом 2 начиная с регистра с номeром 12*)
get2_modbus(
	Enable:= enabl,			(* разрешение работы блока *)
	Mode:=MB_RTU ,		(*режим передачи*)
	DevAddr:=2 ,				(*адрес*)
	FirstAddr:=12 ,				(*номер регистра*)
	Quantity:=8 ,				(*количество регистров*)
	ComHandle:= Settings.Port,(*номер COM-порта*)
	TimeOut:=TimeOut  , 		(*Таймаут T#50ms*)
	Buffer:=Buffer ,			(* буфер данных *)
	Complete=>cmpl ,		(* скопировать признак завершения операции *)
	Exception=>err ,			(* скопировать регистр ошибок *)
	ByteCnt=> DataSize);		(*кол-во считанных байтов *)
enabl:=FALSE;
delay(IN:=TRUE);
(*если установлен признак завершения операции, то *)
IF cmpl THEN
	IF err=0 THEN (*Если нет ошибок, то получаем данные из буфера типа INT*)
		x1:=BYTE_TO_WORD(BUFFER[4]) OR SHL(BYTE_TO_WORD(BUFFER[3]),8);
		x2:=BYTE_TO_WORD(BUFFER[8]) OR SHL(BYTE_TO_WORD(BUFFER[7]),8);
		x3:=BYTE_TO_WORD(BUFFER[12]) OR SHL(BYTE_TO_WORD(BUFFER[11]),8);

	END_IF
enabl:=TRUE;
	(*master1:=0; переходим к выполнению следующего ФБ*)
END_IF
END_CASE

IF  enabl = FALSE AND delay.Q THEN
 	enabl := TRUE;
	delay(IN:=FALSE);
END_IF

IF  err <> 0 THEN
 	enabl := FALSE;
END_IF

END_IF



включил MB_RTU и тоже самое в настройках сервера
специально оставил включенной только мультирегистровый запрос:
master1: BYTE:= 2;
а также прибавил количество запрашиваемых регистров
Quantity:=8 , (*количество регистров*)

софт MasterOPCUniversal позволяет отслеживать, что проходит через порт.
последний приведенный пример дает следующее

27-05-2022 14:30:26.065 Node2:lc73_answerCOM3) Tx: [0021] 02 04 10 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 2E CE
27-05-2022 14:30:26.065 Node2:lc73_answerCOM3) Rx: [0008] 02 04 00 0C 00 08 31 FC

соответственно мы видим запрос Rx и ответ Tx размером 21 байт (включительно с контрольной суммой)
контрольную сумму я даже проверял в считалке на сайте, совпадает!!!

но вот что я обнаружил в Codesys 2 среде во время работы контроллера!
если выставить количество регистров 4, все отрабатывает нормально
но если 6 и более, как в исходном тексте примера, то в буфере мелькает занятых байт
в массиве Buffer только 15 байт ! а далее нули.

Если указать в запросе только 4 байта, то два байта контрольной суммы видны в Buffer, а более -нули в конце.
2022-05-27_14-59-50.png

код ошибки прилетает 255 (таймаут), ну получается как будто действительно таймаут, потому как последних байт в последовательности нету.

Подскажите, что может быть не так!?