Ir al contenido

Modbus en PLCs basados en Arduino y ESP32 con el Arduino IDE

Implementación para PLCs basados en Arduino / ESP32 (Arduino IDE)

Instalación

1. Arduino IDE: Para la implementación de PLCs basados en Arduino y ESP32, comúnmente se utiliza el Arduino IDE. Descárgalo aquí.

2. Placas de Industrial Shields: Para poder trabajar con los PLCs de Industrial Shields, instala su paquete de placas, siguiendo esta guía, paso a paso.

3. Librería Modbus: Descarga la librería Modbus que se usará en esta lección. Instálala desde aquí.

Esclavo

Los siguientes ejemplos son implementaciones de esclavo Modbus tanto con RTU como con TCP. Estos códigos también se pueden encontrar en el Arduino IDE en Archivo > Ejemplos > Tools40 > Modbus:


Esclavo Modbus RTU


Esclavo Modbus TCP 

Guía de implementación

Las diferencias entre la implementación de RTU y TCP están en las configuraciones iniciales, ya que RTU funciona sobre RS-485 y TCP funciona sobre Ethernet:

  • Para Modbus RTU (utilizando RS-485):
    • Incluye las librerías <RS485.h> y <ModbusRTUSlave.h>
    • Instanciar el objeto Modbus con: ModbusRTUSlave modbus(RS485, slaveID);
    • Inicializar el puerto RS-485: RS485.begin(baudrate, HALFDUPLEX, SERIAL_8E1);
    • Inicializar el objeto Modbus: modbus.begin(RS485_BAUDRATE);
  • Para Modbus TCP:
    • Incluye las librerías <Ethernet.h> y <ModbusTCPSlave.h>
    • Instanciar el objeto Modbus con: ModbusTCPSlave modbus(port);
    • Inicializar el Ethernet con: Ethernet.begin(mac, ip);
    • Inicializar el objeto Modbus: modbus.begin();

1. Mapeo de registros Modbus: De acuerdo con el modelo de tu PLC, define las entradas y salidas que se mapearán como los objetos Modbus correspondientes. Los códigos de ejemplo están implementados para el M-Duino 21+. Debes modificar las entradas y salidas del código, según tu versión.

int digitalOutputsPins[] = { /* Define your digital output pins here */ };
int digitalInputsPins[] = { /* Define your digital input pins here */ };
int analogOutputsPins[] = { /* Define your analog output pins here */ };
int analogInputsPins[] = { /* Define your analog input pins here */ };

#define numDigitalOutputs (sizeof(digitalOutputsPins) / sizeof(digitalOutputsPins[0]))
#define numDigitalInputs (sizeof(digitalInputsPins) / sizeof(digitalInputsPins[0]))
#define numAnalogOutputs (sizeof(analogOutputsPins) / sizeof(analogOutputsPins[0]))
#define numAnalogInputs (sizeof(analogInputsPins) / sizeof(analogInputsPins[0]))

bool digitalOutputs[numDigitalOutputs];
bool digitalInputs[numDigitalInputs];
uint16_t analogOutputs[numAnalogOutputs];
uint16_t analogInputs[numAnalogInputs];

2. Configuración: En la función de setup, se inicializan los pines de entrada y salida del PLC. Y se configura el protocolo de comunicación, ya sea Modbus TCP o Modbus RTU. Además, se inicializa el objeto Modbus Slave y se vinculan las bobinas (coils) y registros asociados a él.

void setup() {
  // Init variables, inputs and outputs

  // Init Ethernet (for TCP) or RS-485 (for RTU)

  // Init ModbusSlave object (pass RS485 baudrate for RTU)

  modbus.setCoils(digitalOutputs, numDigitalOutputs);
  modbus.setDiscreteInputs(digitalInputs, numDigitalInputs);
  modbus.setHoldingRegisters(analogOutputs, numAnalogOutputs);
  modbus.setInputRegisters(analogInputs, numAnalogInputs);
}

3. Loop: En la función loop, el PLC actualiza continuamente sus entradas y salidas y procesa las solicitudes Modbus. Las entradas digitales y analógicas se leen y se actualizan para reflejar el estado actual. El "objeto Modbus" procesa cualquier solicitud entrante, y las salidas se actualizan, según el estado actual de las bobinas (coils) y registros.

void loop() {
  // Update Inputs
  modbus.update();
  // Update Outputs
}

Maestro

Los siguientes ejemplos son implementaciones de maestro Modbus, tanto con RTU, como con TCP. Estos códigos también se pueden encontrar en el Arduino IDE en Archivo > Ejemplos > Tools40 > Modbus, junto con más ejemplos:

Maestro Modbus RTU, leer coils

Maestro Modbus RTU, escribir coils


Maestro Modbus TCP, leer coils

Maestro Modbus TCP, escribir coils

Guía de implementación

