modbus --- Modbus RTU 从站协议

本模块提供了一个纯 Python 实现的 Modbus RTU 从站,它通过 UART 进行通信。它维护一个内部保持寄存器数组,并响应标准的 Modbus 功能码 0x03(读保持寄存器)、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 从站,它从 UART 读取请求,更新其内部寄存器数组,并将相应的响应写回 UART。

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

构造一个 ModbusRTU 从站。

  • uart 是一个用于发送和接收 Modbus 帧的 UART 实例(例如 machine.UARTpyb.UART)。在传入之前,必须以适当的波特率、校验位和超时配置好该 UART。

  • slave_id 是该实例将响应的 Modbus 从站地址(1-247)。寻址到其他从站 ID 的帧会被忽略。

  • register_num 是支持该从站的 16 位保持寄存器的数量。寄存器存储在 REGISTER 列表中并初始化为零。

SLAVE_ID: int

该实例将响应的 Modbus 从站地址。由 slave_id 构造函数参数设定。

uart: machine.UART

传递给构造函数的 UART 实例,用于所有 I/O。

register_num: int

16 位保持寄存器的数量,由 register_num 构造函数参数设定。

REGISTER: list[int]

长度为 register_num 的列表,保存当前的 16 位寄存器值。通过传入的 Modbus 请求执行的读写操作会更新此列表。应用代码可以直接读取或写入此列表,以与 Modbus 主站交换数据。

CRC16_TABLE: list[int]

为 Modbus CRC-16 多项式预计算的 256 项查找表,由 crc16() 使用。

any() int

返回底层 UART 接收缓冲区中当前可用的字节数(委托给 uart.any())。在调用 handle() 之前,使用它来检查是否有传入的请求。

clear() None

REGISTER 中的每一项重置为 0

crc16(data: bytes | bytearray) bytes

使用 CRC16_TABLE 计算 data 的 Modbus CRC-16,并将其作为一个 2 字节的小端 bytes 对象返回,适合附加到 Modbus 帧。

  • data 是一个包含待校验字节的 bytes/bytearray(或任何整数可迭代对象)。

handle(debug: bool = False) None

从 UART 读取单个 Modbus 请求,按需更新内部寄存器数组,并将相应的响应写回 UART。

支持的功能码:

  • 0x03 读保持寄存器 —— 以请求范围内的寄存器值进行响应。

  • 0x06 写单个寄存器 —— 写入单个寄存器并回显地址和值。

  • 0x10 写多个寄存器 —— 写入一段连续的寄存器范围,并以起始地址和数量进行响应。

在以下情况下返回 Modbus 异常响应:

  • 非法功能(0x01)—— 不支持的功能码。

  • 非法数据地址(0x02)—— 寄存器索引超出范围。

  • 非法数据值(0x03)—— 字节数与声明的寄存器数量不匹配。

CRC 不匹配或从站地址与 SLAVE_ID 不匹配的帧会被静默丢弃。

  • debug 如果为 True,则将原始请求、解析出的功能码、生成的响应以及任何错误详情打印到 REPL。默认为 False