1. Обязательно представиться на русском языке кириллицей (заполнить поле "Имя").
  2. Фиктивные имена мы не приветствуем. Ивановых и Пупкиных здесь уже достаточно.
  3. Не надо писать свой вопрос в первую попавшуюся тему - всегда лучше создать новую тему.
  4. За поиск, предложение и обсуждение пиратского ПО и средств взлома - бан без предупреждения. Непонятно? - Читать здесь.
  5. Рекламу и частные объявления "куплю/продам/есть халтура" мы не размещаем ни на каких условиях.
  6. Перед тем как что-то написать - читать здесь, а затем здесь и здесь.
  7. Не надо писать в ЛС администраторам свои технические вопросы. Администраторы форума отлично знают как работает форум, а не все-все контроллеры, о которых тут пишут.

Расшифровка пакета ModBus TCP

RS-485, ProfiBUS, 4-20 mA, Wi-Fi, GSM и так далее

Модератор: Глоб.модераторы

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

Автор темы
Sinich
здесь недавно
здесь недавно
Сообщения: 12
Зарегистрирован: 08 апр 2016, 08:36
Имя: Юрий Катунов
Страна: Россия
город/регион: Тольятти
Благодарил (а): 2 раза

Расшифровка пакета ModBus TCP

Сообщение Sinich »

Здравствуйте. Мне поставили задачу - разработать программу передачи данных в ОРС сервер KepWare по протоколу ModBus.
Вообщем я настроил тестовый сервер KepServerEx, написал простенький сниффер на Дельфи ХЕ8 и считываю данные. Вот основной исходный код на дельфи:

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

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  bufSize: Integer;  // Размер буфера
  i: Integer; //итератор
  buf: TIDbytes; //Буфер для массива байтов
  mas: array of string; // Накопитель байтов
  s: string; //Строка для отображения байтов
begin
  try
    bufSize:= AContext.Connection.IOHandler.InputBuffer.Size;
    if bufSize > 0 then
    begin
      SetLength(mas, bufSize);
      Memo1.Lines.Add('Размер - ' + IntToStr(bufSize)); //Вывод размера буфера
      AContext.Connection.IOHandler.ReadBytes(buf, bufSize); //Читаем байты в буфер
      s:= ''; //Очищаем строку отображения
      for i:= 0 to bufSize - 1 do
      begin
        mas[i]:= ByteToHex(buf[i]); //Переводим буфер байтов в HEX-вид с преобразованием в строку
        s:= s + mas[i] + '-'; //Копим байты в строке отображения
      end;
    Memo1.Lines.Add(s);
    end;
  finally
  end;
end;
У меня там есть компонент Memo1 в который записывается лог приходящей информации на 502 порт.
Приходит всегда пакет размером = 12 байт!Его отображение:
OC-01-00-00-00-06-00-03-00-00-00-01
При этом этот пакет обновляется примерно раз в пол секунды, меняется только один бит(второй)! Вот как это выглядит:
OC-01-00-00-00-06-00-03-00-00-00-01
OC-02-00-00-00-06-00-03-00-00-00-01
OC-03-00-00-00-06-00-03-00-00-00-01
OC-04-00-00-00-06-00-03-00-00-00-01
OC-05-00-00-00-06-00-03-00-00-00-01
OC-06-00-00-00-06-00-03-00-00-00-01
Видимо второй бит какой то счётчик.
Далее...
Я начинаю добавлять теги в KepServerEx по одному, пакет начинает меняться
OC-01-00-00-00-06-00-03-00-00-00-01 - добавлен 1 тег
OC-01-00-00-00-06-00-03-00-00-00-02 - добавлен 2 тег
...
...
...
OC-01-00-00-00-06-00-03-00-00-00-0F - добавлен 16 тег
Я могу трактовать это как уникальный адрес.
Собственно вопрос: как мне узнать информацию что это вообще за пакет? Назначение его битов? Предполагаю что это ADU посылка, но она не похожа на ту, что описана в документации на modbus.org. Подскажите пожалуйста, в каком направлении мне поискать, как мне расшифровать эту посылку битов?
Спасибо.
Аватара пользователя

