Ir al contenido

Trama Modbus RTU, códigos de función y CRC, con una librería maestro para PLC

Estructura de la trama, códigos de función, modelo de datos, códigos de excepción y CRC, con bytes reales de petición y respuesta
18 de marzo de 2020 por
Trama Modbus RTU, códigos de función y CRC, con una librería maestro para PLC
Boot & Work Corp. S.L, Fernandez Queralt Martinez

Modbus RTU es la versión serie del protocolo Modbus. Un maestro envía una trama binaria (dirección de esclavo, código de función, datos y un CRC-16) por RS-485 o RS-232, y solo responde el esclavo con esa dirección. Cada trama se separa de la siguiente con un silencio de al menos 3,5 caracteres.

Esta referencia explica cómo funciona Modbus RTU, la estructura de la trama, el modelo de datos, los bytes de petición y respuesta de los ocho códigos de función más usados, los códigos de excepción y cómo construir a mano una trama y su CRC. Al final verás cómo la librería Modbus RTU master de Industrial Shields envía las mismas tramas desde un PLC basado en Arduino o ESP32. Para la conexión y los sketches completos, consulta Modbus RTU con PLC basados en Arduino y ESP32.

¿Qué es Modbus RTU?

Modbus es un protocolo de petición y respuesta que Modicon publicó en 1979 para sus PLC. Hoy mantiene la especificación la Modbus Organization, y es pública y de uso libre. Modbus define los mensajes (la capa de aplicación). Modbus RTU añade las reglas para enviarlos por una línea serie: codificación binaria, una dirección de esclavo y una comprobación CRC.

  • Se diseñó para el control industrial: un PLC lee y escribe los registros de otros equipos.
  • Es abierto y fácil de implementar, por eso casi todos los analizadores, variadores, transmisores y HMI lo admiten.
  • Cada trama lleva un CRC, así que el receptor puede detectar errores de transmisión.
  • Los comandos básicos leen el valor de un registro o de un bit, o lo cambian.

Maestro, esclavos y direcciones en un bus Modbus RTU

Modbus RTU es la implementación de Modbus más habitual en líneas serie. Envía los datos en forma binaria compacta, y los silencios en la línea separan una trama de la siguiente.

Mensaje Modbus RTU: silencio de 3,5 caracteres, dirección del esclavo, código de función, datos, CRC y silencio de 3,5 caracteres, con pausas entre mensajes

En un bus RS-485 todos los equipos comparten un par trenzado. Solo el nodo configurado como maestro inicia una transacción. Todos los demás equipos son esclavos: responden a las peticiones y nunca hablan por iniciativa propia. Cada esclavo tiene una dirección única de 1 a 247. La dirección 0 es un broadcast: todos los esclavos ejecutan una escritura enviada a la dirección 0 y ninguno responde.

Maestro Modbus RTU que envía una petición a los esclavos 1, 2 y N, donde solo el esclavo direccionado envía la respuesta

Todos los esclavos reciben todas las peticiones, pero solo el esclavo direccionado actúa y responde. RS-485 admite 32 cargas unitarias en un segmento sin repetidor, así que un bus típico tiene un maestro y hasta 31 esclavos estándar. Los transceptores de 1/4 o 1/8 de carga unitaria permiten más, hasta las 247 direcciones de Modbus.

A lo largo de esta guía construiremos una trama. El maestro quiere el valor de 6 input registers del esclavo 2. La trama empieza con la dirección del esclavo: 02.

Estructura de la trama Modbus RTU

ADU de Modbus según la especificación Modbus Application Protocol V1.1b: dirección adicional, código de función, datos y comprobación de errores, con la PDU en su interior

La Application Data Unit (ADU) de Modbus RTU tiene cuatro campos. El código de función y los datos forman la Protocol Data Unit (PDU), que es la misma en Modbus TCP.

CampoTamañoContenido
Dirección de esclavo1 byte1 a 247 (0 = broadcast)
Código de función1 byteLo que debe hacer el esclavo (1 a 127)
Datos0 a 252 bytesDirecciones, cantidades y valores. Depende del código de función
CRC2 bytesCRC-16/MODBUS, byte bajo primero

