Modbus

por | 24 julio, 2016

RS485

RS-485 Es un estándar de comunicaciones en bus de la capa física del Modelo OSI. Está definido como un sistema de bus diferencial multipunto, es ideal para transmitir a altas velocidades sobre largas distancias (35 Mbit/s hasta 10 metros y 100 kbit/s en 1200 metros) y a través de canales ruidosos, ya que el par trenzado reduce los ruidos que se inducen en la línea de transmisión. El medio físico de transmisión es un par trenzado que admite 32, 128 o 254 estaciones en 1 solo par, con una longitud máxima de 1200 metros operando entre 300 y 19200 bit/s y la comunicación half-duplex (semiduplex) dependiendo del consumo de cada driver. La transmisión diferencial permite alcanzar mayor distancia con una notable inmunidad al ruido, siempre que el bus de comunicación conserve las características de bus balanceado dando la posibilidad de una configuración multipunto.

Más información sobre RS485:

Conectar Arduino a un bus de campo consiste en conectar al bus mediante un adaptador un transceiver adecuado para el bus de campo que convierte el stream de datos de la UART al bus conectado haciendo de pasarela entre los diferentes niveles de tensión, intensidad e impedancia. Estos transceivers incluyen filtros y condensadores para adaptar adaptar y mejorar la señal.

Transceiver RS485: http://www.linear.com/product/LTC1484

Datasheet: https://www.sparkfun.com/datasheets/Components/General/sp3485CN-LTR.pdf

Otros transceivers RS-485:

Módulo RS485 para Arduino: https://arduino-info.wikispaces.com/RS485-Modules

Shields RS485 para Arduino:

Shields RS-485 para raspberry pi:

También es posible conectarse a un bus modbus con un ordenador mediante USB y con un conversor de USB a RS485. También es posible con este módulo controlar varios Arduino conectados a un bus modbus.

Cable conversor: http://www.ftdichip.com/Support/Documents/DataSheets/Cables/DS_USB_RS485_CABLES.pdf

Breakout board: https://www.sparkfun.com/products/9822

Ejemplo de uso:

Guía de conexión RS-485:

Ejemplo de uso de bus de campo sobre una red RS-485 (bus serie) para comunicar con una sonda HygroClip 2 (HC2) Probe with AirChip 3000: https://github.com/jecrespo/AirChip_3000

La sonda tiene un chip AirChip 3000:

Tipo de interface  (por defecto) UART (Receptor-Transmisor Asíncrono Universal)
Organización Diálogo, dúplex
Configuración por defecto Baud rate : 19200
Paridad : Ninguna
bits de datos : 8
bits de parada : 1
Flow Control : none
Tolerancia 3 %
Configuración de Baud rate : No
Niveles lógicos Lógica 0: < = 0.3V * VDD
Lógica 1: > = 0.8V * VDD
Longitud máxima del cable 5 m (Sin amplificador de señal)

Protocolo de HC2: ver pdf de HC2 y pdf de Hygroclyp en https://github.com/jecrespo/AirChip_3000/tree/master/Doc

Sondas con airchip 3000: http://www.rotronic.com/catalogsearch/result/?q=airchip+3000

Sonda utilizada: http://www.rotronic.com/hc2-ldp.html e información adicional: http://www.lesmaninst.com/unleashd/catalog/analytical/Rotronic-HygroClip2/Intro-to-Rotronic-HC2-Probes.pdf

Protocolo Modbus

Modbus un protocolo de comunicaciones situado en el nivel 7 del Modelo OSI, basado en la arquitectura maestro/esclavo (RTU) o cliente/servidor (TCP/IP), diseñado en 1979 por Modicon para su gama de controladores lógicos programables (PLCs). Convertido en un protocolo de comunicaciones estándar de facto en la industria, es el que goza de mayor disponibilidad para la conexión de dispositivos electrónicos industriales. Las razones por las cuales el uso de Modbus es superior a otros protocolos de comunicaciones es:

  1. Es público
  2. Su implementación es fácil y requiere poco desarrollo
  3. Maneja bloques de datos sin suponer restricciones

