На форуме обязательно:
  1. Заполнить свой профиль НА РУССКОМ ЯЗЫКЕ КИРИЛЛИЦЕЙ. См. Правила, п.2.d.
  2. Не писать свой вопрос в первую попавшуюся тему, а вместо этого создать свою. См. Правила, п.3.a.

Рекламу мы не размещаем ни на каких условиях.

CP341, Опрос Modbus-устройства.

Ответить

Автор темы
FOTONNN
здесь недавно
здесь недавно
Сообщения: 6
Зарегистрирован: 14 сен 2016, 08:26
Имя: Сорокин Дмитрий Валентинович

CP341, Опрос Modbus-устройства.

Сообщение FOTONNN » 23 ноя 2016, 15:19

Добрый день, нашел тут тему подобную, но обновлю. У кого есть опыт не могли бы помочь?

Хотел сориентироваться в примерах Modbus RTU протоколом.

Дело в том что ставят задачу опрашивать несколько устройств через CP341 соответственно через Simatic 300 серии.

Хотел бы проверить реально действующие примеры на таком железе.

Интересует именно формирование разных запросов на разные устройства с Modbus. Немного не хватает опыта по такого рода задачам,
хотелось бы определится как должны формироваться запросы.
Насколько я понимаю сколько будет разных посылок, столько надо будет формировать различных вызовов DB на каждый отдельный запрос.
Каким образом лучше формировать сами посылки запросов чтобы система работала гибко и просто /если принять во внимание необходимость опроса разных устрйоств.

Аватара пользователя

CHANt
эксперт
эксперт
Сообщения: 1313
Зарегистрирован: 25 июл 2008, 09:25
Имя: Гринев Эдуард Владимирович
Откуда: Оренбург
Благодарил (а): 17 раз
Поблагодарили: 56 раз
Контактная информация:

CP341, Опрос Modbus-устройства.

Сообщение CHANt » 23 ноя 2016, 23:38

Донгл драйвера Модбас, что мастер, что слейв, стоил в районе 1500 евро для CP341 ))) Да, на оф. форуме Сименса хорошие люди раздавали самописные драйвера под любые конфигурации, но, форум полетел... Может рассмотрите варианты:
- покупки самой дешевой модели S7-1200 с нужным коммуникационником, и официально и модбас бесплатен, и примеров куча.
- покупки аппаратного шлюза модбас/профибас как вариант от Anybus http://www.industrialnets.ru/catalogue/ ... odbus-rtu/
--------------------------------------------------------------------------------------------
"Почти все начальники - дилетанты." © цитата из поста hell_boy )))


Автор темы
FOTONNN
здесь недавно
здесь недавно
Сообщения: 6
Зарегистрирован: 14 сен 2016, 08:26
Имя: Сорокин Дмитрий Валентинович

CP341, Опрос Modbus-устройства.

Сообщение FOTONNN » 24 ноя 2016, 06:55

Все есть)
Нужны примеры, желательно на LD

Аватара пользователя

CHANt
эксперт
эксперт
Сообщения: 1313
Зарегистрирован: 25 июл 2008, 09:25
Имя: Гринев Эдуард Владимирович
Откуда: Оренбург
Благодарил (а): 17 раз
Поблагодарили: 56 раз
Контактная информация:

CP341, Опрос Modbus-устройства.

Сообщение CHANt » 24 ноя 2016, 11:39

Примеры под новые 1200 посмотрите - там и как порт открыть и как организовать вызов, т.е. считать, сменить признак на запись, записать, сменить адрес устройства и опять считать и так по кругу - в этом и есть отличие от встроенного профибаса где коммуникационник опросы сам устраивает )))
--------------------------------------------------------------------------------------------
"Почти все начальники - дилетанты." © цитата из поста hell_boy )))


Boroda4
новенький
новенький
Сообщения: 2
Зарегистрирован: 27 ноя 2016, 08:49
Имя: Перерва Алексей Петрович
Поблагодарили: 1 раз

CP341, Опрос Modbus-устройства.

Сообщение Boroda4 » 27 ноя 2016, 09:21

Держи пример:

Код: Выделить всё

FUNCTION_BLOCK FB10

VAR_INPUT
    enable    : BOOL; //разрешение работы
    Addr_CP   : INT;  // ID
    
    dbD1 : INT  := 0; //номер блока данных первого пакета
    P1_EN   : BOOL := 0; //разрешения обмена первого пакета

    dbD2 : INT  := 0; //номер блока данных второго пакета
    P2_EN   : BOOL := 0; //разрешения обмена для второго пакета
    