Una trama Modbus RTU tiene como máximo 256 bytes. Dentro de una trama, el silencio entre dos caracteres no puede superar 1,5 tiempos de carácter. Entre tramas debe haber al menos 3,5 tiempos de carácter: unos 4 ms a 9600 baudios y 2 ms a 19200 baudios. Por encima de 19200 baudios la especificación fija estos silencios en 750 µs y 1,75 ms.

Códigos de función Modbus

El código de función ocupa un byte. Los códigos 1 a 127 son peticiones, y el esclavo responde un error sumando 0x80 al código de función (128 a 255). El código 0 no es válido. Estos son los códigos de función que los PLC usan a diario:

Tabla de códigos de función Modbus por tipo: entradas discretas, bobinas, registros de entrada, registros holding, registros de archivo y diagnóstico
Código (dec)Código (hex)NombreTabla de datos
010x01Leer coilsCoils
020x02Leer discrete inputsDiscrete inputs
030x03Leer holding registersHolding registers
040x04Leer input registersInput registers
050x05Escribir una coilCoils
060x06Escribir un registroHolding registers
150x0FEscribir varias coilsCoils
160x10Escribir varios registrosHolding registers

La especificación define más códigos, como el 08 (diagnóstico), el 23 (leer y escribir varios registros) y el 43 (leer la identificación del equipo), pero muchos equipos no los admiten.

Respuestas de excepción

Cuando un esclavo no puede ejecutar una petición, responde con el código de función más 0x80 y un código de excepción. Por ejemplo, 01 83 02 C0 F1 significa que el esclavo 1 ha rechazado una petición de función 03 porque la dirección no existe.

Código de excepciónNombreCausa habitual
01Función no válida (Illegal function)El esclavo no admite este código de función
02Dirección no válida (Illegal data address)El registro o el bit no existe, o la cantidad pasa del final del mapa
03Valor no válido (Illegal data value)Cantidad incorrecta o valor fuera de rango
04Fallo del equipo (Server device failure)El esclavo ha tenido un error interno al ejecutar la petición
06Equipo ocupado (Server device busy)El esclavo está procesando un comando largo. Reintenta más tarde

Si el esclavo no responde (dirección incorrecta, CRC erróneo, velocidad distinta), no hay código de excepción: el maestro solo ve un timeout.

Modelo de datos Modbus: coils, discrete inputs y registros

Modbus organiza los datos de un esclavo en cuatro tablas. Los bits pueden valer ON (1) u OFF (0). Los registros son palabras de 16 bits.

TablaTipoAccesoCódigos de funciónNumeración habitual
Coils1 bitLectura y escritura01, 05, 1500001 a 09999
Discrete inputs1 bitSolo lectura0210001 a 19999
Input registersPalabra de 16 bitsSolo lectura0430001 a 39999
Holding registersPalabra de 16 bitsLectura y escritura03, 06, 1640001 a 49999

Los números 0xxxx, 1xxxx, 3xxxx y 4xxxx vienen de los manuales de los equipos, no de la trama. En la trama cada tabla empieza en la dirección 0, así que el registro 40001 es la dirección 0 y el registro 40108 es la dirección 107.

Un registro contiene de 0 a 65535 como valor sin signo, o de -32768 a 32767 cuando el equipo lo usa como entero con signo (complemento a dos). Los valores que necesitan más de 16 bits, como contadores de 32 bits o floats, usan dos registros consecutivos. El orden de las dos palabras depende del equipo, así que consulta su manual.

Formato de petición y respuesta de cada código de función

Cada petición y respuesta Modbus es una ADU que contiene una PDU. Las tablas siguientes muestran la PDU: en Modbus RTU, añade delante la dirección del esclavo y detrás el CRC. Los ejemplos salen de la especificación Modbus Application Protocol, con la trama completa para el esclavo 1 y su CRC.

ADU de Modbus RTU con dirección del esclavo, código de función, datos y checksum, donde la PDU es el código de función más los datos

(0x01) Leer coils