Las diferencias entre la implementación de RTU y TCP están en las configuraciones iniciales, ya que RTU funciona sobre RS-485 y TCP funciona sobre Ethernet:

  • Para Modbus RTU (utilizando RS-485):
    • Incluye las librerías <RS485.h> y <ModbusRTUMaster.h>
    • Instanciar el "objeto Modbus" con: ModbusRTUMaster modbus(RS485);​
    • Inicializar el puerto RS-485: RS485.begin(baudrate, HALFDUPLEX, SERIAL_8E1);
    • Inicializar el objeto Modbus: modbus.begin(RS485_BAUDRATE);
  • Para Modbus TCP:
    • Incluir las librerías <Ethernet.h> y <ModbusTCPMaster.h>
    • Configurar los valores de Ethernet: dirección MAC, IP del maestro e IP del esclavo
    • Instanciar el objeto maestro con: ModbusTCPMaster modbus;​
    • Inicializar el Ethernet con: Ethernet.begin(mac, ip);

Referencias API

Como se vio en la primera lección de este curso, Modbus proporciona múltiples códigos de función (FC) para leer y escribir las diferentes bobinas (coils) y registros. Nuestra librería ofrece algunas funciones para enviar mensajes utilizando los diferentes códigos de función. Estas son las funciones disponibles:

Descripción:

Lee el contenido de un número determinado de bobinas (coils) de un dispositivo esclavo (FC=01).

Sintaxis:

readCoils(slave, addr, quantity);

Parámetros:

  • slave: la dirección del dispositivo esclavo.
  • addr: la dirección inicial de las bobinas.
  • quantity: el número de bobinas que se leen.

Devuelve:

Devuelve true si la operación se ha realizado correctamente y false en caso contrario.

Descripción:

Lee el contenido de un número determinado de entradas discretas de un dispositivo esclavo (FC=02).

Sintaxis:

readDiscreteInputs(slave, addr, quantity);

Parámetros:

  • slave: la dirección del dispositivo esclavo.
  • addr: la dirección inicial de las entradas discretas.
  • quantity: el número de entradas discretas que se leen.

Devuelve:

Devuelve true si la operación se ha realizado correctamente y false en caso contrario.

Descripción:

Lee el contenido de un número determinado de registros de retención (holding registers) de un dispositivo esclavo (FC=03).

Sintaxis:

readHoldingRegisters(slave, addr, quantity);

Parámetros:

  • slave: la dirección del dispositivo esclavo.
  • addr: la dirección inicial de los registros de retención.
  • quantity: el número de registros de retención que se leen.

Devuelve:

Devuelve true si la operación se ha realizado correctamente y false en caso contrario.

Descripción:

Lee el contenido de un número determinado de registros de entrada (input registers) de un dispositivo esclavo (FC=04).

Sintaxis:

readInputRegisters(slave, addr, quantity);

Parámetros:

  • slave: la dirección del dispositivo esclavo.
  • addr: la dirección inicial de los registros de entrada.
  • quantity: el número de registros de entrada que se leen.

Devuelve:

Devuelve true si la operación se ha realizado correctamente y false en caso contrario.

Descripción:

Escribe una sola bobina a 0 o a 1 en un dispositivo esclavo (FC=05).

Sintaxis:

writeSingleCoil(slave, addr, value);

Parámetros:

  • slave: la dirección del dispositivo esclavo.
  • addr: la dirección de la bobina.
  • value: el valor que se escribe en la bobina.

Devuelve:

Devuelve true si la operación se ha realizado correctamente y false en caso contrario.

Descripción:

Escribe un valor en un solo registro de retención de un dispositivo esclavo (FC=06).

Sintaxis:

writeSingleRegister(slave, addr, value);

Parámetros:

  • slave: la dirección del dispositivo esclavo.
  • addr: la dirección del registro de retención.
  • value: el valor que se escribe en el registro de retención.

Devuelve:

Devuelve true si la operación se ha realizado correctamente y false en caso contrario.

Descripción:

Escribe valores en una secuencia de bobinas de un dispositivo esclavo (FC=15).

Sintaxis:

writeMultipleCoils(slave, addr, values, quantity);

Parámetros:

  • slave: la dirección del dispositivo esclavo.
  • addr: la dirección inicial de las bobinas.
  • values: los valores que se escriben en las bobinas.
  • quantity: el número de bobinas que se escriben.

Devuelve:

Devuelve true si la operación se ha realizado correctamente y false en caso contrario.

Descripción:

Escribe valores en una secuencia de registros de retención de un dispositivo esclavo (FC=16).

Sintaxis:

writeMultipleRegisters(slave, addr, values, quantity);

Parámetros:

  • slave: la dirección del dispositivo esclavo.
  • addr: la dirección inicial de los registros de retención.
  • values: los valores que se escriben en los registros de retención.
  • quantity: el número de registros de retención que se escriben.

Devuelve:

Devuelve true si la operación se ha realizado correctamente y false en caso contrario.

Calificación
0 0

No hay comentarios por ahora.

para ser el primero en comentar.

1. En la implementación con el Arduino IDE, ¿qué librerías incluyes para un esclavo Modbus RTU?