END_VAR

VAR_IN_OUT
    init {S7_read_back := 'false'}: BOOL := true; 
END_VAR

VAR_OUTPUT
    Err_Send : BOOL;  // Ошибка функции передачи
    Err_Recv : BOOL;  // Ошибка функции приема
    ERROR     : BOOL;  // ERROR LINK
    
    ERR_P1 : BOOL; //ошибка приема/передачи первого пакета  
    ERR_P2 : BOOL; //ошибка приема/передачи второго пакета
    
        
    ERR_SND  : WORD;  //код ошибки функции передачи
    ERR_RCV  : WORD;  //код ошибки функции приема
    
    ES_CNT      {S7_visible := 'false'} : INT; //счетчик ошибок передачи
    ER_CNT      {S7_visible := 'false'} : INT; //счетчик ошибок приема
    
    paket       {S7_visible := 'false'} : INT; //номер текущего пакета
    Point       {S7_visible := 'false'} : INT; //Точка входа    
    timeout     {S7_visible := 'false'} : INT; //ожидание ответа
    
    ACK_ERR      {S7_visible := 'false'} : BOOL; //ведомый возвращает ошибку
    ACK_ERR_CODE {S7_visible := 'false'} : INT; //ответный код ошибки ведомого
    ACK_ERR_CNT  {S7_visible := 'false'} : INT; //счетчик ошибок в ответе ведомого
    CRCERR       {S7_visible := 'false'} : BOOL; //ошибка CRC пакета
    CRCERR_CNT   {S7_visible := 'false'} : INT; //счетчик ошибок CRC
   
END_VAR


VAR_TEMP
  // Temporary Variables
  i,k, CRCCount : INT;
  ERR_SFC  : INT; //ошибка вызова SFC
  lenght   : INT; //размер копируемых данных
  STATUS   : WORD;
  LEN_SEND : WORD;  // Длина передаваемого пакета
  LEN_RECV : WORD;  // Длина принатого пакета
  Err_S    : BOOL;
  Err_R    : BOOL;
  
  tbit : BOOL;
  
  TempPointer: ANY; // Artificial variable 
  AnyPointer AT TempPointer: STRUCT 
        s7const  :BYTE; // константа s7
        datatype :BYTE; // тип данных
        lenght   :WORD; // размер передаваемых данных
        db_num   :WORD; // номер блока данных
        area     :DWORD; //стратовый адрес 
        END_STRUCT;

    tdword : DWORD;
    stdword AT tdword : STRUCT
        B1: BYTE;
        B2: BYTE;
        B3: BYTE;
        B4: BYTE;
    END_STRUCT;
    

END_VAR
VAR
  // Static Variables
  Done     : BOOL;     // Передача успешна
  NDR      : BOOL;     // Прием успешен
  REQ      : BOOL;     // Разрешение перeдачи 
  
  CRC16    : WORD;
  
  SND_DATA : P_SND_RK;
  RCV_DATA : P_RCV_RK;
  
  RECV_Message : ARRAY [1..250] OF BYTE;   // Массив принятых данных
  SEND_Message : ARRAY [1..40] OF BYTE;   // Массив переданных данных
  
  Addr_Slave: INT;   //адрес ведомого
  
END_VAR
//-----------------------------------------------------------------
//инициализация

IF init THEN
    
    Err_Send := false;
    Err_Recv := false;
    ERROR    := false;
    ERR_P1   := false;
    ERR_P2   := false;
    ACK_ERR  := false;
    CRCERR   := false;
    init     := false;
    
    paket        :=0;
    point        :=0;
    timeout      :=0;
    ERR_SND      :=0;
    ERR_RCV      :=0;
    ES_CNT       :=0;
    ER_CNT       :=0;
    ACK_ERR_CODE :=0;
    ACK_ERR_CNT  :=0;
    CRCERR_CNT   :=0;

    
END_IF;

//рарешение работы
IF NOT enable THEN RETURN; END_IF; 