Lee de 1 a 2000 coils contiguas de un esclavo. La respuesta empaqueta una coil por bit: el bit menos significativo del primer byte de datos es la primera coil pedida. Si la cantidad no es múltiplo de 8, el último byte se completa con ceros.

PDU de petición

CampoTamañoValor
Código de función1 byte0x01
Dirección inicial2 bytes0x0000 a 0xFFFF
Cantidad de coils2 bytes1 a 2000 (0x0001 a 0x07D0)

PDU de respuesta

CampoTamañoValor
Código de función1 byte0x01
Número de bytes1 byteN (cantidad / 8, redondeado hacia arriba)
Estado de las coilsN bytes1 bit por coil

Ejemplo: leer las coils 20 a 38 (direcciones 19 a 37)

Campo de la peticiónHexCampo de la respuestaHex
Función01Función01
Dirección inicial Hi00Número de bytes03
Dirección inicial Lo13Coils 27 a 20CD
Cantidad Hi00Coils 35 a 286B
Cantidad Lo13Coils 38 a 3605

Petición RTU completa al esclavo 1, con el CRC: 01 01 00 13 00 13 8C 02

(0x02) Leer discrete inputs

Lee de 1 a 2000 discrete inputs contiguas (bits de solo lectura). Las entradas numeradas de 1 a 16 tienen las direcciones 0 a 15. La respuesta empaqueta los bits igual que la función 01.

PDU de petición

CampoTamañoValor
Código de función1 byte0x02
Dirección inicial2 bytes0x0000 a 0xFFFF
Cantidad de entradas2 bytes1 a 2000 (0x0001 a 0x07D0)

PDU de respuesta

CampoTamañoValor
Código de función1 byte0x02
Número de bytes1 byteN (cantidad / 8, redondeado hacia arriba)
Estado de las entradasN bytes1 bit por entrada

Ejemplo: leer las discrete inputs 197 a 218 (direcciones 196 a 217)

Campo de la peticiónHexCampo de la respuestaHex
Función02Función02
Dirección inicial Hi00Número de bytes03
Dirección inicial LoC4Entradas 204 a 197AC
Cantidad Hi00Entradas 212 a 205DB
Cantidad Lo16Entradas 218 a 21335

Petición RTU completa al esclavo 1, con el CRC: 01 02 00 C4 00 16 B8 39

(0x03) Leer holding registers

Lee de 1 a 125 holding registers contiguos. Los registros numerados de 1 a 16 tienen las direcciones 0 a 15. Cada registro vuelve en 2 bytes, el byte alto primero.

PDU de petición

CampoTamañoValor
Código de función1 byte0x03
Dirección inicial2 bytes0x0000 a 0xFFFF
Cantidad de registros2 bytes1 a 125 (0x0001 a 0x007D)

PDU de respuesta

CampoTamañoValor
Código de función1 byte0x03
Número de bytes1 byte2 x N
Valores de los registrosN x 2 bytesByte alto primero

Ejemplo: leer los holding registers 108 a 110 (direcciones 107 a 109)

Campo de la peticiónHexCampo de la respuestaHex
Función03Función03
Dirección inicial Hi00Número de bytes06
Dirección inicial Lo6BRegistro 10802 2B (555)
Cantidad Hi00Registro 10900 00 (0)
Cantidad Lo03Registro 11000 64 (100)

Petición RTU completa al esclavo 1, con el CRC: 01 03 00 6B 00 03 74 17

(0x04) Leer input registers

Lee de 1 a 125 input registers contiguos (solo lectura, normalmente medidas). El formato es el mismo que el de la función 03.

PDU de petición

CampoTamañoValor
Código de función1 byte0x04
Dirección inicial2 bytes0x0000 a 0xFFFF
Cantidad de input registers2 bytes1 a 125 (0x0001 a 0x007D)

PDU de respuesta

CampoTamañoValor
Código de función1 byte0x04
Número de bytes1 byte2 x N
Input registersN x 2 bytesByte alto primero

Ejemplo: leer el input register 9 (dirección 8)

Campo de la peticiónHexCampo de la respuestaHex
Función04Función04
Dirección inicial Hi00Número de bytes02
Dirección inicial Lo08Input register 900 0A (10)
Cantidad Hi00
Cantidad Lo01