servo85
специалист по B&R
специалист по B&R
Сообщения: 157
Зарегистрирован: 15 фев 2014, 23:37
Имя: Волоснов Сергей
Страна: Казахстан
город/регион: Актобе
Благодарил (а): 19 раз
Поблагодарили: 12 раз

Расшифровка пакета ModBus TCP

Сообщение servo85 »

Автоматизация бардака порождает только автоматизированный бардак

Alex question
осмотрелся
осмотрелся
Сообщения: 144
Зарегистрирован: 20 янв 2015, 10:13
Имя: Алексей
Страна: Россия
Поблагодарили: 10 раз

Расшифровка пакета ModBus TCP

Сообщение Alex question »

http://www.cta.ru/cms/f/435973.pdf

Вторая часть статьи.
В принципе все просто и понятно расписано что и как.
Аватара пользователя

Автор темы
Sinich
здесь недавно
здесь недавно
Сообщения: 12
Зарегистрирован: 08 апр 2016, 08:36
Имя: Юрий Катунов
Страна: Россия
город/регион: Тольятти
Благодарил (а): 2 раза

Расшифровка пакета ModBus TCP

Сообщение Sinich »

Ничего не понятно. Это всё - Вода. Нужна конкретная информация, примеры, исходники...

SaNNy
освоился
освоился
Сообщения: 260
Зарегистрирован: 01 фев 2010, 10:37
Имя: Александр
Страна: Россия
город/регион: Брянск
Благодарил (а): 10 раз
Поблагодарили: 33 раза

Расшифровка пакета ModBus TCP

Сообщение SaNNy »

Sinich писал(а): Ничего не понятно. Это всё - Вода. Нужна конкретная информация, примеры, исходники...
Исходники чего? Modbus ?
Тогда смотрите http://libmodbus.org/
Аватара пользователя

servo85
специалист по B&R
специалист по B&R
Сообщения: 157
Зарегистрирован: 15 фев 2014, 23:37
Имя: Волоснов Сергей
Страна: Казахстан
город/регион: Актобе
Благодарил (а): 19 раз
Поблагодарили: 12 раз

Расшифровка пакета ModBus TCP

Сообщение servo85 »

0c0100000006000300000001
Part of Data Package Description Value
0C 01 Transaction identifier 0x0C01 (3073)
00 00 Protocol identifier 0 = MODBUS protocol
00 06 Length 0x0006 (6)
00 Unit identifier 0x00 (0)
03 Function code 0x03 (3) - Read Holding Registers
00 00 Starting address 0x0001 (1)
00 01 Quantity 0x0001 (1)
Автоматизация бардака порождает только автоматизированный бардак
Аватара пользователя

Автор темы
Sinich
здесь недавно
здесь недавно
Сообщения: 12
Зарегистрирован: 08 апр 2016, 08:36
Имя: Юрий Катунов
Страна: Россия
город/регион: Тольятти
Благодарил (а): 2 раза

Расшифровка пакета ModBus TCP

Сообщение Sinich »

Во, уже ближе к теме, спасибо servo85.
Даю более подробную информацию, как я делаю.
У меня два компьютера с разными IP адресами 192.168.0.103 и 192.168.0.105. Значит... на 192.168.0.105 у меня стоит сервер
KEPServerEx V4.0. На 192.168.0.103 стоит моя программа, которая должна обмениваться данными с сервером. Т.е. соответственно я пишу программу Slave(имитирую контроллер). Что я делаю?

Запускаю KEPServerEx V4.0.
File-New-Click to add chanel
ChanelName - Chanel1. Device Driver-ModBus Ethernet. Network Adapter-Default. Далее жму только всё готово.
Жму...Click to add device. Device Name -Device1. Device Model - Modbus. Теперь самое интересное Device ID. Я указываю IP адрес и DeviceID 192.168.0.103.0(адрес компьютера где работает моя программа). И далее всё по умолчанию...Port Number=502, IP Protocol=TCP/IP.
Далее добавляю тег... Click to add static tag. Ввожу Name=test. Address=400001. Жму зелёную галочку, выставляются настройки Data Type=Word. Client Access=Read/Write. Жму применит-ОК. Всё. Нажимаю Tools-> Launch OPC Quick Client. Запускается OPC Quick Client и моя программа на другом компьютере начинает тут же принимать пакеты. Пакеты вида указанные выше.
OC-01-00-00-00-06-00-03-00-00-00-01.
Получается... Мне нужно ответить на этот пакет. Нужно записать значение в поле Value. Читаю-листаю и до сих пору меня не получается найти как мне ответить на этот запрос. В http://modbus.rapidscada.net/ пытаюсь сделать Response ответ и...неудачи((. Пишут что в ответ на эту посылку нужно просто добавить данные в конец, но ничего не выходит OC-01-00-00-00-06-00-03-00-00-00-01(добавляю, 01). Отсылаются уже 13 байт и значение не появляется. Помогите пожалуйста советом, примером, какой комбинацией отправить ответ... Спасибо