//-----------------------------------------------------------------
//формирование пакета
IF point = 0 THEN  //формирование запроса
     
    
  CASE paket OF
   0 ://Запрос первого пакета
        IF NOT P1_EN THEN //разрешение на обмен данных параметров
            paket := paket +1;
            RETURN;
        END_IF;
        
        Send_Message[1] := INT_TO_BYTE(4); // Адрес слейва
        Send_Message[2] := B#16#03; //функция чтения входов
        Send_Message[3] := B#16#00; //стартовый адрес hi
        Send_Message[4] := B#16#14; //стартовый адрес lo 
        Send_Message[5] := B#16#00; //количество параметров hi
        Send_Message[6] := B#16#01; //количество параметров lo:  
        CRCCount :=6;
      
    1://Запрос второго пакета
        IF NOT P2_EN THEN //разрешение на обмен данных параметров
            paket := paket +1;
            RETURN;
        END_IF;
        
        Send_Message[1] := INT_TO_BYTE(5); // Адрес слейва
        Send_Message[2] := B#16#03; //функция чтения входов
        Send_Message[3] := B#16#00; //стартовый адрес hi
        Send_Message[4] := B#16#3A; //стартовый адрес lo, 
        Send_Message[5] := B#16#00; //количество параметров hi
        Send_Message[6] := B#16#02; //количество параметров lo  
        CRCCount :=6;
        
             
  ELSE:
    paket :=0;
    RETURN;
  END_CASE;
  
//расчет контрольной суммы
CRC16:=W#16#FFFF;
  
