Modbus TCP Master with Industrial Arduino & ESP32 PLCs

Communication using master-slave technique with Arduino Modbus TCP
March 25, 2020 by
Modbus TCP Master with Industrial Arduino & ESP32 PLCs
Bernat Garcia

Index

Introduction

The Modbus protocol was developed in 1979 by Modicon for industrial automation systems and programmable logic controllers with an Ethernet connection. It is used to transfer discrete/analog I/O information and register data between industrial control and monitoring devices.

M-Duino Modbus TCP

Modbus' devices communicate using a master-slave (client-server) technique, in which only one device (the master/client) can initiate transactions (called queries). The other devices (Arduino Modbus TCP server example slaves/servers) respond by supplying the requested data to the master, or by taking the action requested in the query.

A slave of Modbus is any peripheral device (I/O transducer valve, network drive, or other measuring devices) that processes information and sends its output to the master using Modbus.

The Acromag I/O Modules from slave/server devices, while a typical master device is a host computer running appropriate application software. Other devices may function as both clients (masters) and servers (slaves).

Requirements to work with Modbus TCP

In order to work with the Modbus TCP, you will need any of our Modbus PLC controllers for industrial automation:

Industrial Shields' controllers based on Arduino automation:

Modbus TCP/IP protocol

Modbus TCP- Construction of Modbus TCP data packet 

Modbus TCP/IP uses TCP/IP and Ethernet to carry the data of the Modbus message structure between compatible devices. That is, Modbus TCP/IP combines a physical network (Ethernet), with a networking standard (TCP/IP), and a standard method of representing data (Modbus as the application protocol). Essentially, the Modbus TCP/IP message is simply a Modbus communication encapsulated in an Ethernet TCP/IP wrapper.

Hardware

Configuration of the switches

Most of the inputs and the outputs are connected to the internal PLC Arduino, but in a few cases, the user can choose between a special peripheral configuration of a GPIO by changing the position of the Dip Switches.

Each switch can select only one of the two possible configurations at the same time, the right position (ON) or the left one (OFF). 

In this case, the position of the switches is not important, because communication is always available.

Software - PLC Modbus TCP Master Library

This Arduino Modbus TCP Library is only available for Industrial Shields' industrial PLC, but they can be modified by any user, so they can be used in other Arduino devices.

The Arduino Modbus TCP/IP Library contains the functions to read and write slave values:

readCoils(client, slave_address, address, quantity);
readDiscreteInputs(client, slave_address, address, quantity);
readHoldingRegisters(client, slave_address, address, quantity);
readInputRegisters(client, slave_address, address, quantity);
writeSingleCoil(client, slave_address, address, value);
writeSingleRegister(client, slave_address, address, value);
writeMultipleCoils(client, slave_address, address, values, quantity);
writeMultipleRegisters(client, slave_address, address, values, quantity);

Where

  • arduino modbus tcp client  is the Ethernet Client connected to the slave.
  • slave_address  is the Modbus RTU slave address.
  • address is the coil, digital input, holding register or input register address. Usually, this address is the coil, digital input, holding register or input register number minus 1: the holding register number 40009 has the address 8.
  • quantity is the number of coils, digital inputs, holding registers or input registers to read/write.
  • value is the given value of the coil or holding registers on a write operation. Depending on the function, the data type changes. A coil is represented by a bool value and a holding register is represented by a uint16_t value.

On a multiple read/write function, the address argument is the first element addressed. On a multiple write function, the values argument is an array of values to write.

It is important to notice that these functions are non-blocking, so they do not return the read value. They return true or false depending on the current module state. If there is a pending Modbus request or the client is not connected, they return false.

  • There is a available() function to check for responses from the slave.
  • The ModbusResponse implements some functions to get the response information:
hasError();
getErrorCode();
getSlave();
getFC();
isCoilSet(offset);
isDiscreteInputSet(offset);
isDiscreteSet(offset);
getRegister(offset);


  • PLC Modbus TCP Master Input registers reader code

/* 
   Copyright (c) 2018 Boot&Work Corp., S.L. All rights reserved

   This program is free software: you can redistribute it and/or modify
   it 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 <Ethernet.h>            // This is the client;
#include <ModbusTCPMaster.h>     // This is the master;

// Ethernet configuration values
uint8_t mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
uint8_t ip[] = { 10, 10, 10, 3 };
uint8_t slaveIp[] = { 10, 10, 10, 4 };
uint16_t slavePort = 502;

// Define the ModbusTCPMaster object
ModbusTCPMaster master;

// Ethernet client object used to connect to the slave
EthernetClient slave;

uint32_t lastSentTime = 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
}

////////////////////////////////////////////////////////////////////////////////////////////////////
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()) {
    slave.stop();

    slave.connect(slaveIp, slavePort);
  }

  // Send a request every 1000ms if connected to slave
  if (slave.connected()) {
    if (millis() - lastSentTime > 1000) {
      // Send a Read Input Registers request to the slave with address 31
      // It requests for 6 registers starting at address 0
      // IMPORTANT: all read and write functions start a Modbus transmission, but they are not
      // blocking, so you can continue the program while the Modbus functions work. To check for
      // available responses, call master.available() function often.
      if (!master.readInputRegisters(slave, 31, 0, 6)) {
        // Failure treatment
      }

      lastSentTime = millis();
    }

    // Check available responses often
    if (master.isWaitingResponse()) {
      ModbusResponse response = master.available();
      if (response) {
        if (response.hasError()) {
          // Response failure treatment. You can use response.getErrorCode()
          // to get the error code.
        } else {
          // 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(',');
          }
          Serial.println();
        }
      }
    }
  }
}

Other Arduino PLC MODBUS

Arduino RS485 working as a Modbus RTU

Modbus is a standard way to connect different devices for Industrial uses. As shown in this post, you can connect through Modbus TCP protocol using Arduino Ethernet shields or working with Arduino as a PLC, but there are other ways to use the Modbus protocol. You can also use Modbus RTU using the RS485 shield for Arduino.

Take into consideration if you need to work using Modbus with Arduino for industrial automation or industrial use. Also, you can use the same code used on an Arduino Uno board connected to any MAX485 Arduino shield using an Arduino industrial controller made from Industrial Shields. 

​Search in our Blog

Modbus TCP Master with Industrial Arduino & ESP32 PLCs
Bernat Garcia March 25, 2020

Looking for your ideal Programmable Logic Controller?

Take a look at this product comparison with other industrial controllers Arduino-based. 

We are comparing inputs, outputs, communications and other features with the ones of the relevant brands.


Industrial PLC comparison >>>