Dominando la Conversión REAL a WORD para Modbus TCP en PC Worx
Guía técnica para mapear valores REAL a arrays WORD en PC Worx, resolviendo un problema común en la comunicación Modbus TCP con ILC 151/171.
Introducción
En el ecosistema de la automatización industrial, la interoperabilidad es un pilar fundamental. Protocolos como Modbus TCP actúan como puentes universales, permitiendo que controladores de diferentes fabricantes intercambien datos de proceso de manera estandarizada. Sin embargo, detrás de esta aparente simplicidad se esconden desafíos técnicos que todo ingeniero de integración enfrenta tarde o temprano. Uno de los más recurrentes es la conversión de tipos de datos entre el mundo interno del PLC y el formato esperado por el protocolo.
Recientemente, en foros especializados como r/PLC, surgió una consulta específica que pone el dedo en la llaga de este problema: cómo mapear correctamente un valor de tipo REAL (número de coma flotante de 32 bits) a un array de WORDs (enteros de 16 bits) para ser servido a través del bloque funcional Modbus TCP en un controlador Phoenix Contact ILC 151/171, programado con PC Worx Express. La asignación directa falla por incompatibilidad de tipos, y las soluciones elegantes como las uniones (UNION) no siempre están disponibles en todas las versiones del entorno. Este artículo desglosa este problema técnico y presenta una solución robusta en lenguaje ST (Structured Text), permitiéndote dominar la comunicación de datos analógicos en tus proyectos de integración.
El Problema Técnico: Puenteando la Brecha entre REAL y WORD
El núcleo del desafío radica en la arquitectura de datos de Modbus y la representación interna del PLC. El protocolo Modbus, en su implementación clásica, opera principalmente con registros de 16 bits (WORDs). Para transportar un número real de simple precisión (REAL, 32 bits), es necesario dividirlo en dos registros Modbus consecutivos. El bloque de servidor Modbus TCP en la biblioteca de Phoenix Contact espera precisamente un array de WORDs para los registros holding (por ejemplo, MB_Holding_Regs[0..n]).
PC Worx, siguiendo el estándar IEC 61131-3, no permite una asignación directa de un REAL a un array de WORDs. Intentar HoldingRegs[0] := MyReal; resulta en un error de compilación por discrepancia de tipos. La función REAL_TO_DWORD tampoco es la solución, ya que convierte el REAL a un entero de 32 bits, truncando la parte decimal y perdiendo la esencia del valor flotante.
La solución no es convertir el valor, sino reinterpretar la representación en memoria. Un REAL y un DWORD ocupan ambos 4 bytes (32 bits) en memoria. La clave está en manipular esos bytes sin alterar su secuencia. En entornos con soporte completo, una UNION de tipos (una estructura que permite acceder a la misma ubicación de memoria con diferentes tipos de datos) sería la herramienta ideal. Sin embargo, como reporta el usuario, esta funcionalidad puede no estar disponible o estar deshabilitada en ciertas versiones de PC Worx Express, lo que obliga a una solución de bajo nivel: el bit-packing manual.
Solución Paso a Paso: Implementación en Structured Text
La estrategia consiste en utilizar operaciones de desplazamiento de bits (SHL, SHR) y máscaras (AND) para desensamblar y ensamblar los 32 bits del REAL en dos WORDs, respetando el orden de bytes (endianness) requerido por el protocolo Modbus, que típicamente es big-endian (el byte más significativo primero).
A continuación, se presenta un bloque de código ST funcional que incluye funciones para ambas direcciones: empaquetar un REAL en dos WORDs para la respuesta del servidor, y desempaquetar dos WORDs en un REAL para procesar escrituras desde el cliente Modbus.
// =====================================================================
// Funciones de Utilidad para Conversión REAL <-> WORD Array (Modbus)
// Orden Big-Endian (MSW primero): HoldingRegs[0] = WORD Alto, [1] = WORD Bajo
// =====================================================================
FUNCTION REAL_TO_MODBUS : BOOL
VAR_INPUT
fValue : REAL; // Valor REAL de entrada
nArrayIdx: INT; // Índice base en el array de WORDs (ej: 0)
END_VAR
VAR_IN_OUT
aHoldingRegs: ARRAY[*] OF WORD; // Array de registros Modbus
END_VAR
VAR
dwTemp : DWORD; // DWORD temporal para manipulación de bits
wHighWord, wLowWord: WORD;
END_VAR
// 1. Reinterpretar los bits del REAL como un DWORD
dwTemp := REAL_TO_DWORD(fValue); // Esta función copia bits, no convierte valor.
// 2. Extraer el WORD Alto (bits 31..16) - Big-Endian para Modbus
wHighWord := WORD(SHR( dwTemp AND 16#FFFF0000, 16 ));
// 3. Extraer el WORD Bajo (bits 15..0)
wLowWord := WORD(dwTemp AND 16#0000FFFF);
// 4. Asignar al array en el orden correcto
aHoldingRegs[nArrayIdx] := wHighWord;
aHoldingRegs[nArrayIdx+1] := wLowWord;
REAL_TO_MODBUS := TRUE;
END_FUNCTION
FUNCTION MODBUS_TO_REAL : REAL
VAR_INPUT
nArrayIdx: INT; // Índice base en el array de WORDs
END_VAR
VAR_IN_OUT
aHoldingRegs: ARRAY[*] OF WORD; // Array de registros Modbus
END_VAR
VAR
dwTemp : DWORD;
END_VAR
// 1. Reconstruir el DWORD a partir de dos WORDs (Big-Endian)
dwTemp := SHL( DWORD(aHoldingRegs[nArrayIdx]), 16 ); // WORD Alto a posiciones 31..16
dwTemp := dwTemp OR DWORD(aHoldingRegs[nArrayIdx+1]); // WORD Bajo a posiciones 15..0
// 2. Reinterpretar los bits del DWORD como un REAL
MODBUS_TO_REAL := DWORD_TO_REAL(dwTemp);
END_FUNCTION
Implementación en el Programa Principal:
En tu programa, declarar un array global para los registros (ej: MB_Holding_Regs : ARRAY[0..99] OF WORD;) y vincularlo al bloque servidor Modbus. Para servir un valor, por ejemplo, la temperatura de un proceso:
REAL_TO_MODBUS(fValue:=rTemperaturaProceso, nArrayIdx:=10, aHoldingRegs:=MB_Holding_Regs);
El cliente Modbus leerá los registros 40011 y 40012 (asumiendo el offset estándar) para obtener el valor flotante. Para procesar un setpoint escrito por el cliente en los registros 40021 y 40022:
rSetpointRecibido := MODBUS_TO_REAL(nArrayIdx:=20, aHoldingRegs:=MB_Holding_Regs);
Beneficios y Aplicaciones Prácticas
Dominar esta técnica de conversión abre la puerta a una integración más fluida y confiable en escenarios clave de la Industria 4.0:
- Integración de Sensores y Actuadores Inteligentes: Muchos dispositivos de campo modernos (sensores de presión, caudalímetros, variadores de frecuencia) utilizan valores de coma flotante para datos de proceso de alta precisión. Esta solución permite incorporarlos directamente a SCADAs o sistemas MES a través de Modbus TCP.
- Puente entre Equipos Legacy y Nuevos Sistemas: Al poder exponer y consumir datos REAL de forma nativa en Modbus, el controlador ILC actúa como un adaptador perfecto entre maquinaria antigua que solo maneja registros enteros y nuevas plataformas de análisis que requieren datos de alta precisión.
- Desarrollo de Bibliotecas Reutilizables: El código presentado puede encapsularse en un bloque función propio (FB) o en una biblioteca de usuario, creando un componente estándar y probado para todos los proyectos de tu equipo, reduciendo errores y tiempo de desarrollo.
- Preparación para IIoT: El envío de datos de proceso a plataformas en la nube o edge computing frecuentemente se realiza mediante gateways que hablan Modbus TCP. Tener los datos en formato REAL desde el origen evita conversiones posteriores y pérdida de fidelidad.
La solución, aunque parece de bajo nivel, garantiza el control total del ingeniero sobre la comunicación, eliminando dependencias de funciones propietarias oscuras o configuraciones mágicas que fallen en la siguiente actualización de software.
Perspectiva Industrial Vibe
El problema discutido trasciende a Phoenix Contact y PC Worx. Es un síntoma de una tensión inherente en la automatización industrial: la coexistencia de protocolos simples y robustos, diseñados hace décadas, con la necesidad moderna de manejar datos complejos y de alta precisión. Modbus, un protocolo venerable, no fue diseñado para tipos de datos flotantes, por lo que la carga de la interpretación correcta recae siempre en los extremos de la comunicación.
Este caso refuerza dos principios cruciales para el ingeniero de automatización moderno:
- La importancia de comprender la representación de datos a nivel de bits y bytes. En un mundo de capas de abstracción, a veces es necesario descender al nivel más fundamental para resolver problemas de integración.
- La necesidad de documentar y estandarizar las convenciones dentro de un proyecto. ¿Big-endian o little-endian? ¿Qué registros contienen qué tipo de dato? Una hoja de cálculo de mapeo de registros Modbus bien definida es tan crítica como el diagrama de cableado.
Mientras esperamos que futuros estándares o extensiones de protocolo (como Modbus TCP con tipos de datos extendidos) se adopten masivamente, soluciones como la aquí descrita seguirán siendo herramientas esenciales en la caja de herramientas del integrador. No es un workaround, es una demostración de oficio.
Conclusión
La integración de sistemas heterogéneos es una constante en la automatización industrial. El desafío de servir valores REAL a través de Modbus TCP en controladores como el ILC 151 de Phoenix Contact tiene una solución elegante y eficaz mediante la manipulación directa de bits en lenguaje ST.
- El problema: Una incompatibilidad de tipos entre el array de WORDs del servidor Modbus y los valores REAL del proceso.
- La solución: Utilizar las funciones
REAL_TO_DWORDyDWORD_TO_REALpara reinterpretar la memoria, combinado con operaciones de bits para dividir y combinar los 32 bits en dos registros de 16 bits, respetando el orden big-endian. - El resultado: Un mecanismo fiable y de alto rendimiento para comunicar datos de precisión, esencial para aplicaciones de supervisión, control avanzado e IIoT.
- El valor añadido: Código reutilizable que incrementa la robustez y mantenibilidad de los proyectos de integración.
¿Has enfrentado retos similares con otros protocolos o entornos de programación? ¿Tienes una variante optimizada de este código? Te invitamos a compartir tus experiencias y soluciones en la sección de comentarios de Industrial Vibe.
Fuente: Reddit r/PLC