FOR i := 1 TO CRCCount BY 1 DO
CRC16 := CRC16 XOR Send_Message[i]; 
  FOR k := 1 TO 8 DO
   IF (CRC16 AND W#16#0001)=W#16#0000 THEN
   CRC16 := SHR (IN:=CRC16, N:=1); 
   ELSE
   CRC16 := SHR (IN:=CRC16, N:=1); 
   CRC16 := CRC16 XOR W#16#A001;
   END_IF;    
  END_FOR;
END_FOR;

point :=1;
END_IF;//IF point = 0    

//-----------------------------------------------------------------
//отправка пакета
IF Point = 1 THEN // Передача данных
        CASE paket OF
            0,1: //первый пакет
                Send_Message[7]:=WORD_TO_BYTE(CRC16);
                Send_Message[8]:=WORD_TO_BYTE(SHR (IN:=CRC16, N:=8));
                LEN_SEND := 8;
            END_CASE;
        
    //берем указатель  на буфер отправки для получения номера ДБ 
    TempPointer := SEND_Message;
    
    
    SND_DATA(SF := 'S' // IN: CHAR
                   ,REQ := REQ // IN: BOOL
                   ,R := false // IN: BOOL
                   ,LADDR := Addr_CP // IN: INT
                   ,DB_NO :=  WORD_TO_INT(AnyPointer.db_num)// IN: INT
                   ,DBB_NO := DWORD_TO_INT(AnyPointer.area AND DW#16#7bff_ffff)/8 // IN: INT
                   ,LEN :=  WORD_TO_INT(LEN_SEND)// IN: INT
                 ); 
       DONE  := SND_DATA.DONE; // OUT: BOOL
       Err_S := SND_DATA.ERROR; // OUT: BOOL
       STATUS:= SND_DATA.STATUS; // OUT: WORD
            
      IF DONE THEN
          Err_Send := false;
          ES_CNT :=0;
          Point := point+1;
          ERR_SND :=0;
      ELSIF NOT REQ THEN
             REQ := true;
      ELSE
             REQ := false;
      END_IF;
       
       IF Err_S THEN 
           Err_Send := true;
           ERR_SND := STATUS;
           ES_CNT := ES_CNT + 1;
           IF (ES_CNT < 3) THEN
               point :=1; //если счетчик ошибок чтения меньше заданного, то отправляем пакет еще раз
               RETURN;
           ELSE
               //если счетчик равен заданному, то переходим к отправке другого пакета
               Point := 0;
               paket := paket +1;
               ES_CNT := 0;
           END_IF;//IF (ES_CNT
           
       END_IF; //Err_S = true
   
     
END_IF;//IF Point = 1

//-----------------------------------------------------------------
//прием пакета
IF Point = 2 THEN // Прием данных 
    
    //берем указатель на буфер приема для определения номера дб и смещения
    TempPointer := RECV_Message;
    RCV_DATA(EN_R :=  true// IN: BOOL
                   ,R := false // IN: BOOL
                   ,LADDR :=Addr_CP  // IN: INT
                   ,DB_NO := WORD_TO_INT(AnyPointer.db_num) // IN: INT
                   ,DBB_NO := DWORD_TO_INT(AnyPointer.area AND DW#16#7bff_ffff)/8 // IN: INT
                   ); 
       NDR      := RCV_DATA.NDR; // OUT: BOOL
       Err_R    := RCV_DATA.ERROR; // OUT: BOOL
       //LEN_RECV := INT_TO_WORD(RCV_DATA.LEN); // OUT: INT
       STATUS   := RCV_DATA.STATUS; // OUT: WORD
          
  
        IF NDR THEN //если есть подтверждение приема, то переходим к разбору пакета
            point := point +1;
            Timeout  :=0;
            ERR_RCV  :=0;
            Err_Recv :=false;
        ELSE //если нет подтверждения
            ERR_RCV  :=STATUS;
            IF Err_R OR (timeout >= 10) THEN //проверяем на ошибку таймаут
                
                ER_CNT := ER_CNT +1;
                timeout :=0;
                //IF Err_R THEN point :=1; END_IF;
            ELSE
                timeout :=timeout +1;
                
            END_IF;
            
            
            
            IF ER_CNT >=3 THEN    //если счетчик ошибок больше заданного, то
                timeout  :=0;
                ER_CNT   :=0;
                ERR_Recv := true; //и выставляем флаг ошибки чтения
                paket    := paket +1; //переходим к чтению следующего пакета
                point    :=0;
                //RETURN;    
            END_IF;
        END_IF;//IF NDR
          
END_IF; //if point =2


//-----------------------------------------------------------------
//разбор принятого пакета
IF point =3 THEN
    IF (Err_Send = false) AND (Err_Recv = false) THEN //если нету ошибок приема/передачи
        
        
        
        //проверка на корректность отработки функции
        IF ((RECV_Message[2] AND b#16#80)<>0) THEN //если есть признак ошибки в ответе
            ACK_ERR_CODE := BYTE_TO_INT(RECV_Message[3]);
            ACK_ERR := true;
            IF ACK_ERR_CNT >=3 THEN
                ACK_ERR_CODE := 0;
                ACK_ERR_CNT := 0;
                ACK_ERR := false;
                CASE paket OF
                        0: //ошибка приёма первого пакета
                            ERR_P1 := true;
                        1: //ошибка приёма второго пакета
                            ERR_P2 := true;
                ELSE
                    ;
                END_CASE;
                point :=0;
                paket := paket+1;
                RETURN;
            ELSE//ACK_ERR_CNT >=3
                ACK_ERR_CNT := ACK_ERR_CNT +1;
                point := 0;
                //RETURN;
            END_IF;//ACK_ERR_CNT >=3
            RETURN;             
        ELSE //IF ((RECV_Message[2] если есть признак ошибки в ответе
            ACK_ERR_CODE := 0;
            ACK_ERR_CNT := 0;
            ACK_ERR := false;
       
        END_IF; //IF ((RECV_Message[2] если есть признак ошибки в ответе
        
        //проверка контрольной суммы принятого пакета
        //расположение контрольной суммы зависит от вида пакета
            CRCCount := BYTE_TO_INT(RECV_Message[3])+3;
            
        //расчет контрольной суммы
        CRC16:=W#16#FFFF;
        FOR i := 1 TO CRCCount BY 1 DO
        CRC16 := CRC16 XOR RECV_Message[i]; 
          FOR k := 1 TO 8 DO
           IF (CRC16 AND W#16#0001)=W#16#0000 THEN
           CRC16 := SHR (IN:=CRC16, N:=1); 
           ELSE
           CRC16 := SHR (IN:=CRC16, N:=1); 
           CRC16 := CRC16 XOR W#16#A001;
           END_IF;    
          END_FOR;
        END_FOR;
    
        IF (RECV_Message[CRCCount+1] <> WORD_TO_BYTE(CRC16 AND w#16#ff)) 
            OR (RECV_Message[CRCCount+2] <>WORD_TO_BYTE(SHR (IN:=CRC16, N:=8)))
        THEN
            CRCERR_CNT := CRCERR_CNT +1;
            CRCERR := true;
            IF (CRCERR_CNT >= 3) THEN 
                              CRCERR_CNT := 0;
               CRCERR := false;
               //выставление соответствующего бита ошибок
                CASE paket OF
                        0: //ошибка приёма первого пакета
                            ERR_P1 := true;
                        1: //ошибка приёма второго пакета
                            ERR_P2 := true;
                ELSE
                    ;
                END_CASE;
               Paket := Paket+1; 
               Point := 0;
               RETURN;
           ELSE
               Point := 1;
           END_IF;
           RETURN;
       ELSE//IF (RECV_Message[CRCCount+1] 
           CRCERR_CNT := 0;
           CRCERR := false;
       END_IF;//IF (RECV_Message[CRCCount+1] 
       ERR_P1 := false;
       //если не было ошибок, то разбираем принятый пакет
       CASE paket OF
           0://первый пакет
                
                Byte_to_bit(ibyte := RECV_Message[5] // IN: BYTE
                            ,obit0 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD1)).dx0.0 // OUT: BOOL
                            ,obit1 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD1)).dx0.1 // OUT: BOOL
                            ,obit2 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD1)).dx0.2 // OUT: BOOL
                            ,obit3 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD1)).dx0.3 // OUT: BOOL
                            ,obit4 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD1)).dx0.4 // OUT: BOOL
                            ,obit5 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD1)).dx0.5 // OUT: BOOL
                            ,obit6 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD1)).dx0.6 // OUT: BOOL
                            ,obit7 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD1)).dx0.7 // OUT: BOOL
                            ); // VOID
                            
                

                                                  
             ERR_P1 := false;
          
           1://второй пакет
            
                Byte_to_bit(ibyte := RECV_Message[5] // IN: BYTE
                            ,obit0 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx1.0 // OUT: BOOL
                            ,obit1 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx1.1 // OUT: BOOL
                            ,obit2 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx1.2 // OUT: BOOL
                            ,obit3 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx1.3 // OUT: BOOL
                            ,obit4 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx1.4 // OUT: BOOL
                            ,obit5 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx1.5 // OUT: BOOL
                            ,obit6 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx1.6 // OUT: BOOL
                            ,obit7 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx1.7 // OUT: BOOL
                            ); // VOID
                            
                Byte_to_bit(ibyte := RECV_Message[7] // IN: BYTE
                            ,obit0 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx2.0 // OUT: BOOL
                            ,obit1 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx2.1 // OUT: BOOL
                            ,obit2 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx2.2 // OUT: BOOL
                            ,obit3 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx2.3 // OUT: BOOL
                            ,obit4 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx2.4 // OUT: BOOL
                            ,obit5 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx2.5 // OUT: BOOL
                            ,obit6 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx2.6 // OUT: BOOL
                            ,obit7 := WORD_TO_BLOCK_DB(INT_TO_WORD(dbD2)).dx2.7 // OUT: BOOL
                            ); // VOID
                            
            ERR_P2 := false;                  
                
        ELSE
            point :=0;
            paket :=0;
            RETURN;
        END_CASE;//paket
        
        ;
    ELSE//если есть ошибки приема/передачи
        //выставление соответствующего бита ошибок
        CASE paket OF
                        0: //ошибка приёма первого пакета
                            ERR_P1 := true;
                        1: //ошибка приёма второго пакета
                            ERR_P2 := true;
                ELSE
                    ;
                END_CASE;
        paket :=paket+1;
        point :=0;
        ;
    END_IF; //если нет ошибок приема/передачи
    
    
    paket := paket +1;   
    IF paket >=2 THEN //переход на начало после приёма последнего пакета
        paket :=0;
        point :=0;
    END_IF;
    point:= 0;