Modbus es definido como un protocolo maestro/esclavo. No es posible tener más de un master Modbus en una red Modbus RTU.

Modbus permite el control de una red de dispositivos, por ejemplo un sistema de medida de temperatura y humedad, y comunicar los resultados a un ordenador. Modbus también se usa para la conexión de un ordenador de supervisión con una unidad remota (RTU) en sistemas de supervisión adquisición de datos (SCADA). Existen versiones del protocolo Modbus para puerto serie y Ethernet (Modbus/TCP).

Existen dos variantes, con diferentes representaciones numéricas de los datos y detalles del protocolo ligeramente desiguales. Modbus RTU es una representación binaria compacta de los datos. Modbus ASCII es una representación legible del protocolo pero menos eficiente. Ambas implementaciones del protocolo son serie. El formato RTU finaliza la trama con una suma de control de redundancia cíclica (CRC), mientras que el formato ASCII utiliza una suma de control de redundancia longitudinal (LRC). La versión Modbus/TCP es muy semejante al formato RTU, pero estableciendo la transmisión mediante paquetes TCP/IP (puerto del sistema 502, identificador asa-appl-proto).

Modbus/ASCII y Modbus/RTU:

Modbus/ASCII Modbus/RTU
Characters ASCII 0…9 and A..F Binary 0…255
Error check LRC Longitudinal Redundancy Check CRC Cyclic Redundancy Check
Frame start character ‘:‘ 3.5 chars silence
Frame end characters CR/LF 3.5 chars silence
Gaps in message 1 sec 1.5 times char length
Start bit 1 1
Data bits 7 8
Parity even/odd none even/odd none
Stop bits 1 2 1 2

Modbus

Más información:

Modbus Plus (Modbus+ o MB+), es una versión extendida del protocolo y privativa de Modicon. Dada la naturaleza de la red precisa un coprocesador dedicado para el control de la misma. Con una velocidad de 1 Mbit/s en un par trenzado sus especificaciones son muy semejantes al estándar EIA/RS-485 aunque no guarda compatibilidad con este.

Trama Modbus

La trama Modbus se transmite igual que si fuera por un puerto serie con sus características.

Dirección (1byte): En el caso de las tramas enviadas por el máster, el campo de número de esclavo indica la dirección del destinatario de esta trama. Permite direccionar hasta 247 esclavos, con las direcciones de 1 a 247 (0x00 a 0xF7). El 0x00 es para los mensajes de Broadcast, así el primer esclavo comienza con la dirección 1 ( de 1 a 247 ). En el caso de las tramas enviadas por los esclavos, este byte sirve para indicar al máster a quién pertenece la respuesta. Es decir, cada vez que un esclavo responde, sitúa su propia dirección en el byte de dirección lo que permite saber al maestro a que equipo corresponde cada respuesta. Las tramas broadcast, no tienen asociada respuesta, y algunas implementaciones de MODBUS no admiten la trama de broadcast.

Cada dispositivo de la red Modbus posee una dirección única. Cualquier dispositivo puede enviar órdenes Modbus, aunque lo habitual es permitirlo sólo a un dispositivo maestro. Cada comando Modbus contiene la dirección del dispositivo destinatario de la orden. Todos los dispositivos reciben la trama pero sólo el destinatario la ejecuta (salvo un modo especial denominado “Broadcast”). Cada uno de los mensajes incluye información redundante que asegura su integridad en la recepción. Los comandos básicos Modbus permiten controlar un dispositivo RTU para modificar el valor de alguno de sus registros o bien solicitar el contenido de dichos registros.

Código de Operación o Función (1 byte): Indica el tipo de operación que queremos realizar sobre el esclavo. Las operaciones se pueden clasificar en dos tipos:

  • De lectura / escritura en memoria: para consultar o modificar el estado de los registros del mapa de memoria del esclavo.
  • Órdenes de control del esclavo: para realizar alguna actuación sobre el esclavo.

