modbus — Протокол Modbus RTU slave

Этот модуль предоставляет реализацию Modbus RTU slave на чистом Python, который обменивается данными по UART. Он поддерживает внутренний массив holding-регистров и отвечает на стандартные коды функций Modbus 0x03 (чтение holding-регистров), 0x06 (запись одного регистра) и 0x10 (запись нескольких регистров). CRC-16 (полином Modbus) вычисляется с помощью таблицы поиска.

Например:

from machine import UART
from modbus import ModbusRTU

uart = UART(1, 115200, timeout=10, timeout_char=10)
modbus = ModbusRTU(uart, slave_id=0x01, register_num=30)

while True:
    if modbus.any():
        modbus.handle(debug=False)

class ModbusRTU

Modbus RTU slave, который считывает запросы из UART, обновляет свой внутренний массив регистров и записывает соответствующий ответ обратно в UART.

class modbus.ModbusRTU(uart: machine.UART, slave_id: int = 0x01, register_num: int = 30)

Создаёт slave ModbusRTU.

  • uart — это экземпляр UART (например, machine.UART или pyb.UART), используемый для отправки и приёма кадров Modbus. UART должен быть настроен с соответствующей скоростью передачи, чётностью и таймаутами перед передачей.

  • slave_id — это адрес Modbus slave (1-247), на который будет отвечать данный экземпляр. Кадры, адресованные другим slave ID, игнорируются.

  • register_num — это количество 16-битных holding-регистров, поддерживающих данный slave. Регистры хранятся в списке REGISTER и инициализируются нулями.

SLAVE_ID: int

Адрес Modbus slave, на который будет отвечать данный экземпляр. Устанавливается из аргумента конструктора slave_id.

uart: machine.UART

Экземпляр UART, переданный в конструктор и используемый для всего ввода-вывода.

register_num: int

Количество 16-битных holding-регистров, устанавливаемое из аргумента конструктора register_num.

REGISTER: list[int]

Список длиной register_num, содержащий текущие 16-битные значения регистров. Операции чтения и записи, выполняемые через входящие запросы Modbus, обновляют этот список. Код приложения может читать из этого списка или записывать в него напрямую для обмена данными с Modbus master.

CRC16_TABLE: list[int]

Предварительно вычисленная таблица поиска из 256 элементов для полинома Modbus CRC-16, используемая методом crc16().

any() int

Возвращает количество байтов, доступных в данный момент в приёмном буфере UART (делегирует uart.any()). Используйте это для проверки наличия входящего запроса перед вызовом handle().

clear() None

Сбрасывает каждый элемент в REGISTER в 0.

crc16(data: bytes | bytearray) bytes

Вычисляет Modbus CRC-16 для data с использованием CRC16_TABLE и возвращает его в виде 2-байтового объекта bytes с порядком байтов little-endian, пригодного для добавления к кадру Modbus.

  • data — это bytes/bytearray (или любой итерируемый объект целых чисел), содержащий байты для вычисления контрольной суммы.

handle(debug: bool = False) None

Считывает один запрос Modbus из UART, при необходимости обновляет внутренний массив регистров и записывает соответствующий ответ обратно в UART.

Поддерживаемые коды функций:

  • 0x03 чтение holding-регистров — отвечает запрошенным диапазоном значений регистров.

  • 0x06 запись одного регистра — записывает один регистр и возвращает адрес и значение.

  • 0x10 запись нескольких регистров — записывает непрерывный диапазон регистров и отвечает начальным адресом и количеством.

Ответы с исключениями Modbus возвращаются для:

  • Недопустимая функция (0x01) — неподдерживаемый код функции.

  • Недопустимый адрес данных (0x02) — индекс регистра вне диапазона.

  • Недопустимое значение данных (0x03) — количество байтов не соответствует объявленному количеству регистров.

Кадры, CRC которых не совпадает или slave-адрес которых не совпадает с SLAVE_ID, незаметно отбрасываются.

  • debug если True, выводит в REPL необработанный запрос, разобранный код функции, сгенерированный ответ и любые детали ошибок. По умолчанию False.