Показано с 1 по 8 из 8

Тема: Последовательный опрос устройств по Modbus RTU

  1. #1

    По умолчанию Последовательный опрос устройств по Modbus RTU

    Здравствуйте, пишу сюда впервые и очень надеюсь на вашу помощь. Задача в последовательном опросе устройств по Modbus RTU.
    Пытаюсь произвести последовательный опрос 3 устройств и испробовал разные способы, Good practice к сожалению не знаю в этом вопросе.
    Вот мои попытки:

    Код:
    //STEP - переменная для шага, по умолчанию 1
    //пользовательский ФБ запроса по RTU
    MB_R1(
    	START := STEP = 1,
    	SLAVE := 1,
    	FUNC := 4,
    	ADDR := 5000,
    	NUMBER := 12,
    	ERR_TIME := 1000);
    
    MBR1 := MB_R1.READY;
    COUNTER1 := MB_R1.CNT;
    //сокращенная форма IF(IN, VAL1, VAL2) - если IN = TRUE, то возвращает VAL1, иначе VAL2
    STEP := IFI(MB_R1.READY, 2, STEP);
    
    MB_R2(
    	START := STEP = 2,
    	SLAVE := 1,
    	FUNC := 4,
    	ADDR := 5050,
    	NUMBER := 12,
    	ERR_TIME := 1000);
    
    MBR2 := MB_R2.READY;
    COUNTER2 := MB_R2.CNT;
    STEP := IFI(MB_R1.READY, 3, STEP);
    
    MB_R3(
    	START := STEP = 3,
    	SLAVE := 1,
    	FUNC := 4,
    	ADDR := 5100,
    	NUMBER := 12,
    	ERR_TIME := 1000);
    
    MBR3 := MB_R3.READY;
    COUNTER3 := MB_R3.CNT;
    STEP := IFI(MB_R3.READY, 1, STEP);
    В итоге запрос виснет только в одном из ФБ, сюда привел самый простой и понятный вариант из написанного, пробовал уже и с передним фронтом и с таймером, но все равно не работает. Может есть какой-то типовой алгоритм для опроса по Modbus RTU? Сил уже нет

  2. #2
    Пользователь Аватар для capzap
    Регистрация
    25.02.2011
    Адрес
    Киров
    Сообщений
    10,224

    По умолчанию

    отвлеченный вопрос, а почему не понравилось использовать SEL и написали свой IFI?
    а по поводу опроса, если брать библиотеку modbus.lib нужно дождаться прихода COMPLETE чтоб перейти к о просу следующего модуля. Для кокой цели служит Ваш READY не известно потому что не пишите что за бибка и где её брали
    Bad programmers worry about the code. Good programmers worry about data structures and their relationships

    среди успешных людей я не встречала нытиков
    Барбара Коркоран

  3. #3

    По умолчанию

    Спорягин Кирилл выкладывал универсальный диспетчер для Modbus.lib: http://www.owen.ru/forum/showthread....E8%F0%E8%EB%EB
    Последний раз редактировалось Newcomer; 27.03.2018 в 16:09.

  4. #4

    По умолчанию

    Цитата Сообщение от capzap Посмотреть сообщение
    отвлеченный вопрос, а почему не понравилось использовать SEL и написали свой IFI?
    а по поводу опроса, если брать библиотеку modbus.lib нужно дождаться прихода COMPLETE чтоб перейти к о просу следующего модуля. Для кокой цели служит Ваш READY не известно потому что не пишите что за бибка и где её брали
    Для использования SEL необходимо будет каждый раз добавлять NOT в условии, а мне это показалось неудобным (использую ПЛК TREI и среду UNIMOD PRO). По поводу второго вопроса, вот мой ФБ:

    Код:
    MB_R_F1(
    		START,
    		IDDRV,
    		SLAVE,
    		FUNC,
    		ADDR,
    		NUMBER);
    		
    	FAULT:=MB_R_F1.FAULT;
    	
    	//таймер на сработку ошибки
    	TON_1(
    		IN := NOT (MB_R_F1.READY AND FAULT = 0),
    		PT := ERR_TIME);
    		
    	//в случае отсутствия ошибок считываем регистры в промежуточный массив, либо обнуляем его	
    	IF NOT TON_1.Q THEN
    			MB_R_FARR[0]:= MB_R_F1.REG01;
    			MB_R_FARR[1]:= MB_R_F1.REG02;
    			MB_R_FARR[2]:= MB_R_F1.REG03;
    			MB_R_FARR[3]:= MB_R_F1.REG04;
    			MB_R_FARR[4]:= MB_R_F1.REG05;
    
    			//счетчик успешно выполненных запросов
    			CNT := CNT + 1;  	
    			READY := TRUE;
    	ELSE 
    		FOR I := 0 TO 4 DO
    			MB_R_FARR[I]:= 0.0;
    		END_FOR;	
    		CNT := 0;	
    		READY := FALSE;	
    	END_IF;
    	
    	FLOAT_00 := MB_R_FARR[0];
    	FLOAT_01 := MB_R_FARR[1];
    	FLOAT_02 := MB_R_FARR[2];
    	FLOAT_03 := MB_R_FARR[3];
    	FLOAT_04 := MB_R_FARR[4];
    END_IF;
    Последний раз редактировалось MTven; 28.03.2018 в 09:05.

  5. #5
    Пользователь Аватар для capzap
    Регистрация
    25.02.2011
    Адрес
    Киров
    Сообщений
    10,224

    По умолчанию

    можно NOT поставить в первый аргумент, а можно оставшиеся два аргумента местами поменять, как будто по Вашему IFI понятно, какой аргумент отвечает за истину, а какой за фальш, только писать про комментарий не надо, он куда длиннее чем поставить NOT

    Что касается выложенного куска кода, выполнение таймера зачем?
    Bad programmers worry about the code. Good programmers worry about data structures and their relationships

    среди успешных людей я не встречала нытиков
    Барбара Коркоран

  6. #6

    По умолчанию

    Цитата Сообщение от capzap Посмотреть сообщение
    можно NOT поставить в первый аргумент, а можно оставшиеся два аргумента местами поменять, как будто по Вашему IFI понятно, какой аргумент отвечает за истину, а какой за фальш, только писать про комментарий не надо, он куда длиннее чем поставить NOT

    Что касается выложенного куска кода, выполнение таймера зачем?
    про поменять местами аргументы SEL я почему-то не подумал...
    Таймер нужен для того чтобы отсекать периодические ошибки запроса, почему-то от ПЛК проскакивает ошибка платы модуля (сейчас мы уточняем данный момент у производителя).

  7. #7
    Пользователь Аватар для capzap
    Регистрация
    25.02.2011
    Адрес
    Киров
    Сообщений
    10,224

    По умолчанию

    в первом посте READY предположительно должен работать как импульс, во четвертом посте как мне кажется работа READY должна быть не импульсной, чтоб дать поработать таймеру, поэтому до сих пор не понятно как это всё работает и то что не переходит на следующий опрос прибора вполне вероятно из-за этих не стыковок
    Bad programmers worry about the code. Good programmers worry about data structures and their relationships

    среди успешных людей я не встречала нытиков
    Барбара Коркоран

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

    По умолчанию

    Вот кусок из рабочего проекта для ПЛК73. Вкраце что тут происходит...
    Два устройства поочередно опрашиваются по 232 и 485. Тут только кусок от 485 оставил. Опрашиваются они через равные промежутки времени!!! Интервал опроса задается в переменной tMessInterval. Как только коммуникационный ФБ выдает COMPLETE по триггеру отключается флаг enableRsSend и коммуникационный ФБ отключается!!! Как только таймер отсчитает tMessInterval и enableRsSend отключен, смениться шаг в цикле CASE и отключится таймер (чтобы заново стал считать) и так по кругу.

    Код:
           (*ТАЙМЕР СМЕНЫ ШАГОВ КОММУНИКАЦИИ*)
    	tmrStepRs(IN:= com_ready1 AND com_ready2, PT:= tMessInterval);	(*как только открылись оба порта запускаем отсчет шагов опроса*)
    
    	(*ОТПРАВКА И ЧТЕНИЕ КОМАНД RS232 и RS485*)
    	IF (com_ready1 = TRUE AND com_ready2 = TRUE)THEN
    		CASE stepRs OF
                            1:     бла бла бла
                            2:
    				(*ПЕРЕДАЧА ЧАСТОТЫ ПЧВ*)
    				send1_modbus(
    						Enable		:= enableRsSend,
    						Mode		:= MB_RTU,
    						DevAddr		:= 2,
    						RegAddr		:= 50009,						(*РЕГИСТР ЗАДАНИЯ ПО ИНТЕРФЕЙСУ*)
    						Value		:= freq1,						(*ЧАСТОТА*)
    					    ComHandle	:= Settings1.Port,
    						TimeOut		:= tWorkBlock,
    						Complete	=> cmpl3,
    						Exception	=> err3
    				);
    				rt_step_2(CLK:= cmpl3);								(*По завершению работы ФБ включаем триггер*)
    				IF rt_step_2.Q THEN
    					enableRsSend := FALSE;
    				END_IF												(*Если завершили отключаем работу ФБ*)
    
    				IF tmrStepRs.Q AND enableRsSend = FALSE THEN		(*Как только досчитал таймер смены шага и блок отправки уже отработал*)
    					stepRs := 3;									(*Меняем шаг*)
    					tmrStepRs(IN:= FALSE);							(*Отключаем таймер*)
    					IF enableRsSend = FALSE THEN enableRsSend := TRUE; END_IF	(*Ставим флаг для запуска следующего блока*)
    				END_IF
    
    			3:
    				(*ОТПРАВКА КОМАНДНОГО СЛОВА*)
    				IF freq < 0.09 THEN									(*если частота ниже 1Hz то двигатель отключен*)
    					pcv_com_word := 1268;							(*двигатель отключен (торможение с выбегом)*)
    					IF v1 < 2500 THEN
    						pcv_com_word := 1212;						(*если скорость ниже 25м/c то используем быструю остановку*)
    					END_IF
    				ELSE
    					pcv_com_word := 1148 ;							(*запуск двигателя*)
    				END_IF
    				send1_modbus(
    						Enable		:= enableRsSend,
    						Mode		:= MB_RTU,
    						DevAddr		:= 2,
    						RegAddr		:= 49999,						(*РЕГИСТР КОМАНДНОГО СЛОВА ПРИВОДА*)
    						Value		:= pcv_com_word,				(*КОМАНДНОЕ СЛОВО*)
    					     ComHandle	:= Settings1.Port,
    						TimeOut		:= tWorkBlock,
    						Complete	=> cmpl4,
    						Exception	=> err4
    				);
    				rt_step_3(CLK:= cmpl4);
    				IF rt_step_3.Q THEN
    					enableRsSend := FALSE;
    				END_IF
    
    				IF tmrStepRs.Q AND enableRsSend = FALSE THEN
    					stepRs := 4;
    					tmrStepRs(IN:= FALSE);
    					IF enableRsSend = FALSE THEN enableRsSend := TRUE; END_IF
    				END_IF
    
    			4:
    				(*ЗАПРОС СОСТОЯНИЯ ЭЛЕКТРОДВИГАТЕЛЯ*)
    				get3_modbus(
    					Enable		:= enableRsSend,
    					Mode		:= MB_RTU,
    					DevAddr		:= 2,
    					FirstAddr	:= 50199,							(*РЕГИСТР СЛОВА СОСТ. ПРИВОДА*)
    					Quantity	:= 1,
    					ComHandle	:= Settings1.Port,
    					TimeOut		:= tWorkBlock,
    					Buffer		:= buffer1,
    					Complete	=> cmpl5,
    					Exception	=> err5,
    					ByteCnt		=> dataSize1
    				);
    				rt_step_4(CLK:= cmpl5);
    				IF rt_step_4.Q THEN
    					IF err5 = 0 THEN
    						pcv_state_word := BYTE_TO_WORD(buffer1[1]) OR SHL (BYTE_TO_WORD(buffer1[0]),8);
    					END_IF
    					enableRsSend := FALSE;
    				END_IF
    
    				IF tmrStepRs.Q AND enableRsSend = FALSE THEN
    					stepRs := 1;
    					tmrStepRs(IN := FALSE);
    					IF enableRsSend = FALSE THEN enableRsSend := TRUE; END_IF
    				END_IF
    		END_CASE
    Еще следует помнить что в библиотеке модбаса есть ошибка из-за которой через пачку в порт мусор идет. Для ее починки следует сделать следующее
    Код:
    (*
    В БИБЛИОТЕКЕ OWEN MODBUS.LIB В ФБ MB_UNI_IO ЗАМЕНЯЕМ СТРОКУ 7 НА
    WHILE SysComRead(ComHandle, ADR(DataBuf)+DataSize, SIZEOF(DataBuf)-DataSize, 0) <> 0 DO;
    инче в случае получения ошибки таймаута FF в след пачке пойдем мусор.
    Также для скорости 9600 необходимо установить значение таймера T_FRTU = ~5ms
    *)

Похожие темы

  1. Опрос нескольких устройств по modbus
    от gias67 в разделе Сетевые технологии
    Ответов: 5
    Последнее сообщение: 26.11.2018, 15:48
  2. Ответов: 7
    Последнее сообщение: 22.07.2016, 08:06
  3. Ответов: 11
    Последнее сообщение: 25.01.2016, 10:36
  4. Ответов: 7
    Последнее сообщение: 29.12.2011, 10:49
  5. Ответов: 3
    Последнее сообщение: 13.09.2011, 10:45

Ваши права

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