Petición RTU completa al esclavo 1, con el CRC: 01 04 00 08 00 01 B0 08

(0x05) Escribir una coil

Pone una coil a ON u OFF. El valor 0xFF00 significa ON y 0x0000 significa OFF. Cualquier otro valor no es válido y la coil no cambia. La respuesta normal es un eco de la petición.

PDU de petición

CampoTamañoValor
Código de función1 byte0x05
Dirección de la salida2 bytes0x0000 a 0xFFFF
Valor de la salida2 bytes0x0000 (OFF) o 0xFF00 (ON)

PDU de respuesta

CampoTamañoValor
Código de función1 byte0x05
Dirección de la salida2 bytes0x0000 a 0xFFFF
Valor de la salida2 bytes0x0000 o 0xFF00

Ejemplo: poner a ON la coil 173 (dirección 172)

Campo de la peticiónHexCampo de la respuestaHex
Función05Función05
Dirección de la salida Hi00Dirección de la salida Hi00
Dirección de la salida LoACDirección de la salida LoAC
Valor de la salida HiFFValor de la salida HiFF
Valor de la salida Lo00Valor de la salida Lo00

Petición RTU completa al esclavo 1, con el CRC: 01 05 00 AC FF 00 4C 1B

(0x06) Escribir un registro

Escribe un holding register. El registro 1 es la dirección 0. La respuesta normal es un eco de la petición, enviado después de escribir el valor.

PDU de petición

CampoTamañoValor
Código de función1 byte0x06
Dirección del registro2 bytes0x0000 a 0xFFFF
Valor del registro2 bytes0x0000 a 0xFFFF

PDU de respuesta

CampoTamañoValor
Código de función1 byte0x06
Dirección del registro2 bytes0x0000 a 0xFFFF
Valor del registro2 bytes0x0000 a 0xFFFF

Ejemplo: escribir 3 (0x0003) en el registro 2 (dirección 1)

Campo de la peticiónHexCampo de la respuestaHex
Función06Función06
Dirección del registro Hi00Dirección del registro Hi00
Dirección del registro Lo01Dirección del registro Lo01
Valor del registro Hi00Valor del registro Hi00
Valor del registro Lo03Valor del registro Lo03

Petición RTU completa al esclavo 1, con el CRC: 01 06 00 01 00 03 98 0B

(0x0F) Escribir varias coils

Pone una secuencia de coils a ON u OFF. Cada bit del campo de datos es una coil: 1 es ON y 0 es OFF, empezando por el bit menos significativo del primer byte. La respuesta devuelve el código de función, la dirección inicial y la cantidad escrita.

PDU de petición

CampoTamañoValor
Código de función1 byte0x0F
Dirección inicial2 bytes0x0000 a 0xFFFF
Cantidad de salidas2 bytes1 a 1968 (0x0001 a 0x07B0)
Número de bytes1 byteN (cantidad / 8, redondeado hacia arriba)
Valor de las salidasN bytes1 bit por coil

PDU de respuesta

CampoTamañoValor
Código de función1 byte0x0F
Dirección inicial2 bytes0x0000 a 0xFFFF
Cantidad de salidas2 bytes1 a 1968 (0x0001 a 0x07B0)

Ejemplo: escribir 10 coils a partir de la coil 20 (dirección 19)

Campo de la peticiónHexCampo de la respuestaHex
Función0FFunción0F
Dirección inicial Hi00Dirección inicial Hi00
Dirección inicial Lo13Dirección inicial Lo13
Cantidad Hi00Cantidad Hi00
Cantidad Lo0ACantidad Lo0A
Número de bytes02
Valor de las salidas (coils 27 a 20)CD
Valor de las salidas (coils 29 a 28)01

Petición RTU completa al esclavo 1, con el CRC: 01 0F 00 13 00 0A 02 CD 01 72 CB

(0x10) Escribir varios registros

Escribe un bloque de 1 a 123 holding registers contiguos. Los valores van en 2 bytes por registro, el byte alto primero. La respuesta devuelve el código de función, la dirección inicial y la cantidad de registros escritos.

PDU de petición

