Страница 4 из 6 ПерваяПервая ... 23456 ПоследняяПоследняя
Показано с 31 по 40 из 52

Тема: Universal Modbus Device или библиотека Modbus.lib?

  1. #31

    По умолчанию

    Цитата Сообщение от Атаман Посмотреть сообщение

    Но только все же Enable:= Send.Q нельзя, так как Send.Q становится FALSE после Complete в другом кейсе.
    Не пойму логики, он, что при каждом вызове кейса номер 1 равен ТRUE?. Тогда и
    IF Send.Q THEN
    ptr:=ADR(Ves_Post1);
    buffer[1]:=ptr^;
    ptr:=ptr+1;
    buffer[0]:=ptr^;
    ptr:=ptr+1;
    buffer[3]:=ptr^;
    ptr:=ptr+1;
    buffer[2]:=ptr^;
    ptr:=ptr+1;
    END_IF
    нельзя! Так как трогать буфер после отправки до завершения операции нельзя. )

  2. #32

    По умолчанию

    Цитата Сообщение от lazy Посмотреть сообщение
    Не пойму логики, он, что при каждом вызове кейса номер 1 равен ТRUE?.
    lazy, торможу в пятницу. Да, с буфером всё норм, надо сделать Enable:= Send.Q. Спасибо!

  3. #33

    По умолчанию

    Включение Enable на один цикл не помогло. Периодическая случайная ошибка таймаута при записи регистров в СМИ1 командой 16 по Modbus-RTU. Где еще копнуть можно?

  4. #34

    По умолчанию

    Начал копать вверх по modbus.lib.... Таймаут устанавливается в MB_UNI_IO в блоке:



    Код:
    IF tonTimer.Q = TRUE THEN	(* стработал таймер любого тайм-аута *)
    				IF StartFrame = FALSE 	(* кадр не принимался или *)
    					OR DataSize < 5		(* размер кадра меньше допустимого *)
    					THEN
    					Exception := EXC_TO;	(* установить  ошибку тайм-аута *)
    В момент таймаута у меня StartFrame = FALSE , но DataSize = 13. Как такое может быть?

  5. #35

    По умолчанию

    Посмотрите свежим взглядом, не могу найти ошибку...
    Тестовое приложение, опрос двух модулей по модбас:

    Код:
    PROGRAM PLC_PRG
    VAR
    	get1_modbus: MB_RD_HOLD_REGS;    (*функция 03 - чтение параметра типа INT*)
    	send2_modbus: MB_WR_REGS;         (*функция 6 - запись параметров*)
    
    	Buffer_out: 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:=TRUE;							(*состояние работы блока*)
    	err,errcount: INT;								(*номер ошибки*)
    	g: REAL;
    	TimeOut: TIME:=T#50ms;				(*таймаут*)
    	Exception: BYTE;
    	DataSize: WORD;
    	master1: BYTE:= 0;
    	TimeOut2 : TON;
    	Send: R_TRIG;
    	f1:DINT:= 2;
    	COM_SERVICE1: COM_SERVICE;
    	x:WORD;
    END_VAR
    
    (*Устанавливаем настройки COM-порта*)
    IF port_opened=0 THEN
    		Settings.Port:=com_num;               (*номер COM-порта*)
    		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  );
    (*Если COM-порт открыт, то переходим к приему и передачи данных *)
    IF COM_SERVICE1.ready THEN
    	port_opened:=2;
    END_IF
    
    IF port_opened=2 THEN (*Удачно проинициализировали*)
    
    CASE master1 OF
    
    0: (* функция 03 инт  - ФБ считывает значение параметра  типа int из прибора с адресом162 в регистр с номером 48 по протоколу Modbus-RTU*)
    get1_modbus(
    	Enable:= enabl ,			(* разрешение работы блока *)
    	Mode:=MB_RTU,		(*режим передачи*)
    	DevAddr:=8 ,				(*адрес*)
    	FirstAddr:=2 ,				(*номер регистра*)
    	Quantity:=1,				(*количество регистров*)
    	ComHandle:=Settings.Port , (*номер COM-порта*)
    	TimeOut:=TimeOut , 		(*Таймаут T#50ms*)
    	Buffer:=Buffer_out,			(* буфер данных *)
    	Complete=>cmpl ,		(* скопировать признак завершения операции *)
    	Exception=>err ,			(* скопировать регистр ошибок *)
    	ByteCnt=>DataSize );		(*кол-во считанных байтов *)
    (*если установлен признак завершения операции, то *)
    IF cmpl THEN
    	IF err=0 THEN (*Если нет ошибок, то получаем данные из буфера типа INT*)
    		x:=BYTE_TO_WORD(BUFFER_out[1]) OR SHL(BYTE_TO_WORD(BUFFER_out[0]),8);
    		master1 := 3;
    	ELSE
    		errcount:=errcount +1;
    	END_IF
    
    END_IF
    
    
    2:  get1_modbus(
    	Enable:=enabl ,			(* разрешение работы блока *)
    	Mode:=MB_RTU,		(*режим передачи*)
    	DevAddr:=48 ,				(*адрес*)
    	FirstAddr:=50 ,				(*номер регистра*)
    	Quantity:=1,				(*количество регистров*)
    	ComHandle:=Settings.Port , (*номер COM-порта*)
    	TimeOut:=TimeOut , 		(*Таймаут T#50ms*)
    	Buffer:=Buffer_out,			(* буфер данных *)
    	Complete=>cmpl ,		(* скопировать признак завершения операции *)
    	Exception=>err ,			(* скопировать регистр ошибок *)
    	ByteCnt=>DataSize );		(*кол-во считанных байтов *)
    (*если установлен признак завершения операции, то *)
    IF cmpl THEN
    	IF err=0 THEN (*Если нет ошибок, то получаем данные из буфера типа INT*)
    		x:=BYTE_TO_WORD(BUFFER_out[1]) OR SHL(BYTE_TO_WORD(BUFFER_out[0]),8);
    		master1 := 3;
    	ELSE
    		errcount:=errcount +1;
    	END_IF
    
    END_IF
    
    
    3:
     TimeOut2(IN :=TRUE,PT:=T#50ms);
     TimeOut2;
     IF TimeOut2.Q THEN
    	g:=g+1;
    	master1 := 0;
    	(*IF g/2 = TRUNC(g/2) THEN
    		 master1 := 2;
    	END_IF*)
    	TimeOut2.IN := FALSE;
    	TimeOut;
    END_IF
    
    END_CASE
    
    END_IF
    Код выше работает без ошибок. Убираю коммент в 3м кейсе - подключаю опрос второго блока каждый второй раз и в первом модуле каждый второй опрос появляется ошибка таймаута. Что за ерунда??

  6. #36

    По умолчанию

    Тыж вроде сам уже нашел:

    TimeOut2.IN := FALSE;
    TimeOut;

    Вместо этого нужна одна строка:
    TimeOut2( IN := FALSE );

  7. #37

    Thumbs up

    Цитата Сообщение от Гарчев Евгений Посмотреть сообщение
    про тонкости работы с modbus.lib уже не раз говорилось... Не надо формировать буфер на запись в каждом цикле, т.к. ф.б. на запись не успеет отработать за один цикл, а буфер используется один и тот же и на отправку запроса и на прием ответа. Таким образом, при ответе от слейв-устройства в буфере будет "каша" из ответа от устройства и данных, которые вы отправляете на него.
    пять лет прошло, а грабли как новые.
    попался мне плк 73 c платкой модбаса,
    залил тестовый проект в него Modbus чтение INT и REAL (ST),
    и к этому же компу через usb-rs485 модбас от контроллера пробросил, софт MasterOPCUniversal включил и смотрю.
    Ага, переключил в коде на MB_RTU , т.к. в MasterOPCUniversal так по умолчанию.
    забил цифры в регистры с 8 по 14 (как в примере) в slave устройстве на софте MasterOPCUniversal
    INT нормально считывает, REAL байты только переставил и все норм тоже.
    А считывание трех INT подряд - нули. что то не так....
    настроил цикл задачи на 500ms и увидел что код ошибки 255 прилетает как раз в тот момент как прошло завершение чтения.
    таким образом ничего в результат не попадает.
    вот в поиске и нашел эту ветку.
    уменьшив в запросе количество байт до 4х - ошибка пропадает, ставишь больше появляется.

    собственно вопрос тот же (как не наступить на грабли ?) как работать с modbus.lib?
    не совсем ясна фраза "Не надо формировать буфер на запись в каждом цикле" ? хотя чувствую что в ней зарыт смысл...
    где посмотреть подробнее?

    PS. не хочется лезть в библиотеку, благо можно открыть либу текстовым редактором и скопипастить это чудо и покопаться.
    Не попадись мне контроллер для опытов just for fun так сказать, не купил бы. А ведь цена на него стоит сейчас в 30 тысяч!
    (хоть и снят с производства) и при этом к нему бубен не прилагается!

  8. #38
    Пользователь Аватар для A.Simonov
    Регистрация
    11.07.2017
    Адрес
    Москва
    Сообщений
    623

    По умолчанию

    Цитата Сообщение от Schneider Посмотреть сообщение
    пять лет прошло, а грабли как новые.
    попался мне плк 73 c платкой модбаса,
    залил тестовый проект в него Modbus чтение INT и REAL (ST),
    и к этому же компу через usb-rs485 модбас от контроллера пробросил, софт MasterOPCUniversal включил и смотрю.
    Ага, переключил в коде на MB_RTU , т.к. в MasterOPCUniversal так по умолчанию.
    забил цифры в регистры с 8 по 14 (как в примере) в slave устройстве на софте MasterOPCUniversal
    INT нормально считывает, REAL байты только переставил и все норм тоже.
    А считывание трех INT подряд - нули. что то не так....
    настроил цикл задачи на 500ms и увидел что код ошибки 255 прилетает как раз в тот момент как прошло завершение чтения.
    таким образом ничего в результат не попадает.
    вот в поиске и нашел эту ветку.
    уменьшив в запросе количество байт до 4х - ошибка пропадает, ставишь больше появляется.

    собственно вопрос тот же (как не наступить на грабли ?) как работать с modbus.lib?
    не совсем ясна фраза "Не надо формировать буфер на запись в каждом цикле" ? хотя чувствую что в ней зарыт смысл...
    где посмотреть подробнее?

    PS. не хочется лезть в библиотеку, благо можно открыть либу текстовым редактором и скопипастить это чудо и покопаться.
    Не попадись мне контроллер для опытов just for fun так сказать, не купил бы. А ведь цена на него стоит сейчас в 30 тысяч!
    (хоть и снят с производства) и при этом к нему бубен не прилагается!
    Добрый день.
    Без кода не очень понятно что и как у вас реализовано.
    Но вообще, если успешность запроса зависит от числа запрашиваемых байт...
    Так может slave не поддерживает групповой опрос? и каждый параметр нужно отдельно опрашивать?

    Прикладываю примеры опроса, которые у меня завалялись.
    Вложения Вложения
    • Тип файла: zip primer.zip (67.2 Кб, Просмотров: 21)

    Александр Андреевич Симонов
    Инженер по продуктам «ПЛК, модули и OwenCloud»

    Не работаю в ОВЕН с 01.07.22
    По всем вопросам обращайтесь на почту: support@owen.ru

  9. #39

    По умолчанию

    Цитата Сообщение от 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 (таймаут), ну получается как будто действительно таймаут, потому как последних байт в последовательности нету.

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

  10. #40
    Пользователь
    Регистрация
    23.09.2008
    Адрес
    Центророссийск
    Сообщений
    2,283

    По умолчанию

    накой delay ?

Страница 4 из 6 ПерваяПервая ... 23456 ПоследняяПоследняя

Похожие темы

  1. Чтение и запись в Universal Modbus device
    от super100 в разделе ПЛК1хх
    Ответов: 20
    Последнее сообщение: 30.10.2013, 13:18
  2. Адресация Universal Modbus device
    от super100 в разделе ПЛК1хх
    Ответов: 6
    Последнее сообщение: 04.10.2013, 14:05
  3. Universal device MODBUS ???
    от EFrol в разделе ПЛК1хх
    Ответов: 3
    Последнее сообщение: 17.01.2012, 10:43

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •