modbus — Protocolo esclavo Modbus RTU

Este módulo proporciona una implementación en Python puro de un esclavo Modbus RTU que se comunica a través de un UART. Mantiene un array interno de registros de retención y responde a los códigos de función Modbus estándar 0x03 (Read Holding Registers), 0x06 (Write Single Register) y 0x10 (Write Multiple Registers). El CRC-16 (polinomio Modbus) se calcula mediante una tabla de búsqueda.

Por ejemplo:

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

Un esclavo Modbus RTU que lee solicitudes desde un UART, actualiza su array interno de registros y escribe la respuesta correspondiente de vuelta al UART.

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

Construye un esclavo ModbusRTU.

  • uart es una instancia de UART (p. ej. machine.UART o pyb.UART) utilizada para enviar y recibir fotogramas Modbus. El UART debe configurarse con la velocidad en baudios, la paridad y los tiempos de espera adecuados antes de pasarlo.

  • slave_id es la dirección de esclavo Modbus (1-247) a la que responderá esta instancia. Los fotogramas dirigidos a otros IDs de esclavo se ignoran.

  • register_num es el número de registros de retención de 16 bits que respaldan a este esclavo. Los registros se almacenan en la lista REGISTER y se inicializan a cero.

SLAVE_ID: int

La dirección de esclavo Modbus a la que responderá esta instancia. Se establece a partir del argumento del constructor slave_id.

uart: machine.UART

La instancia de UART pasada al constructor, utilizada para todas las operaciones de E/S.

register_num: int

El número de registros de retención de 16 bits, establecido a partir del argumento del constructor register_num.

REGISTER: list[int]

Lista de longitud register_num que contiene los valores actuales de los registros de 16 bits. Las lecturas y escrituras realizadas mediante solicitudes Modbus entrantes actualizan esta lista. El código de la aplicación puede leer o escribir directamente en esta lista para intercambiar datos con el maestro Modbus.

CRC16_TABLE: list[int]

Tabla de búsqueda precalculada de 256 entradas para el polinomio CRC-16 de Modbus, utilizada por crc16().

any() int

Devuelve el número de bytes disponibles actualmente en el búfer de recepción del UART subyacente (delega en uart.any()). Úsalo para comprobar si hay una solicitud entrante antes de llamar a handle().

clear() None

Restablece cada entrada de REGISTER a 0.

crc16(data: bytes | bytearray) bytes

Calcula el CRC-16 de Modbus de data usando CRC16_TABLE y lo devuelve como un objeto bytes little-endian de 2 bytes adecuado para añadirlo a un fotograma Modbus.

  • data es un bytes/bytearray (o cualquier iterable de enteros) que contiene los bytes a los que aplicar la suma de comprobación.

handle(debug: bool = False) None

Lee una única solicitud Modbus desde el UART, actualiza el array interno de registros según sea necesario y escribe la respuesta correspondiente de vuelta al UART.

Códigos de función admitidos:

  • 0x03 Read Holding Registers — responde con el rango solicitado de valores de registro.

  • 0x06 Write Single Register — escribe un único registro y devuelve como eco la dirección y el valor.

  • 0x10 Write Multiple Registers — escribe un rango contiguo de registros y responde con la dirección inicial y la cantidad.

Se devuelven respuestas de excepción Modbus para:

  • Illegal Function (0x01) — código de función no admitido.

  • Illegal Data Address (0x02) — índice de registro fuera de rango.

  • Illegal Data Value (0x03) — el número de bytes no coincide con la cantidad declarada de registros.

Los fotogramas cuyo CRC no coincide o cuya dirección de esclavo no coincide con SLAVE_ID se descartan silenciosamente.

  • debug si es True, imprime la solicitud sin procesar, el código de función analizado, la respuesta generada y cualquier detalle de error en el REPL. El valor predeterminado es False.