Tipos de datos Modbus explicados — coils, discrete inputs, input registers y holding registers
Tipos de datos Modbus en la práctica: coils, discrete inputs, input registers y holding registers, direccionamiento, function codes y trampas reales de campo.
El ingeniero lee por primera vez la documentación Modbus de un PLC y encuentra cuatro tablas con nombres parecidos, prefijos de cinco dígitos que comienzan en 0, 1, 3 o 4, y un function code por operación. Luego descubre que la dirección lógica 40001 se convierte en 0x0000 dentro del frame, que el registro más obvio aparece desplazado una posición y que la mitad de los clientes de prueba muestra un valor distinto al de la otra mitad. La confusión es herencia de un protocolo de 1979 que carga en los nombres de sus tipos el mapa de memoria del PLC Modicon 984. Este post separa las cuatro tablas, muestra los function codes que tocan cada una y cierra con las trampas que aparecen en el primer día de campo.
Los 4 tipos de datos Modbus
El modelo de datos original de Modbus tiene cuatro tablas. Cada una define el tipo (bit o palabra de 16 bits), el sentido, el prefijo de dirección lógica y los function codes que operan sobre ella.
| Tabla | Tipo | Acceso | Prefijo lógico | Function codes |
|---|---|---|---|---|
| Coils | 1 bit | Lectura y escritura | 0xxxx (00001–09999) | 0x01, 0x05, 0x0F |
| Discrete inputs | 1 bit | Solo lectura | 1xxxx (10001–19999) | 0x02 |
| Input registers | 16 bits | Solo lectura | 3xxxx (30001–39999) | 0x04 |
| Holding registers | 16 bits | Lectura y escritura | 4xxxx (40001–49999) | 0x03, 0x06, 0x10 |
Coils y discrete inputs viajan empaquetados, ocho por byte. Input y holding registers viajan en palabras de 16 bits big-endian. Intentar escribir en input register devuelve excepción 0x01 (Illegal Function); leer un coil con function code 0x02 también devuelve 0x01.
Coils (0x) — bit de lectura y escritura
Los coils representan salidas digitales individuales. El nombre viene de la bobina de un relé interno: encender y apagar contactos, accionar válvulas solenoides, energizar lámparas, comandar arranques y paradas. En equipos modernos los coils también aparecen como flags de comando: reset de contador, limpieza de alarma, disparo de calibración.
Tres function codes tocan coils:
- 0x01 Read Coils: lee de 1 a 2000 coils consecutivos; respuesta con
ceil(N/8)bytes empaquetados. - 0x05 Write Single Coil: escribe un coil. Valor 0xFF00 para encender, 0x0000 para apagar; cualquier otro es ilegal.
- 0x0F Write Multiple Coils: escribe hasta 1968 coils en una sola transacción.
Trampa frecuente: un coil escrito como 0xFF00 vuelve como bit 1 en la lectura siguiente. Comparar siempre contra la representación de lectura, no contra el valor escrito.
Discrete inputs (1x) — bit solo lectura
Los discrete inputs representan entradas digitales conectadas a sensores binarios. El caso clásico es el contacto seco: final de carrera, sensor inductivo, presostato, termostato, botón de emergencia, contacto auxiliar. En equipos de medición también exponen flags de estado.
Solo un function code opera:
- 0x02 Read Discrete Inputs: lee de 1 a 2000 entradas consecutivas, con ocho bits empaquetados por byte.
No existe escritura sobre un discrete input. El intento devuelve excepción 0x01 o 0x02. La confusión más común ocurre cuando el mismo equipo expone un estado (sensor) y un comando (actuador) sobre el mismo concepto: el fabricante cuidadoso asigna un discrete input para "alarma activa" y un coil para "limpiar alarma".
Input registers (3x) — palabra solo lectura
Los input registers son palabras de 16 bits solo lectura. El uso original era exponer el valor digitalizado de una entrada analógica (termopar, 4–20 mA, sensor de presión, encoder). En equipos dedicados, alojan magnitudes medidas: tensión, corriente, temperatura, contadores.
- 0x04 Read Input Registers: lee de 1 a 125 registros. La respuesta lleva
2×Nbytes en big-endian.
La separación semántica importa: el input register es el contrato "esto es lo que el equipo mide, no puedes tocarlo". En arquitecturas Secure by Design, mantener magnitudes medidas en una tabla solo lectura simplifica la auditoría. En la práctica, muchos fabricantes consolidan todo en holding registers; el AEM-60DC8 sigue esa línea con 147 holding registers documentados.
Holding registers (4x) — palabra de lectura y escritura
Los holding registers son palabras de 16 bits de lectura y escritura. Es la tabla más usada porque cabe todo: setpoints, límites de alarma, configuración, estado, telemetría, contadores, identificación, calibración.
Tres function codes dominan:
- 0x03 Read Holding Registers: lee de 1 a 125 registros. La operación más frecuente en supervisorios.
- 0x06 Write Single Register: escribe una palabra de 16 bits en un único registro.
- 0x10 Write Multiple Registers: escribe hasta 123 registros en una transacción atómica.
Los function codes secundarios incluyen 0x16 (mask write) y 0x17 (read/write multiple). El contrato de un holding register debe documentar, además de la dirección: unidad, escala, offset, rango válido, valor centinela (0x8000 en int16) y persistencia.
Direccionamiento — origen 0 vs 1, offset Modicon, mapa hex × decimal
El punto donde más integraciones tropiezan no es el function code, es la dirección. Dos convenciones coexisten:
- Dirección lógica (1-based, con prefijo): la notación Modicon. Primer coil 00001, primer discrete input 10001, primer input register 30001, primer holding register 40001.
- Dirección de protocolo (0-based, sin prefijo): lo que va dentro del frame. Primer registro de cualquier tabla es 0x0000. Quien distingue la tabla es el function code.
| Tabla | Dirección lógica | Dirección de protocolo | Function code |
|---|---|---|---|
| Coils | 00001 | 0x0000 | 0x01 |
| Coils | 00100 | 0x0063 | 0x01 |
| Discrete inputs | 10001 | 0x0000 | 0x02 |
| Input registers | 30016 | 0x000F | 0x04 |
| Holding registers | 40001 | 0x0000 | 0x03 |
| Holding registers | 40147 | 0x0092 | 0x03 |
Regla práctica: restar el prefijo, restar uno más y convertir a hex. Algunas herramientas adoptan una tercera convención con prefijo 4 y dirección 0-based, donde 40000 se refiere al mismo registro que 40001 en la notación clásica. En caso de ambigüedad, capturar el frame con analizador serial y leer el byte directamente.
Cómo el AEM-60DC8 organiza sus 147 holding registers
El AEM-60DC8 (Plataforma Industrial de Supervisión DC, firmware v1.03) expone 147 holding registers en 17 bloques funcionales. El recorte de abajo es un ejemplo simplificado con fines didácticos; el mapa autoritativo es el anexo del manual técnico.
| Bloque | Rango (hex) | Registros | Sentido | Contenido |
|---|---|---|---|---|
| Tensión CH1–CH8 instantánea | 0x0000–0x0007 | 8 | RO efectivo | uint16 con escala ×100 |
| Tensión CH1–CH8 promedio 1 s | 0x0008–0x000F | 8 | RO efectivo | Ventana móvil de 1 s |
| Estado por canal | 0x0010–0x0017 | 8 | RO efectivo | Bitfield: presente, en alarma, calibrado |
| Límites superiores/inferiores | 0x0020–0x002F | 16 | RW | Setpoints por canal |
| Configuración de canal | 0x0040–0x004F | 16 | RW | Habilitación, modo, oversampling |
| Configuración de comunicación | 0x0050–0x0057 | 8 | RW | Slave ID, baudrate, paridad, timeout |
| Contadores de evento | 0x0060–0x006F | 16 | RO efectivo | Subida y bajada de alarma |
| Telemetría forense | 0x0070–0x007F | 16 | RO efectivo | Uptime, watchdog resets, CRC errors |
| Calibración de fábrica | 0x0080–0x008F | 16 | RW (protegido) | Ganancia y offset, requiere código |
| Identificación | 0x0090–0x0092 | 3 | RO efectivo | Modelo, serial, firmware v1.03 |
Los holding registers con sentido "RO efectivo" aceptan escritura a nivel de protocolo, pero el firmware rechaza con excepción 0x04 cuando el contenido es resultado de una medida. Publicar un mapa sin indicar sentido efectivo, unidad, escala y persistencia convierte cada integración en negociación.
Errores comunes en la lectura
Cinco trampas explican la mayoría de los reportes de "Modbus que no funciona" en campo:
Off-by-one: leer holding register 40016 escribiendo 0x0010 en lugar de 0x000F. El servidor responde con el valor de 40017. Corregir: restar el prefijo y uno más antes de convertir.
Byte order: Modbus es big-endian dentro del registro de 16 bits — byte alto primero. Implementaciones little-endian leen con los bytes invertidos. Síntoma: 24,00 V aparece como 0,06 V (0x0960 leído como 0x6009).
Word swapping en 32 bits: float, int32 y contadores ocupan dos registros consecutivos. El orden de palabras (high word primero vs low word primero) no está estandarizado. Las cuatro combinaciones (ABCD, CDAB, BADC, DCBA) aparecen en campo. Síntoma: valores pequeños correctos, valores grandes absurdos.
Signed vs unsigned: el protocolo transporta 16 bits crudos, sin indicar signo. -100 llega como 0xFF9C; leído como uint16 vale 65436. Tensiones con referencia flotante pueden ser negativas y exigen interpretación signed.
Cantidad fuera del límite: 0x03 y 0x04 aceptan hasta 125 registros; 0x10 acepta hasta 123. Pedidos mayores devuelven excepción 0x03. Leer 147 registros en una sola solicitud no funciona — dividir en dos lecturas.
Preguntas frecuentes
¿Por qué existen cuatro tablas en lugar de una sola? La separación refleja la memoria del PLC Modicon 984 de los años 80, donde salidas digitales, entradas digitales, entradas analógicas y memoria de configuración ocupaban áreas físicas distintas. La especificación la preservó para dejar explícita la semántica RO vs RW y bit vs palabra.
¿Puedo usar holding registers para todo? Técnicamente sí, y muchos fabricantes consolidan medidas, setpoints y estados en holding registers. La pérdida es semántica: el cliente debe saber por convención cuáles registros son lectura efectiva.
¿Cómo leo un float de 32 bits en Modbus? Leyendo dos holding registers consecutivos y reconstruyendo el float según el orden documentado. El orden más común en equipos modernos es CDAB (low word primero), pero ABCD aparece en equipos europeos.
¿El AEM-60DC8 expone coils o discrete inputs? No. El AEM-60DC8 consolida las 147 variables en holding registers, con soporte para los function codes 0x03 y 0x10. Estado de canal y flags de alarma se exponen como bitfields.
¿Cómo sé si la dirección de la documentación es lógica o de protocolo? Por el número: cinco dígitos comenzando en 0, 1, 3 o 4 es dirección lógica. Hexadecimal o comenzando en 0x0000 es dirección de protocolo. En ambigüedad, capturar el frame y leer el byte directamente.