Степа
осмотрелся
осмотрелся
Сообщения: 158
Зарегистрирован: 25 окт 2010, 10:30
Имя: Капуста Степан Степанович
Поблагодарили: 7 раз

Расшифровка пакета ModBus TCP

Сообщение Степа »

Sinich писал(а): OC-01-00-00-00-06-00-03-00-00-00-01
0C01 - идентификатор пакета. У вас он увеличивается на единицу, где-то он просто константа, где-то - еще как-то...
0000 - всегда такое значение.
0006 - длина информационной части пакета 6 байт.
00 - логический адрес контроллера /обычно равен 1, но.../
03 - команда чтения регистров
0000 - с адреса 0000
0001 - всего читается один регистр.
Sinich писал(а): Мне нужно ответить на этот пакет
Ответ должен быть типа такого:
0C01 - идентификатор повторить из запроса
0000 - всегда такое значение
0005 - длина информационной части
00 - свой адрес /повторить из запроса/
03 - функция
02 - число байт /регистры обычно 16-битные, потому число байт кратно двум, но бывают 32-х, тогда тут будет число кратное 4/
xxxx - значение регистра
и строка байт: 0C 01 00 00 00 05 00 03 02 xx xx
Порядок байт, насколько помнится, тут везде прямой - значение регистра 1234h прямо так и подаются в строку байт 12 34.
Аватара пользователя

Автор темы
Sinich
здесь недавно
здесь недавно
Сообщения: 12
Зарегистрирован: 08 апр 2016, 08:36
Имя: Юрий Катунов
Страна: Россия
город/регион: Тольятти
Благодарил (а): 2 раза

Расшифровка пакета ModBus TCP

Сообщение Sinich »

Степа, Спасибо огромное за подсказку! Исчерпывающий ответ. Только в ответе 03 - функция - это функция чтения, а 06 - функция записи. В сниффере Wireshark виден чёткий обмен запрос-ответ по протоколу modbus/tcp. Дописал я програмку, она отсылает пакет на KepServerEx. Но...

И последняя загвоздка у меня осталась мне непонятная. Настраиваю я KepServerEx как топике 5(выше) запускаю OPC Quick Client и там пишутся Value=Unknown, Quaility=Bad. Значения в OPC Quick Client не обновляются, хотя моя программа работает и снифферы Wireshark , установленные на обоих компьютерах, запущены и фиксируют входящие-выходящие пакеты.
Важный момент, не только моя программа, но и ModScan32, и Ananas не могут запивать значения в OPC Quick Client.(запускал на обоих компьютерах!). Если же в настройках OPC Quick Client я высталяю DeviceID 127.0.0.1.0 то данные записываются с обоих компьютеров. Если же указываю IP адрес - 192.168.0.103(ком-р где стоит моя программа) то обмен не происходит.

При этом пытаюсь изменить значение стандартными средствами OPC Quick Client ... Жму на Item ID правой мышкой, выбираю Sunchronous Write, ввожу Write Value=1234, жму Apply-OK. Значение не появляется, а появляются 2 ошибки:
1) В OPC Quick Client... Failed on item 'Chanel1.Device1.test' sunchronous write for group 'Chanel1.Device1' (HR=80004005)
2) В KepServerEx... Unable to write to address '400001 on device 'Chanel1.Device1.'

