Для протокола существуют открытые спецификации на официальном сайте, где подробно разбирается Modbus по составляющим, правда на английском. Modbus нужен, как правило, чтобы читать регистры с устройств, или записывать в них данные, даже по 1 биту, и еще ряд дополнительных свойств. Это может обеспечить взаимодействие программы и устройства, чтобы считать измеренные устройством данные (заряд батареи, показания вольтметра, температуры) и произвести настройку устройства.
Кратко покажу что такое modbus rtu:
unsigned char* response;
response = new unsigned char[8];
ReadFile(hSer, (char*)response, 8, &size, 0);
Так можно прочитать приходящие на сервер запросы modbus rtu. Структура 8 байт. FF это байт.
Может прийти сообщение вида: 02 03 A0 28 00 04 93 2A
Расшифрую сообщение. 02 — это номер устройства, к которому идет обращение. 03 — номер функции, т.е. 3 — читать регистры, а бывает еще записывать, регистры, коилы по 1 биту и т.д.
A0 28 если перевести в десятичную систему будет 41000 — номер регистра, 00 04 — значит еще 4 регистра нужно считать от 41000. Последние 2 числа — 2 байта кода CRC16.
Раз такое сообщение пришло, соответственно так же нужно заполнить массив на стороне отправки, и переправить либо через tcp сокеты, либо через com порт, или другим способом.
Ответ так же заполняется, но там будет уже сообщение вида: 02 03 08 00 01 00 02 00 03 00 04 95 В8 т.е. код устройства, код функции, количество передаваемых байт, 1234 данных (это как бы значения регистров). 2 байта код CRC.
Код CRC рассчитывается от сообщения не включая 2 байта кода CRC. Это для функции 3. В коде:
unsigned char* request
request = new unsigned char[reqsize];
Заполнить данными и подсчитать CRC:
crc.i = CRC16((unsigned char *)request, reqsize-2);
request[reqsize-2] = crc.ch[1];
request[reqsize-1] = crc.ch[0];
И отправить по Serial порту:
BOOL iRet = WriteFile(hSer, (char*)request, reqsize, &dwBytesWritten, NULL );
Таким образом отправили и ответили на функцию 3 (чтение нескольких регистров) по протоколу Modbus.
Спасибо за внимание! Читайте спецификации на официальном сайте протокола.
Комментарии (7)
grossws
30.12.2016 18:04+1RTU варианте поверх работы с Serial портом, или 485 интерфейса насколько это встречалось в моей практике.
RS485 — тоже serial интерфейс, противопоставление некорректно. Modbus RTU (и ASCII, который вы не упомянули) может работать по произвольному последовательному интерфейсу (RS232, RS422, RS485, UART, как примеры).
Сама же статья непонятно о чём. Вы научились писать/читать из serial интерфейса и считать crc16 с помощью внешней функции? Хорошо.
Вы ничего не написали про структуру фрейма, коды операций, структуру адресного пространства устройства (отличия discrete input, coil, input register, holding register, независимость адресации), два варианта адресации в клиентских библиотеках (десятичная запись адреса часто смещена на 1) и кучу других базовых аспектов.
GreyPhantom
30.12.2016 19:14+6«Краткость- сестра...» У вас, похоже, она родная…
Читайте спецификации на официальном сайте протокола.
Тогда зачем вообще этот пост? Показать что Вы наконец-то разобрались с довольно простым протоколом? Хотя бы ссылку на «официальный сайт протокола» привели бы что-ли.
timka05
30.12.2016 22:09+4Походу реальная цель этого опуса — засветить имя юзера (которое адрес сайта). Другой мысли нет.
sozercanie_kosmosa
02.01.2017 11:16Полностью поддерживаю, предыдущий комментарий, какая то бессмысленная статья получается,
непонятно какие цели преследует автор.
Абсолютно вырванные из контекста куски кода
crc.i = CRC16((unsigned char *)request, reqsize-2); request[reqsize-2] = crc.ch[1]; request[reqsize-1] = crc.ch[0];
что за crc.i — что это за структура?
что за request откуда взялся, как объявлен?
какие еще функции в MB протоколе существуют?
какие есть коды ошибок и как их обрабатывать?
какая особенность расчета контрольной суммы именно для MB протокола?
отсылка к оф. докам, это не серьезно
После прочтения статьи образуется еще больше вопросов и это не следствие осознание проблемы.
ProstoTyoma
Желающим использовать Modbus могу подсказать две «неприятности», с которыми столкнулся на опыте.
Первая — отсутствие преамбулы. Точнее она есть, это задержка в 3.5 символа. Если же вы пытаетесь прочитать дамп Modbus/RTU данных из файла, или получаете их из ненадёжного по задержкам канала, или используете какие-то преобразователи типа 485 over TCP/IP, то эти 3.5 вы не найдёте. Или найдёте посередине половины пакетов. В итоге приходится как-то умно детектить границы пакетов по номеру устройства и CRC, что неприятно.
Вторая — отсутствие стандарта на Modbus\UDP, который на самом деле существует, но не стандартизирован.
А в остальном — хороший удобный протокол.
A1ien
Есть Modbus ASCII, там все есть
ProstoTyoma
Ну, это какая-то другая крайность.