Modbus Master Slave обмен
Modbus Slave 127.0.0.1 ID56 HR0 VAL=4
Результат опроса
Modbus TCP
Запрос Tx:002684-07 |F4 00| |00 00| |00 06| |38| |03 00 00 00 01|
Ответ Rx:002685-07 |F4 00| |00 00| |00 05| |38| |03 02 00 04|
Встречается модификация с 1 байтом ID-транзакции
Запрос Tx:002684-07 |F4| |00 00| |00 06| |38| |03 00 00 00 01|
Ответ Rx:002685-07 |F4| |00 00| |00 05| |38| |03 02 00 04|
Modbus TCP с ошибкой запроса
Запрос Tx:002684-07 |F4 00| |00 00| |00 06| |38| |03 00 00 00 01|
Ответ Rx:002685-07 |F4 00| |00 00| |00 03| |38| |83 06|
Modbus RTU over TCP/IP
Запрос Tx:018165-38 |38| |03 00 00 00 01| 81 63
Ответ Rx:018166-38 |38| |03 02 00 04| 25 82
Modbus RTU
Запрос Tx:000063-01 |01| |04 00 00 00 01| |31 CA|
Ответ Rx:000064-01 |01| |04 02 00 00| |B9 30|
ADU (Application Data Unit) — пакет Modbus целиком, со всеми заголовками, PDU, контрольной суммой, адресом и маркерами. Отличается, в зависимости от реализации протокола.
PDU (protocol data unit) — основная часть пакета, одинаковая для всех реализаций протокола. Содержит сам payload.
Запрос кадр ADU
ID-транзакции | ID-протокола | Длина пакета | Адрес Slave | Кадр PDU |
---|---|---|---|---|
2 байта | 2 байта | 2 байта | 1 байт | <=253 байта |
F4 00 | 00 00 | 00 06 | 38 | 03 00 00 00 01 |
Запрос кадр PDU
- 03 - функция
- 00 00 - адрес первого регистр
- 00 01 - количество регистров
Ответ кадр ADU
ID-транзакции | ID-протокола | Длина пакета | Адрес Slave | Кадр PDU |
---|---|---|---|---|
2 байта | 2 байта | 2 байта | 1 байт | <=253 байта |
F4 00 | 00 00 | 00 05 | 38 | 03 02 00 04 |
Ответ кадр PDU
- 03 - функция
- 02 - количенство передаваемых байт
- 00 04 - данные
Ответ кадр PDU с ошибкой
- 83 - функция (80 +03) - ошибка
- 06 - Код ошибки
Расчет контрольной суммы
Используется CRC-16 тип контрольной суммы
Калькулятор расчета
https://www.lammertbies.nl/comm/info/crc-calculation
Modbus RTU
Tx:000063-01 |01| |04 00 00 00 01| |31 CA|
Rx:000064-01 |01| |04 02 00 00| |B9 30|
Python code расчета контрольной суммы
def calculate_crc16(data_bytes):
"""
Calculate CRC-16 (Modbus) checksum for the given bytes.
Polynomial: 0x8005 (x^16 + x^15 + x^2 + 1)
Initial value: 0xFFFF
"""
crc = 0xFFFF
for byte in data_bytes:
crc ^= byte
for _ in range(8):
if crc & 0x0001:
crc >>= 1
crc ^= 0xA001 # 0xA001 is the reverse of 0x8005
else:
crc >>= 1
return crc
# Input data in hex: 01 04 00 00 00 01
data = bytes.fromhex('01 04 00 00 00 01')
# Calculate CRC-16
crc = calculate_crc16(data)
# The result is in little-endian format (LSB first)
crc_bytes = crc.to_bytes(2, byteorder='little')
print(f"CRC-16 (Modbus) of 01 04 00 00 00 01: 0x{crc:04X}")
print(f"Bytes (LSB first): {crc_bytes.hex(' ')}")
Результат
CRC-16 (Modbus) of 01 04 00 00 00 01: 0xCA31
Bytes (LSB first): 31 ca
[Finished in 97ms]