В OPC Quick Client есть другой пункт меня Asunchronous 2.0 Write. Тоже выскакивает 2 ошибки:
1) В OPC Quick Client... Failed on item 'Chanel1.Device1.test' for asunchronous 2.0 write treansaction 034B40FC (HR=80004005)
2) В KepServerEx... Unable to write to address '400001 on device 'Chanel1.Device1.'
Очень непонятное... Данные по прежнему не передаются

Степа
осмотрелся
осмотрелся
Сообщения: 158
Зарегистрирован: 25 окт 2010, 10:30
Имя: Капуста Степан Степанович
Поблагодарили: 7 раз

Расшифровка пакета ModBus TCP

Сообщение Степа »

Sinich писал(а): Только в ответе 03 - функция - это функция чтения, а 06 - функция записи.
В ответе должна быть именно та функция, которая присутствует в запросе. Максимум - в поле функции выставляется старший бит для сигнализации об ошибке. Тогда после номера функции иногда записывается байт с кодом ошибки. Т.е. если вопросили с функцией 3, то и ответить надо с той же функцией.
Ищите описание Modbus-RTU - информационная часть Modbus-TCP кроме поля CRC полностью идентична /это поле в Modbus-TCP отсутствует - предполагается, что контроль отсутствия ошибок в пакете уровней Ethernet и TCP вполне достаточен/.
Sinich писал(а): Очень непонятное...
Такое впечатление, что у вас проблема с адресами. Точнее, с их интерпретацией. Скажем, адрес регистра 400001 - логический, в поле адресов Modbus такого физически нет и быть не может - 16-битные адреса, самый старший адрес 65536. Логический адрес 400001 - вроде как нулевой /0000h/ или первый /0001h/ для функции 03h /не вчера разбирался, уже не помню наверное/.
В общем, разбираться с адресами надо...
Аватара пользователя

Автор темы
Sinich
здесь недавно
здесь недавно
Сообщения: 12
Зарегистрирован: 08 апр 2016, 08:36
Имя: Юрий Катунов
Страна: Россия
город/регион: Тольятти
Благодарил (а): 2 раза

Расшифровка пакета ModBus TCP

Сообщение Sinich »

