Страница 3 из 6 ПерваяПервая 12345 ... ПоследняяПоследняя
Показано с 21 по 30 из 52

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

Комбинированный просмотр

Предыдущее сообщение Предыдущее сообщение   Следующее сообщение Следующее сообщение
  1. #1

    По умолчанию

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

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

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

    По умолчанию

    накой delay ?

  3. #3
    Пользователь
    Регистрация
    28.08.2008
    Адрес
    23..93..123
    Сообщений
    1,799

    По умолчанию

    Так мы не против , Евгений , только примерчик ваш :

    1: (* функция 16 - запись параметров типа Int (регистр 4) и Real (регистр 6) в прибор с адресом 2 *)
    (*запись в буффер параметра типа INT*)
    Buffer[1] := DINT_TO_BYTE(f1);
    Buffer[0] := DINT_TO_BYTE( SHR(f1,8));
    Buffer[3] := DINT_TO_BYTE( SHR(f1,16));
    Buffer[2] := DINT_TO_BYTE( SHR(f1,24));

    (*запись в буффер параметра типа Float*)
    ptr_f2:=ADR(f2);
    buffer[5] := ptr_f2^;
    ptr_f2:=ptr_f2+1;
    buffer[4] := ptr_f2^;
    ptr_f2:=ptr_f2+1;
    buffer[7] := ptr_f2^;
    ptr_f2:=ptr_f2+1;
    buffer[6] := ptr_f2^;

    send2_modbus(
    Enable:= enabl, (* разрешение работы блока *)
    Mode:=MB_ASCII , (*режим передачи*)
    DevAddr:=2 , (*адрес*)
    FirstAddr:= 4, (*номер регистра*)
    Quantity:= 4, (*количество записываемых регистров*)
    ComHandle:=Settings.Port ,(*номер сом-порта*)
    TimeOut:=TimeOut , (*таймаут T#50ms*)
    Buffer:=Buffer , (* буфер данных *)
    Complete=>cmpl , (* скопировать признак завершения операции *)
    Exception=>err , (* скопировать регистр ошибок *)
    RegCnt=> DataSize); (*кол-во считанных байтов *)
    (*если установлен признак завершения операции, то *)
    IF cmpl THEN
    master1:=0;(*переходим к выполнению следующего блока*)
    END_IF

    END_CASE

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

    Кто примеры пишет и ни фига не проверяет , а если проверяет то плохо ???
    10 лет уже ПЛКшки выпускаете , а вилы и грабли все те-же , только понтов не меряно.
    И описания для библиотек вместе (в одном месте!!!)с библиотеками и примерами нормальными не только на форуме должны быть , а на Оф.сайте в соответствующем и !!! легко находимом разделе .
    А то шаришся по форуму , который похож сейчас на птичий базар , только что какашки не летят...
    Щас тема подзатеряется и ... опять тот - же вопрос , те-же вилы,грабли...надоело!

  4. #4

    По умолчанию

    Эврика! ))

    Спасибо всем за помощь. Евгений прав, буфер не надо каждый цикл переписывать и всё работает ) Хотя да.... писал с вашего примера

  5. #5

    По умолчанию

    modbus.lib да, своеобразная, и в описалове к ней есть пара ошибок (в типах данных), но при должном подходе она работает нормально. В моём случае работает уже 3 года на объекте, полёт нормальный.

    И описания для библиотек вместе (в одном месте!!!)с библиотеками и примерами нормальными не только на форуме должны быть , а на Оф.сайте в соответствующем и !!! легко находимом разделе .
    А то шаришся по форуму , который похож сейчас на птичий базар , только что какашки не летят...
    Щас тема подзатеряется и ... опять тот - же вопрос , те-же вилы,грабли...надоело!
    С этим абсолютно солидарен.
    Последний раз редактировалось Boris_K; 01.02.2017 в 09:54.

  6. #6

    По умолчанию

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

  7. #7

    По умолчанию

    Добрый вечер )

    Мысль переписать по modbus.lib возникла после безуспешной борьбы с панелью СМИ1 через конфигуратор. При передаче по протоколу Modbus-RTU (СМИ1 - slave) на панели иногда гас экран и шла ошибка 81. Через несколько секунд работа панели возобновлялась. Всё происходит случайным образом без какой-либо закономерности. Изменение параметров не помогало. Сейчас переписал всё на modbus.lib. Происходит все тоже самое с небольшим нюансом - в панели при таймауте гаснет экран и включается при остановке программы в ПЛК-100. То есть после нормальной работы в течение 5-30 минут гаснет экран и в цикле идут следующие кейсы с ошибкой 255 до тех пор пока не остановлю программу.

    Код:
    FUNCTION_BLOCK Modbus
    VAR_IN_OUT
    	VesViklNew1,VesViklNew2,Tara:BOOL;
    	BigError:BOOL;
    END_VAR
    VAR_INPUT
    	Ves_Post2,Ves_Post1:REAL;
    END_VAR
    VAR_OUTPUT
    	err:INT;
    	VesVikl_Post1, VesVikl_Post2,VesTenzo: REAL;
    END_VAR
    VAR
    	get1_modbus: MB_RD_HOLD_REGS;    (*функция 03 - чтение параметра типа INT*)
    	send2_modbus: MB_WR_REGS;          (*функция 16 - запись параметров*)
    	com_ready1:BOOL;
    	Settings1:COMSETTINGS;				(* настройки последовательного порта *)
          	com_num1: PORTS;			       (*0 - RS-485, 1 - RS-232*)
    	Buffer: ARRAY[0..255] OF BYTE;		(* байтовый буфер данных *)
    	Buffer_ok: ARRAY[0..255] OF BYTE;
    	Buffer_error: ARRAY[0..255] OF BYTE;
    	TimeOut: TIME:=T#50ms;			(*таймаут*)
    	cmpl:BOOL;
    	rejim, rejimerror :BYTE;
    	DataSize: WORD;
    	TimeOut2 : TON;
    	Send: R_TRIG;
    	ptr:POINTER TO BYTE;
    	COM_SERVICE1: COM_SERVICE;
    	x: REAL;
    	errorcount,errorcount0,errorcount1,errorcount2,errorcount3,errorcount4,errorcount5,errorcount6: BYTE;
    	VesTaraNew, VesTaraOld :REAL;
    END_VAR
    
    ......
    
    1: (* Отправка в СМИ1 значения Ves_Post1*)
    Send.CLK := TRUE;
    Send;
    IF Send.Q = TRUE 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
    
    send2_modbus(
    	Enable:= TRUE,			(* разрешение работы блока *)
    	Mode:=MB_RTU ,		(*режим передачи*)
    	DevAddr:=32 , 				(*адрес*)
    	FirstAddr:= 0, 				(*номер регистра*)
    	Quantity:= 2,   				(*количество записываемых регистров*)
    	ComHandle:=Settings1.Port ,(*номер сом-порта*)
    	TimeOut:=TimeOut ,		(*таймаут T#50ms*)
    	Buffer:=buffer ,			(* буфер данных *)
    	Complete=>cmpl ,		(* скопировать признак завершения операции *)
    	Exception=>err ,			(* скопировать регистр ошибок *)
    	RegCnt=> DataSize);		(*кол-во записанных байтов *)
    (*если установлен признак завершения операции, то *)
    IF cmpl THEN
       	IF err = 0 THEN
    		rejim:=100;(*переходим к выполнению следующего блока*)
    	ELSE
    		rejimerror := rejim;
    		rejim := 101;
       END_IF
    END_IF
    
    .......
    
    101:(*При ошибке:*)
    	TimeOut2(IN :=TRUE,PT:=T#50ms);
    	TimeOut2;
    	IF TimeOut2.Q THEN
    		rejim := rejimerror;
    		Send.CLK :=FALSE;
    		Send;
    		TimeOut2.IN :=FALSE;
    		TimeOut2;
    	END_IF
    У кого-нибудь мысли есть, что со СМИ1 происходит в этот момент? Может кто то сталкивался с таким?

    P.S. Все остальные модули ОВЕН работают без вопросов. Проблема только со СМИ1. Панели 2шт. - обе ведут себя одинаково.
    Последний раз редактировалось Атаман; 08.02.2017 в 17:59.

  8. #8

    По умолчанию

    А то что ПЛК посылает в панель правильно отображается ?

  9. #9

    По умолчанию

    Цитата Сообщение от Вольд Посмотреть сообщение
    А то что ПЛК посылает в панель правильно отображается ?
    Да, все правильно отображается до появления ошибки.

  10. #10

    По умолчанию

    Чувствую, что где то рядом, но нет....

    Результаты ниже, может у кого то мысль возникнет )

    На ASCII все прекрасно работает - ошибок 0.
    Оставляю блок, который приводил выше, все остальные опросы убираю. То есть записывает в СМИ1 разные значения в один регистр непрерывно. Работал так пару часов - ошибок 0.
    Как только подключаю весь остальной проект возникает ошибка в этом же блоке, при этом в СМИ1 гаснет экран и обе лампочки. И так остается до тех пор, пока не остановлю программу. В программе выполняется последовательно этот блок. Пробовал на горячую при зависании изменить таймаут между отправкой запроса, изменял до 10 сек, не помогает - экран включается но горят нули и всё равно таймаут. Но! Как только меняю на горячую CASE на другой, экран отвисает и всё работает. Вот этот момент я вообще не пойму. Такое ощущение, что где-то что-то не переключается или не отпускает.
    Тот же проект, но с конфигуратором вместо modbus.lib также дает сотни ошибок таймаута.
    Резистор ставил 100, 120, 620 ОМ, с бубном плясал....

    Вообщем ХЕЛП!

    И да... нужно ли буфер обнулять перед отправкой запроса? И как это делается? Пробовал тупо
    for i:= 1TO255 do
    buffer[i] := 0;
    next_for
    уходит в перезагрузку.
    Последний раз редактировалось Атаман; 10.02.2017 в 16:10.

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

Похожие темы

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

Ваши права

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