CampoTamañoValor
Código de función1 byte0x10
Dirección inicial2 bytes0x0000 a 0xFFFF
Cantidad de registros2 bytes1 a 123 (0x0001 a 0x007B)
Número de bytes1 byte2 x N
Valor de los registrosN x 2 bytesByte alto primero

PDU de respuesta

CampoTamañoValor
Código de función1 byte0x10
Dirección inicial2 bytes0x0000 a 0xFFFF
Cantidad de registros2 bytes1 a 123 (0x0001 a 0x007B)

Ejemplo: escribir 0x000A y 0x0102 en los registros 2 y 3 (direcciones 1 y 2)

Campo de la peticiónHexCampo de la respuestaHex
Función10Función10
Dirección inicial Hi00Dirección inicial Hi00
Dirección inicial Lo01Dirección inicial Lo01
Cantidad Hi00Cantidad Hi00
Cantidad Lo02Cantidad Lo02
Número de bytes04
Registro 2 Hi00
Registro 2 Lo0A
Registro 3 Hi01
Registro 3 Lo02

Petición RTU completa al esclavo 1, con el CRC: 01 10 00 01 00 02 04 00 0A 01 02 92 30

Cómo construir a mano una trama Modbus RTU

Volvamos al ejemplo: el maestro quiere 6 input registers del esclavo 2. La función 04 (leer input registers) necesita la dirección inicial y la cantidad, y después el CRC.

CampoHex
Dirección de esclavo02
Código de función04
Dirección inicial Hi00
Dirección inicial Lo00
Cantidad de input registers Hi00
Cantidad de input registers Lo06
CRC Lo70
CRC Hi3B

El CRC-16/MODBUS de 02 04 00 00 00 06 es 0x3B70. Modbus envía primero el byte bajo, así que la trama acaba en 70 3B y la petición completa es 02 04 00 00 00 06 70 3B. Puedes comprobar un CRC con una calculadora de CRC en línea (elige CRC-16 (Modbus)) o calcularlo en C:

#include <stdint.h>
#include <stddef.h>

// CRC-16/MODBUS: polynomial 0xA001 (reflected 0x8005), initial value 0xFFFF
uint16_t modbusCrc(const uint8_t *frame, size_t length) {
  uint16_t crc = 0xFFFF;
  for (size_t i = 0; i < length; i++) {
    crc ^= frame[i];
    for (uint8_t bit = 0; bit < 8; bit++) {
      if (crc & 0x0001) {
        crc = (crc >> 1) ^ 0xA001;
      } else {
        crc >>= 1;
      }
    }
  }
  return crc;  // send the low byte first, then the high byte
}

Esta función devuelve 0x3B70 para la trama del ejemplo (probada con gcc). El esclavo responde con 02 04 0C, después 12 bytes de datos (2 por registro) y su propio CRC.

Librería Modbus RTU master para los PLC de Industrial Shields

En un PLC no hace falta construir las tramas a mano. La librería Modbus de Industrial Shields construye la trama, calcula el CRC, respeta el silencio de 3,5 caracteres y comprueba la respuesta. Funciona con cualquier puerto serie por hardware: ModbusRTUMaster master(RS485); o ModbusRTUMaster master(RS232);. Este sketch envía la misma petición que la trama anterior y compila para un M-Duino 21+:

#include <RS485.h>
#include <ModbusRTUMaster.h>

ModbusRTUMaster master(RS485);

void setup() {
  Serial.begin(115200UL);
  RS485.begin(9600, HALFDUPLEX, SERIAL_8E1);   // the serial port
  master.begin(9600);                          // the Modbus timings, same baud rate
}

void loop() {
  // Same request as the frame built by hand: slave 2, 6 input registers from address 0
  static uint32_t lastRequest = 0;
  if (!master.isWaitingResponse() && millis() - lastRequest >= 1000UL) {
    master.readInputRegisters(2, 0, 6);
    lastRequest = millis();
  }

  ModbusResponse response = master.available();
  if (response) {
    if (response.hasError()) {
      Serial.println(response.getErrorMessage());   // exception code from the slave
    } else {
      for (int i = 0; i < 6; i++) {
        Serial.println(response.getRegister(i));
      }
    }
  }
  if (master.hasException()) {                       // timeout or bad CRC
    Serial.println(master.getExceptionMessage());
    master.clearException();
  }
}

