El protocolo de comunicaciones ModBus está situado en el Nivel 2 del modelo de interconexión de sistemas abiertos (ISO/IEC 7498-1), también llamado OSI (Open System Interconnection) y que fue creado por la Organiz. Internacional para la Estandarización (ISO) en el año 1984. Está basado en la arquitectura maestro/esclavo o cliente/servidor y fue diseñado en 1979 por Modicon para su gama de controladores lógicos programables (PLCs) convirtiéndose algunos años después en uno de los protocolos más usados en el mundo de la automatización de procesos industriales. Su éxito radica en lo sencillo que resulta implementarlo y en que es posible encontrar gran cantidad de documentación donde se tratan todos los aspectos técnicos del mismo.
ModBus permite el control de una red de dispositivos de forma rápida y sencilla sin necesidad de grandes infraestructuras cliente/servidor y que puede estar conformado por elementos de diferente naturaleza: sensores de temperatura, humedad, variadores de frecuencia y un largo etcétera de dispositivos que implementan este protocolo.
Existen dos variantes del mismo protocolo: ModBus RTU, que es una representación binaria de los datos y ModBus ASCII, que es una representación legible en formato ASCII pero menos eficiente. Ambas implementaciones del protocolo son del tipo de comunicación serie.
La variante que veremos en este post es la de ModBus RTU y que, como puede leerse más arriba, empaqueta la información de forma binaria. Dicha información es almacenada en la memoria de cada dispositivo en forma de parámetros ordenados secuencialmente, de forma que desde nuestro programa de control ModBus RTU podemos leer el valor de un parámetro determinado o modificarlo para que el funcionamiento del dispositivo cambie en consecuencia. Existen dos tipos de comandos: de lectura y de escritura, que permiten realizar la acción correspondiente sobre el dispositivo. Inicialmente Modicon, cuando definió el protocolo, creó varios tipos de comandos de lectura y varios de escritura según los siguientes identificadores:
Por otro lado, cada dispositivo presente en la red ModBus está identificado por un número único, de 0 a 255, que le permitirá atender solamente aquellas peticiones de lectura o escritura que circulen por la red y que coincidan con su indentificador. Como ejemplo, he desarrollado una aplicación que puedes descargar en la columna derecha de este post, en Descargas relacionadas:
En primer lugar deberían seleccionarse los parámetros básicos de configuración tales como velocidad en baudios, paridad, bits de datos, etc. en el menú File.
Después de haber configurado las comunicaciones en nuestra aplicación de ejemplo es necesario seleccionar el identificador del dispositivo ModBus con el que deseamos comunicar (Terminal ID) y Command a ‘3’ (Read Analog Output Holding Registers) así como el parámetro donde deseamos que comience nuestra lectura (Address) y el número de bytes a leer (Quantity) desde ese parámetro, por defecto un solo byte. Nuestro programa efectúa la construcción del comando ModBus de la siguiente manera:
Como puede comprobarse el mensaje para leer un parámetro ModBus está formado por 8 bytes, en la siguiente forma:
Byte_07 y Byte_08 se refieren a un cálculo de chequeo llamado Comprobación de Redundancia Cíclica (CRC) y que se calcula con los bytes desde Byte_01 a Byte_06 para asegurarse de que toda la información enviada y recibida por los distintos dispositivos de la red ModBus es correcta y coherente. Veremos la función después.
El comando de escritura también está formado por 8 bytes, en la siguiente forma:
La única diferencia reseñable es que Byte_05 y Byte_06 contienen el valor que deseamos escribir en el registro Address (Byte_03 y Byte_04) del dispositivo ModBus.
El código fuente de la parte de nuestra aplicación que conforma el mensaje de escritura queda como sigue:
Tanto la formación del comando de lectura como de escritura necesitan un sistema de comprobación de la integridad de la información que contiene (CRC), así que la siguiente función es la encargada de recorrer los primeros 6 bytes que forman el comando y hacer una serie de operaciones que darán como resultado un valor de 16 bits que será añadido al final del comando, antes de ser enviado.
Como consecuencia de las operaciones de lectura o escritura, cada uno de los dispositivos controlados mediante ModBus retornan una respuesta: la información recuperada del dispositivo, en el caso de envío de un comando de lectura, o una confirmación de que el valor que queríamos escribir ha sido colocado con éxito. Durante mucho tiempo he buscado una aplicación que fuera capaz de recuperar esa respuesta con garantías, sin éxito ya que esta parte determina el correcto funcionamiento de nuestro sistema de control. Finalmente, he implementado un sistema de recogida de la respuesta usando un evento del propio sistema de comunicaciones serie:
Esta aplicación además incluye algunas opciones más para garantizar la correcta recepción de la respuesta. El ejecutable está disponible en el margen derecho de esta página, en el apartado Descargas relacionadas.
![]() |
![]() |
![]() |
ModBus permite el control de una red de dispositivos de forma rápida y sencilla sin necesidad de grandes infraestructuras cliente/servidor y que puede estar conformado por elementos de diferente naturaleza: sensores de temperatura, humedad, variadores de frecuencia y un largo etcétera de dispositivos que implementan este protocolo.
Existen dos variantes del mismo protocolo: ModBus RTU, que es una representación binaria de los datos y ModBus ASCII, que es una representación legible en formato ASCII pero menos eficiente. Ambas implementaciones del protocolo son del tipo de comunicación serie.
La variante que veremos en este post es la de ModBus RTU y que, como puede leerse más arriba, empaqueta la información de forma binaria. Dicha información es almacenada en la memoria de cada dispositivo en forma de parámetros ordenados secuencialmente, de forma que desde nuestro programa de control ModBus RTU podemos leer el valor de un parámetro determinado o modificarlo para que el funcionamiento del dispositivo cambie en consecuencia. Existen dos tipos de comandos: de lectura y de escritura, que permiten realizar la acción correspondiente sobre el dispositivo. Inicialmente Modicon, cuando definió el protocolo, creó varios tipos de comandos de lectura y varios de escritura según los siguientes identificadores:
| Comando | Hex | Descripción |
| 01 | &H01 | Read Discrete Output Coils |
| 05 | &H05 | Write single Discrete Output Coil |
| 15 | &H0F | Write multiple Discrete Output Coils |
| 02 | &H02 | Read Discrete Input Contacts |
| 04 | &H04 | Read Analog Input Registers |
| 03 | &H03 | Read Analog Output Holding Registers |
| 06 | &H06 | Write single Analog Output Holding Register |
| 16 | &H10 | Write multiple Analog Output Holding Registers |
Por otro lado, cada dispositivo presente en la red ModBus está identificado por un número único, de 0 a 255, que le permitirá atender solamente aquellas peticiones de lectura o escritura que circulen por la red y que coincidan con su indentificador. Como ejemplo, he desarrollado una aplicación que puedes descargar en la columna derecha de este post, en Descargas relacionadas:
En primer lugar deberían seleccionarse los parámetros básicos de configuración tales como velocidad en baudios, paridad, bits de datos, etc. en el menú File.
Formando el comando de lectura
Después de haber configurado las comunicaciones en nuestra aplicación de ejemplo es necesario seleccionar el identificador del dispositivo ModBus con el que deseamos comunicar (Terminal ID) y Command a ‘3’ (Read Analog Output Holding Registers) así como el parámetro donde deseamos que comience nuestra lectura (Address) y el número de bytes a leer (Quantity) desde ese parámetro, por defecto un solo byte. Nuestro programa efectúa la construcción del comando ModBus de la siguiente manera:
szCommand = Chr(modbusTerminalID) + Chr(modbusCmd)szCommand = szCommand + Chr(modbusAdr \ 256) + Chr(modbusAdr Mod 256)szCommand = szCommand + Chr(modbusQ \ 256) + Chr(modbusQ Mod 256)commandCRC = modbusCRC(szCommand)szCommand = szCommand + Chr(commandCRC Mod 256) + Chr(commandCRC \ 256)MSComm1.Output = szCommand
Como puede comprobarse el mensaje para leer un parámetro ModBus está formado por 8 bytes, en la siguiente forma:
| Byte_01 | Terminal ID | |
| Byte_02 | Command | |
| Byte_03 | Address MSB | |
| Byte_04 | Address LSB | |
| Byte_05 | Quantity MSB | |
| Byte_06 | Quantity LSB | |
| Byte_07 | CRC_LSB | |
| Byte_08 | CRC_MSB |
Byte_07 y Byte_08 se refieren a un cálculo de chequeo llamado Comprobación de Redundancia Cíclica (CRC) y que se calcula con los bytes desde Byte_01 a Byte_06 para asegurarse de que toda la información enviada y recibida por los distintos dispositivos de la red ModBus es correcta y coherente. Veremos la función después.
Formando el comando de escritura
El comando de escritura también está formado por 8 bytes, en la siguiente forma:
| Byte_01 | Terminal ID | |
| Byte_02 | Command | |
| Byte_03 | Address MSB | |
| Byte_04 | Address LSB | |
| Byte_05 | Value MSB | |
| Byte_06 | Value LSB | |
| Byte_07 | CRC_LSB | |
| Byte_08 | CRC_MSB |
La única diferencia reseñable es que Byte_05 y Byte_06 contienen el valor que deseamos escribir en el registro Address (Byte_03 y Byte_04) del dispositivo ModBus.
El código fuente de la parte de nuestra aplicación que conforma el mensaje de escritura queda como sigue:
szCommand = Chr(modbusTerminalID) + Chr(modbusCmd)szCommand = szCommand + Chr(modbusAdr \ 256) + Chr(modbusAdr Mod 256)szCommand = szCommand + Chr(modbusValue \ 256) + Chr(modbusValue Mod 256)commandCRC = modbusCRC(szCommand)szCommand = szCommand + Chr(commandCRC Mod 256) + Chr(commandCRC \ 256)MSComm1.Output = szCommand
El cálculo de CRC de los comandos
Tanto la formación del comando de lectura como de escritura necesitan un sistema de comprobación de la integridad de la información que contiene (CRC), así que la siguiente función es la encargada de recorrer los primeros 6 bytes que forman el comando y hacer una serie de operaciones que darán como resultado un valor de 16 bits que será añadido al final del comando, antes de ser enviado.
Function modbusCRC(Command As String) As LongLength = Len(Command)CRC = 65535Generator = 40961For charCnt = 1 To LengthTemp = Asc(Mid(Command, charCnt, 1))CRC = CRC Xor TempFor j = 1 To 8Bit = CRC And 1CRC = CRC \ 2If Bit = True ThenCRC = CRC Xor GeneratorEnd IfNext jNext charCntmodbusCRC = CRCEnd Function
La respuesta de los dispositivos
Como consecuencia de las operaciones de lectura o escritura, cada uno de los dispositivos controlados mediante ModBus retornan una respuesta: la información recuperada del dispositivo, en el caso de envío de un comando de lectura, o una confirmación de que el valor que queríamos escribir ha sido colocado con éxito. Durante mucho tiempo he buscado una aplicación que fuera capaz de recuperar esa respuesta con garantías, sin éxito ya que esta parte determina el correcto funcionamiento de nuestro sistema de control. Finalmente, he implementado un sistema de recogida de la respuesta usando un evento del propio sistema de comunicaciones serie:
Select Case MSComm1.CommEventCase comEvReceiveIf (MSComm1.InBufferCount > 0) ThendataReceived = MSComm1.InputEnd IfEnd Select
Esta aplicación además incluye algunas opciones más para garantizar la correcta recepción de la respuesta. El ejecutable está disponible en el margen derecho de esta página, en el apartado Descargas relacionadas.
Comparte este post
2013-06-11 18:03:17
Tags: #Modbus
Posts relacionados