END_IF;//IF point =3
  ;
END_FUNCTION_BLOCK




akin
здесь недавно
здесь недавно
Сообщения: 4
Зарегистрирован: 15 сен 2014, 06:30
Имя: Вяткин Олег Николаевич
Благодарил (а): 3 раза

CP341, Опрос Modbus-устройства.

Сообщение akin » 13 май 2017, 12:19

Добрый день, передо мной стоит та же задача, Вы нашли решение проблемы? у меня ср341 вроде общается с терминалом (rx/ tx при отправление како го либо запроса) , но не могу ни как правильно сформировать запрос или ответ получить, вобщем кроме мигания лампочек ни чего не добился.....правильно ли я понимаю, что CP общается с устройством через FB8, FB7? может кто-нибудь сможет доходчиво разжевать формирование запросов-ответов


akin
здесь недавно
здесь недавно
Сообщения: 4
Зарегистрирован: 15 сен 2014, 06:30
Имя: Вяткин Олег Николаевич
Благодарил (а): 3 раза

CP341, Опрос Modbus-устройства.

Сообщение akin » 14 май 2017, 09:24

В общем я разобрался! :good:


Jallo
здесь недавно
здесь недавно
Сообщения: 6
Зарегистрирован: 05 июн 2017, 08:50
Имя: Александр

CP341, Опрос Modbus-устройства.

Сообщение Jallo » 13 дек 2017, 12:48

akin писал(а): В общем я разобрался! :good:
Как вы это сделали? Расскажите пожалуйста. Не могу сформировать запрос и получить ответ от Овен ТРМ-138 :ges_no:

Ответить

Вернуться в «ПЛК SIMATIC (S7-200, S7-1200, S7-300, S7-400, S7-1500, ET200)»