Introducción
Modbus es un estándar muy útil que nos permite comunicar varios dispositivos de diferentes fabricantes en la misma red. Además Modbus TCP/IP se transfiere a través de Ethernet que es uno de los protocolos más fiables del mercado.
En este caso, mostraremos cómo configurar dos PLCs industriales basados en ArduinoM-Duinos, uno utilizado como amo y el otro como esclavo.
Control Industrial
Requisitos para la conexión entre un controlador lógico programable industrial Arduino y Modbus TCP/IP
Controlador industrial basado en Arduino Modbus TCPs TCP/IP Master/Slave ejemplos:
Sigue el post anterior para ver el código Slave que hemos utilizado en este ejemplo:
Cómo usar la biblioteca Modbus TCP Slave con un controlador PLC Arduino Leer el post >>>
También, echa un vistazo a la publicación del Maestro para ver cómo usar la Biblioteca Modbus, pero para el Maestro hemos cambiado un poco el código para hacerlo más interactivo con el usuario:
Modbus TCP Master con PLCs basados en Arduino industrial Leer el post >>>
Arquitectura de aplicación de la conexión entre un PLC Arduino y Modbus TCP/IP
M-Duino Master tiene un menú serie interactivo que permite al usuario controlar la aplicación. El menú tiene 6 opciones. Las primeras cuatro opciones son controlar dos salidas del Slave, la quinta opción es obtener las entradas Analógicas o registros del Slave y la última opción, es obtener las entradas Digitales o entradas discretas del Slave.
Usamos las funciones use writeSingleCoil(), readInputRegisters() y readDiscreteInputs() para comunicarnos con el Slave. A continuación, simplemente ejecutando un corto loop dependiendo del mensaje que hayamos enviado, leemos los valores usando response.getRegister() o response.isDiscreteInputSet().
El resto del código es solo configuraciones Ethernet y comandos Serial para depurar y hacer que la aplicación sea más interactiva.
modbus tcp ip
Software
/*
Copyright © 2018 Boot&Work Corp., S.L. All rights reserved
This program is free software: you can redistribute it and/or modify
it is under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <ModbusTCPMaster.h>
#if defined(MDUINO_PLUS)
#include <Ethernet2.h>
#else
#include <Ethernet.h>
#endif
// Ethernet configuration values
uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(10, 10, 10, 3);
IPAddress slaveIp(10, 10, 10, 4);
uint16_t slavePort = 502;
// Define the ModbusTCPMaster object
ModbusTCPMaster modbus;
//
bool registerSet = 0;
bool discreteSet = 0;
// Ethernet client object used to connect to the slave
EthernetClient slave;
uint32_t lastSentTime = 0UL;
uint32_t lastSentTimeReadInputs = 0UL;
////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
Serial.begin(9600UL);
// Begin Ethernet
Ethernet.begin(mac, ip);
Serial.println(Ethernet.localIP());
// NOTE: it is not necessary to start the modbus master object
mainUI();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
// Connect to slave if not connected
// The ethernet connection is managed by the application, not by the library
// In this case the connection is opened once
if (!slave.connected()) {
Serial.println("Slave not connected");
slave.stop();
slave.connect(slaveIp, slavePort);
if (slave.connected()) {
Serial.println("Reconnected");
}
}
// Send a request every 1000ms if connected to slave
if (slave.connected()) {
//Serial.println("Slave connected");
if (Serial.available()) {
byte chosenOption= Serial.read();
bool value;
byte address;
switch(chosenOption){
case '1': //set Q0_0 to high
value = 1;
address = 0;
if (!(modbus.writeSingleCoil(slave, 0, address, value))) {
// Failure treatment
Serial.println("Request fail");
}
Serial.println("Q0_0 set to HIGH");
break;
case '2': //set Q0_0 to low
value = 0;
address = 0;
if (!(modbus.writeSingleCoil(slave, 0, address, value))) {
// Failure treatment
Serial.println("Request fail");
}
Serial.println("Q0_0 set to LOW");
break;
case '3': //set Q0_1 to high
value = 1;
address = 1;
if (!(modbus.writeSingleCoil(slave, 0, address, value))) {
// Failure treatment
Serial.println("Request fail");
}
Serial.println("Q0_1 set to HIGH");
break;
case '4':
value = 0;
address= 1;
if (!(modbus.writeSingleCoil(slave, 0, address, value))) {
// Failure treatment
Serial.println("Request fail");
}
Serial.println("Q0_1 set to LOW");
break;
case '5':
if (!modbus.readInputRegisters(slave, 0, 0, 6)) {
// Failure treatment
Serial.println("Error requesting registers");
}else{registerSet = true;}
break;
case '6':
if (!modbus.readDiscreteInputs(slave, 0, 0, 7)) {
// Failure treatment
Serial.println("Error requesting discrete input");
}else{discreteSet = true;}
break;
}
mainUI();
}
if (modbus.isWaitingResponse()) {
ModbusResponse response = modbus.available();
if (response) {
if (response.hasError()) {
// Response failure treatment. You can use response.getErrorCode()
// to get the error code.
}else if (registerSet){
// Get the input registers values from the response
Serial.print("Input registers values: ");
for (int i = 0; i < 6; ++i) {
Serial.print(response.getRegister(i));
Serial.print(',');
}
registerSet = false;
} else if(discreteSet) {
// Get the input registers values from the response
Serial.print("Input discrete values: [");
for (int i = 0; i < 7; ++i) {
Serial.print(response.isDiscreteInputSet(i));
Serial.print(',');
}
Serial.println(']');
discreteSet = false;
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void mainUI(){
Serial.println("********************Modbus Test*********************");
Serial.println("Chose an option:");
Serial.println("1. Set Q0_0 to HIGH");
Serial.println("2. Set Q0_0 to LOW");
Serial.println("3. Set Q0_1 to HIGH");
Serial.println("4. Set Q0_1 to LOW");
Serial.println("5. Print slave input analog values");
Serial.println("6. Print slave input digital values");
Serial.println("****************************************************");
}
* IMPORTANTE: al conectar los PLC, se debe utilizar un cable Ethernet cruzado