Обращался в службу поддержки кипварэ. Вообщем суть разговора, используй 127.0.0.1 в качестве сервера кипварэ и к своим датчикам обращайся добавками <127.0.0.1>.0 127.0.0.1>.1 и т.д. и проблем не будет.
Как решился вопрос... поисками вышел на програмку MBTCPSlave(вот сайт разработчика программы http://www.tracker2.narod.ru/. там много вкусной информации по модбас). Связь с кипваре сервером удалось установить исходя из требований описанных выше. Проблема была в написанном мной коде, отсылающим пакет. Степан дан исчерпывающее описание Responce пакета, спасибо огромное ещё раз.
Итог - в общем и целом вопрос решился. Чуть пожже обязательно выложу уже полноценный, обкатанный, класс на дельфи, реализующий обмен данными с KepWare сервером по протоколу модбас с помощью пакетных запросов-ответов.
Аватара пользователя

Автор темы
Sinich
здесь недавно
здесь недавно
Сообщения: 12
Зарегистрирован: 08 апр 2016, 08:36
Имя: Юрий Катунов
Страна: Россия
город/регион: Тольятти
Благодарил (а): 2 раза

Расшифровка пакета ModBus TCP

Сообщение Sinich »

Собственно класс который получился. Ещё совсем сырец, но данные передаёт. Не обвешан try except finally, без функционала на выбор добавок <127.0.0.1>.0 127.0.0.1>.1. Но это вопрос времени. Тему можно закрывать...

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

{
Реализован класс позволяющий производить обмен данными по протоколу
ModBusTCP.
Запрос вида:
0С-01-00-00-00-06-00-03-00-00-00-01
0С01 - идентификатор пакета.
0000 - всегда такое значение
0006 - длина информационной части пакета 6 байт
00 - логический адрес контроллера/обычно равен 1, но.../
03 - команда чтения регистров
0000 - с адреса 0000
0001 - всего читается один регистр

Ответ вида:
0С-01-00-00-00-05-00-03-02-хх-хх
0С01 - идентификатор повторить из запроса
0000 - всегда такое значение
0005 - длина информационной части
00 - свой адрес /повторить из запроса/
03 - функция
02 - число байт /регистры обычно 16-битные, потому число байт кратно двум/
хххх - значение регистра

Адресация в KepServerEx начинается с нуля. От 0 до 254.
}

unit MasterModBusTCP;

interface

uses
  IdTCPServer, // Тут лежит компонент
  System.SysUtils, // Тут лежат вспомогательные процедуры
  IdContext, //Тут лежит AContext: TIdContext
  IdGlobal // Тут лежит тип данных TIdBytes
  ;

type

  TMasterModBusTCP = class(TObject)
  private
    Flag: Boolean; //Старт-стоп передачи данных
    Port: Integer; //Порт для работы ModBus
    LogicAddress: Byte; //Логический адрес контроллера
    BufForReading: TIdBytes; // Буфер для приёма посылок из KepWareEx
    BufForWriting: TIdBytes; // Буфер для записи посылок в KepWareEx
    SizeReadBuf, SizeWriteBuf: Integer; //Размеры пакетов буферов чтения и за-
//писи.
    DigitalValue: array of Integer; //Массив со значениями
    IdTCPServer: TIdTCPServer; // Компонент обеспечивает связь
    // second level initialization
    // private helper methods
    procedure CleanData; //Очистка буферов и их размеров
    procedure GenerateResponce(PacketLenght: Integer);
    // events handlers
    procedure TCPServerExecute(AContext: TIdContext); // Сработает, когда на
// порт 502 придёт запрос от KepWare
  public
    procedure WriteToKepServer(_Value: array of Integer; _LogicAddress: Byte);
    constructor Create;
    destructor Destroy;  override;
  end;  // TMasterModBusTCP

implementation

uses Unit1; // Нужно обязательно подлючить главный модуль программы(чтобы
// знать о форме дельфи).

procedure TMasterModBusTCP.GenerateResponce(PacketLenght: Integer);
const Support1 = 10; Support2 = 4; //Опора для определения длины ответа
var
  x1, x2, temp: Integer; // Переменная опора для определения длины пакета
  i, j: Integer;
begin
  x1:= PacketLenght - 1;
  x2:= PacketLenght - 1;

  SizeWriteBuf:= Support1 + PacketLenght + x1;
  SetLength(BufForWriting, SizeWriteBuf );

// Формируем пакет ответа
   BufForWriting[0]:= BufForReading[0];
   BufForWriting[1]:= BufForReading[1];
   BufForWriting[2]:= BufForReading[2];
   BufForWriting[3]:= BufForReading[3];
   BufForWriting[4]:= BufForReading[4]; //Остаются неизменными
   BufForWriting[5]:= Support2 + PacketLenght + x2;
   BufForWriting[6]:= LogicAddress;//BufForReading[6];
   BufForWriting[7]:= BufForReading[7];
   BufForWriting[8]:= PacketLenght * 2;

   i:= 9; // Устанавливаем сохранение на 9-ый байт
   j:= 0; // Размерность массива
   while i <= (SizeWriteBuf - 1)do
   begin
     if Flag = false then Break;
     BufForWriting[i]:= Hi($+DigitalValue[j]);
     i:= i+1;
     BufForWriting[i]:= Lo($+DigitalValue[j]);
     i:= i+1;
     j:= j+1;
   end;
end;

procedure TMasterModBusTCP.WriteToKepServer(_Value: array of Integer;
  _LogicAddress: Byte);
var
  i: Integer;
begin
  LogicAddress:= _LogicAddress;
  SetLength(DigitalValue, Length(_Value));

  for i := 0 to Length(_Value) - 1 do
    DigitalValue[i]:= _Value[i];
  Flag:= true; //Трактуем что данные появились
end;

procedure TMasterModBusTCP.CleanData;
begin
  BufForReading:= nil;
  BufForWriting:= nil;
  SizeReadBuf:= 0; SizeWriteBuf:= 0;
end;

procedure TMasterModBusTCP.TCPServerExecute(AContext: TIdContext);
begin
  CleanData;
  SizeReadBuf:= AContext.Connection.IOHandler.InputBuffer.Size; //Определяем
  //длину посылки, которая поступила на порт
  if SizeReadBuf = 12 then //Если  12 байт пришло на порт, то это именно те
  //данные, которые определяют модбас посылку.
  begin
    AContext.Connection.IOHandler.ReadBytes(BufForReading, SizeReadBuf); //Чи-
    //таем данные, которые пришли с порта.
    GenerateResponce(BufForReading[11]); //В 11-ом байте информация о коли-
    // честве тэгов в запросе.
     AContext.Connection.IOHandler.Write(BufForWriting, SizeWriteBuf); //Пере-
     //дать сформированную посылку на KepWare
  end;
end;

constructor TMasterModBusTCP.Create;
begin
  inherited Create;
  Port:= 502;
  Flag:= false;
  IdTCPServer:= TIdTCPServer.Create(Form1); //Кидаем компонент на форму
  with IdTCPServer do
  begin
    DefaultPort:= Port;
    OnExecute:= TCPServerExecute;
    Active:= true;
  end;
end;

destructor TMasterModBusTCP.Destroy;
begin
  CleanData;
  FreeAndNil(IdTCPServer);
  inherited Destroy;
end;
end.
Аватара пользователя

Автор темы
Sinich
здесь недавно
здесь недавно
Сообщения: 12
Зарегистрирован: 08 апр 2016, 08:36
Имя: Юрий Катунов
Страна: Россия
город/регион: Тольятти
Благодарил (а): 2 раза

Расшифровка пакета ModBus TCP

Сообщение Sinich »

Всем снова доброго... Уже написал полноценный класс и работаю со всеми типами данных, кроме Double и String. Собственно вопрос в чём, никак не могу найти программу, которая отсылала бы данные по протоколу ModBus TCP с типами данных Double и String. Я уж тут чего только не перелопачивал, никак не могу найти рабочие программы, которые обмениваются данными Double и String. Может кто сталкивался? Подкиньте ссылочки-тестеры кто с этими типами данных работал, видел когда либо, наводки на программки, рабочие решения... Я когда переработаю информацию, сюда код скину библиотеки, чтобы больше не спотыкались на эти же грабли... Спасибо коллеги...

Ryzhij
почётный участник форума
почётный участник форума
Сообщения: 5808
Зарегистрирован: 07 окт 2011, 09:12
Имя: Гаско Вячеслав Эриевич
Страна: Россия
город/регион: Рязань
Благодарил (а): 682 раза
Поблагодарили: 857 раз

Расшифровка пакета ModBus TCP

Сообщение Ryzhij »

В спецификациях протокола Modbus, как для линии последовательной связи, так и для передачи через Ethernet, не стандартизируются данные, длина которых отлична от 16 бит.
Как их упаковывать при передаче и потом парсить при приёме - это дело личное.
Те программы и програмно-аппаратные гейты, которые берутся принимать подобное, как правило имеют возможность настройки по свопингу байт и регистров.
---------------------------------------------------
«У человека в душе дыра размером с Бога, и каждый заполняет её как может.» (Жан-Поль Сартр)
"Ту пустоту, которая остаётся в душе, когда в ней нет Бога, и весь мир не может заполнить." (святитель Николай Сербский)

Михайло
эксперт
эксперт
Сообщения: 3650
Зарегистрирован: 10 ноя 2009, 04:58
Имя: Толмачев Михаил Алексеевич
город/регион: г. Чехов, МО
Благодарил (а): 8 раз
Поблагодарили: 287 раз

Расшифровка пакета ModBus TCP

Сообщение Михайло »

Модбас - очень древняя разработка, по ней можно слать только биты и слова (16 бит), а также наборы из n бит и наборы из n слов (но не все устройства поддерживают последние функции Модбаса).

kandiral
здесь недавно
здесь недавно
Сообщения: 7
Зарегистрирован: 26 окт 2016, 12:47
Имя: Кандирал Руслан Иванович
Страна: Украина
город/регион: Украина, Николаев

Расшифровка пакета ModBus TCP

Сообщение kandiral »

Вот тут пример использования Modbus протокола на Delphi
http://kandiral.ru/delphi/primer_pereda ... elphi.html

Поддерживается Modbus ASCII, Modbus RTU и Modbus TCP
Типы данных: Word, DWord, Smallint, Integer, Single, String
Ответить

Вернуться в «Интерфейсы, протоколы, связь»