El código de operación puede tomar cualquier valor comprendido entre el 0 y el 127 ( el bit de más peso se reserva para indicar error). Cada código se corresponde con una determinada operación. Algunos de estos códigos se consideran estándar y son aceptados e interpretados por igual por todos los dispositivos que dicen ser compatibles con MODBUS, mientras que otros códigos son implementaciones propias de cada fabricante. Es decir que algunos fabricantes realizan implementaciones propias de estos códigos “no estándar”.

Es también mediante el código de función que el esclavo confirma si la operación se ha ejecutado correctamente o no. Si ha ido bien responde con el mismo código de operación que se le ha enviado, mientras que si se ha producido algún error, responde también con el mismo código de operación pero con su bit de más peso a 1 ( 0x80 ) y un byte en el campo de datos indicando el código de error que ha tenido lugar.

Funciones Modbus:

Funciones

Dirección, datos y subfunciones (n bytes): Este campo contiene la información necesaria para realizar la operación indicada en el código de operación. Cada operación necesitará de unos parámetros u otros, por lo que el número de bytes de este campo variará según la operación a realizar. En el caso del esclavo, este puede responder con tramas con o sin campo de datos dependiendo de la operación. En los casos en que se produzca algún error es posible que el esclavo responda con un byte extra para especificar el código de error.

Al establecer la dirección de una variable u otro elemento en el mapa de direcciones MODBUS, direccionamos con 1 unidad menos a la del registro al que queremos acceder, de manera que si p.ej. quisiéramos acceder al relé @ 127d, lo haríamos situando el valor 126d en el byte del campo de dirección. Otros ejemplos:

  • El relé número 1 de un controlador se direccionará con el valor 0000 en el campo de dirección de un mensaje MODBUS.
  • El relé 0x007F (127d ) de un controlador se direccionará con el valor 0x007E ( 126d ) en el campo de dirección de un mensaje MODBUS.
  • El Holding Register 40001 se accedería situando el valor 0000 en el campo de dirección del mensaje. Como se puede ver el código de función de acceso a los Holding Registers lleva implícito el acceso a la dirección ‘4XXXX’.
  • El Holding Register 40108 es accedido leyendo de la dirección 0x006B ( 107d )

Generalmente en MODBUS cada tipo de dato se mapea en un rango de memoria concreto:

  • @1-10000 (DOs – digital outputs): 1 bit por dirección para indicar el estado de una salida, mando o relé ( 0 desactivado, 1 activado ). Las direcciones de este rango se suelen acceder mediante las funciones 1 (lectura), 5 (escritura), 15 (escritura múltiple).
  • @10001-20000 (DIs – digital inputs): 1 bit por dirección para leer el estado de una entrada digital ( 0 desactivada, 1 activada ) también denominadas DIs ( Digital Inputs ). Las direcciones de este rango se suelen acceder con la función 2 (lectura) y llevan implícita la dirección 10001 como dirección base ( para acceder a una dirección bastará con especificar la distancia entre esta y la dirección base ).
  • @20001-30000: el protocolo MODBUS estándar no hace uso de este rango de direcciones.
  • @30001-40000 (AIs – analog inputs): 16 bits por dirección con el estado de las medidas o entradas analógicas también denominadas AIs ( Analog Inputs ). Dependiendo del dispositivo este puede hacer uso de más de un registro para almacenar la información de la medida, así con 2 registros consecutivos podríamos almacenar medidas de 32 bits. Las direcciones de este rango se acceden mediante la función 4 (lectura) y llevan implícita la dirección 30001 como dirección base ( para acceder a una dirección bastará con especificar la distancia entre esta y la dirección base ).
  • @40001-50000 (AOs – analog outputs): 16 bits con los registros de salidas analógicas o de propósito general ( Output Registers – Holding Registers). Se acceden con las funciones 3 ( lectura ), 6 ( escritura ) o 16 ( escritura múltiple ) y llevan implícita la dirección 40001 como dirección base ( para acceder a una dirección bastará con especificar la distancia entre esta y la dirección base ).