Las funciones de lectura y escritura no bloquean y no devuelven el valor. Devuelven true cuando la petición se envía y false cuando el maestro está ocupado. La respuesta llega con available(), que da un ModbusResponse con hasError(), getErrorCode(), getErrorMessage(), getSlave(), getFC(), isCoilSet(), isDiscreteInputSet() y getRegister(). Pasa la misma velocidad a RS485.begin() y a master.begin(): la librería la usa para los tiempos de la trama (19200 si la dejas vacía).

La conexión de cada familia de PLC, un sketch de esclavo y la tabla de errores están en Modbus RTU con PLC basados en Arduino y ESP32. Cada código de función con un maestro y un esclavo M-Duino Arduino PLC está en el tutorial de códigos de función Modbus RTU.

Mira las tramas de un ciclo de lectura real. El simulador de red Modbus muestra cada petición, respuesta, CRC y timeout de un M-Duino 21 que interroga a cuatro esclavos Modbus RTU. Cambia la dirección de un esclavo o la velocidad y mira lo que recibe el maestro.

Abrir el simulador de red ModbusLeer el caso de la red Modbus de temperatura

Preguntas frecuentes sobre Modbus RTU

¿Qué diferencia hay entre Modbus RTU y Modbus ASCII?

Los dos funcionan en líneas serie. Modbus RTU envía bytes binarios y los comprueba con un CRC-16. Modbus ASCII envía cada byte como dos caracteres ASCII, empieza las tramas con dos puntos, las termina con retorno de carro y salto de línea, y usa una comprobación LRC. Las tramas RTU son más o menos la mitad de largas, por eso RTU es la opción habitual.

¿Qué diferencia hay entre Modbus RTU y Modbus TCP?

La PDU (código de función y datos) es la misma. Modbus TCP la envía por Ethernet dentro de una conexión TCP, normalmente en el puerto 502. Sustituye la dirección de esclavo por un identificador de unidad en una cabecera de 7 bytes y elimina el CRC, porque TCP ya comprueba los datos. Consulta Modbus RTU, Modbus TCP u OPC UA.

¿Por qué el registro 40001 es la dirección 0?

La numeración 4xxxx es una convención de los manuales: el primer dígito indica la tabla y el resto cuenta desde 1. La trama lleva la dirección dentro de la tabla, que cuenta desde 0. Resta 40001 al número de registro para obtener la dirección.

¿Cuántos registros puedo leer en una petición?

Hasta 125 registros con las funciones 03 y 04, y hasta 2000 bits con las funciones 01 y 02. Puedes escribir hasta 123 registros con la función 16 y hasta 1968 coils con la función 15. Muchos equipos aceptan menos, así que consulta su manual.

¿Qué configuración serie usa Modbus RTU?

Cada carácter tiene 11 bits: 1 de inicio, 8 de datos, 1 de paridad y 1 de parada. El valor por defecto es paridad par con 1 bit de parada (8E1). Sin paridad, la especificación pide 2 bits de parada (8N2), aunque muchos equipos usan 8N1. Todos los equipos de un bus deben usar la misma configuración.

¿Por qué el CRC se envía con el byte bajo primero?

Lo dice la especificación: los campos de datos van con el byte alto primero, pero el CRC va con el byte bajo primero. Un CRC con los bytes invertidos es el error más habitual en las tramas Modbus hechas a mano.

Buscar en nuestro blog

Trama Modbus RTU, códigos de función y CRC, con una librería maestro para PLC
Boot & Work Corp. S.L, Fernandez Queralt Martinez 18 de marzo de 2020
Compartir esta publicación

¿Estás buscando tu Controlador Lógico Programable ideal?

Echa un vistazo a esta comparativa de producto de varios controladores industriales basados en Arduino.

Comparamos entradas, salidas, comunicaciones y otras especificaciones con las de los equipos de otras marcas destacadas.

Comparativa de PLCs