Cuando se produce un error en la ejecución de un comando en el esclavo, este responde poniendo a 1 el bit de más peso del código de función ( 0x80 ). Con este bit el maestro sabe que se ha producido un error, pero para obtener más detalle sobre el tipo de error, ha de comprobar el campo de datos:

Código Nombre Significado
01 ILLEGAL FUNCTION El código de función recibido no se corresponde a ningún comando disponible en el esclavo
02 ILEGAL DATA ADRESS La dirección indicada en la trama no se corresponde a ninguna dirección válida del esclavo
03 ILLEGAL DATA VALUE El valor enviado al esclavo no es válido
04 SLAVE DEVICE FAILURE El esclavo ha recibido la trama y la ha comenzado a procesar, pero se ha producido algún error y no ha podido termina la tarea.
05 ACKNOWLEDGE El esclavo ha recibido la trama y la está procesando pero esto le llevará un periodo un poco largo. Mediante esta respuesta se evita que el máster considere un error de timeout. El máster podrá enviar más tarde una trama una trama de tipo Poll Program Complete para verificar si ha completado el comando
06 SLAVE DEVICE BUSY El esclavo está ocupado realizando otra tarea y no puede atender a esa petición en ese instante por lo que el máster tendrá que reintentarlo más adelante.

Control de errores LRC o CRC: Se utiliza un sistema de detección de errores diferente dependiendo del tipo de codificación utilizado ( ASCII o RTU ) . En el caso de la codificación ASCII  es el checksum ( o  Longitud Redundancy Check LRC ) en módulo 16 expresado en ASCII ( 2 caracteres representan 1 byte ), sin considerar el “:” ni el “CR LF” de la trama. En la codificación RTU se utiliza el método de CRC ( Cyclical Redundancy Check ) codificado en 2 bytes (16  bits).

Para calcular el CRC se carga un registro de 16 bits todo con ‘1’s, se hace OR con cada uno de los caracteres de 8 bits con el contenido de cada byte y el resultado se desplaza una bit a la izquierda insertando un 0 en la posición de menor peso ( la de la derecha ). El de la izquierda se extrae y se examina: si es 1 se vuelve a hacer OR con un valor prefijado, si es 0 no se hace ninguna OR… y el proceso se repite hasta que se han hecho los 8 shifts del byte.

Cálculo CRC:

CRC

CRC:

Calcular CRC con Arduino:

Más información de modbus:

Modbus reference:

Información de modbus y SW: http://www.simplymodbus.ca/

Implementación Modbus en Arduino

Es importante conocer el protocolo modbus, pero implementarlo en Arduino puede ser una tarea compleja. Sin embargo, hay disponibles diversas librerías que implementa el protocolo y su uso es generalmente sencillo.

Al ser modbus un protocolo de capa 7, su implementación se debe hacer en el software de Arduino ya sea hecha por uno mismo o usando una librería

La librería por excelencia para MCUs es freemodbus http://www.freemodbus.org/ que implementa modbus y está muy bien documentada, el problema que tiene es que no está adaptada a Arduino, es más compleja de entender y pesa mucho, por lo que en un arduino con un programa medio podría quedarse sin memoria. Para usar esta librería, mejor usar el Atmel Studio que el IDE de Arduino.

El código está disponible en https://github.com/webconn/freemodbus, en la web no funciona el enlace de descarga, pero es un fork de la librería original.

Versión profesional: http://www.embedded-solutions.at/en/modbus

A la hora de implementar por SW el protocolo Modbus, habrá una implementación para el master y otra para el slave diferentes, puesto que el comportamiento en un caso y en otro es distinto.

Existen diversas librerías que implementan modbus en Arduino, tanto para maestro como esclavo y para RTU, ASCII y TCP. Algunas son más sencillas y solo implementan unas pocas funciones y otras más complejas y pesadas, en función de nuestro objetivo habrá que elegir una u otra.

Algunas librerías Modbus para Arduino:

Más documentación:

Interesante web con drivers y librerías modbus para todo tipo de lenguajes y también herramientas: http://www.modbusdriver.com/

Ejemplo Uso Modbus en Arduino

El primer paso es usar transceiver RS-485 para Arduino que convierta los niveles de señal de RS-485 a los de Arduino, para ello se puede usar un shield como:

Al Final todos los shields simplemente usan un max485 para convertir la capa física del RS485 a nivel TTL (0-5V):

Comunicar 2 arduino con MAX485: http://johanneskinzig.de/hardware/arduino-communicates-via.html

El segundo paso es implementar el protocolo modbus RTU en Arduino, para ello hay varias librerías como las vistas anteriormente o implementarlo directamente programando.

Supongamos el caso de querer usar un Arduino como un esclavo modbus controlado mediante un HMI que hace de maestro y el Arduino recibe los request del HMI. Algo similar a ejemplo: https://www.youtube.com/watch?v=bfZh8oy-SXs

Esta librería es muy sencilla, ocupa muy poco e implementa modbus RTU slave:  https://github.com/jecrespo/simple-modbus/tree/master/Modbus%20RTU%20libraries%20for%20Arduino/SimpleModbusSlaveV10

Si tomamos como ejemplo la pantalla HMI monitouch TS1070: http://monitouch.fujielectric.com/site/technoshot-e/ts1070-01.html y se configura un botón para enceder o apagar un elemento, leo por el puerto serie la secuencia en hex: 01-06-00-00-00-FF-C9-8A (8 Bytes)

Estructura de la trama modbus: http://www.xmcarne.com/blog-tecnico/trama-modbus/

  • Dirección esclavo = 01 (primer byte)
  • Función modbus = 06 (segundo byte)

Funciones de lectura de datos:

  • Función 01 (01 hex): Lectura de señales discretas de salida (Discrete Output Coils)
  • Función 02 (02 hex): Lectura de señales discretas de entradas (Discrete Input Contacts)
  • Función 03 (03 hex): Lectura de registros analógicos (Analog Output Holding Registers)
  • Función 04 (04 hex): Lectura de registros analógicos de entrada (Analog Input Registers)

Funciones de escritura de datos:

  • Función 05 (05 hex): Escritura de una señal discreta de salida (Simple Discrete Output Coil)
  • Función 15 (0F hex): Escritura de múltiples señales discretas de salida (Múltiple Discrete Output Coils)
  • Función 06 (06 hex): Escritura de un Simple Analog Output Holding Register
  • Función 16 (10 hex): Escritura Múltiple Analog Output Holding Registers

Byte de datos = 256 (4 bytes) = 00 – 00 – 00 – FF

CRC (Cyclic Redundancy Check o comprobación de redundancia cíclica) = C98A (2 bytes)

Para el cálculo del CRC se utilizan cada uno de los bytes que conforman la trama. El procedimiento es el siguiente:

  • Se envía la trama Modbus con el CRC calculado.
  • El receptor del mensaje recibe la trama completa e internamente calcula el CRC con los datos recibidos. Y lo compara con el CRC que le ha llegado.
    • Si el código coincide, la trama Modbus es correcta y se prosigue con el funcionamiento normal generando la respuesta pertinente.
    • Si el código es erróneo, es decir que no coincide el CRC recibido con el CRC no se responderá a la petición de datos por parte del master, de manera que ocurrirá un Timeout en recepción del Master y este deberá entender que el Slave no ha recibido la trama correctamente y procederá a un reintento.

Como calcular el CRC: http://www.xmcarne.com/blog-tecnico/crc-modbus-rtu/

Calcular CRC online http://www.lammertbies.nl/comm/info/crc-calculation.html

Para este caso obtengo CRC-16 (modbus) = 0x8AC9

Una vez  recibido el mensaje hay que devolver el mensaje a HMI para finalizar la acción, en este caso la respuesta es la misma que la recibida.

Ejemplo de como se implementa el protocolo para este caso en Arduino: https://github.com/jecrespo/Aprendiendo-Arduino/blob/master/Otros/ejemplo_modbus/ejemplo_modbus.ino

Para este caso se usó un Arduino Mega que tiene 4 puertos serie y el segundo se usó para conectar al RS-485 shield.

Otros ejemplos de uso de Modbus con Arduino:

Deja un comentario