Modbus TCP Arduino - Raspberry

Good afternoon,

After searching a lot I can't find the solution to my problem. I expose: I am doing an application in which I need to transfer the weight of some scales to an external controller updating with the "minimum sample rate". I explain all the architecture to see if you can help me. On the one hand I have a Mega 2560 rev3 + ethernet shield 2 + 8 scales (I use the ADC HX711+loadcells), this works correctly and I am able to manage the values and display on the LCD screen. I also have a temperature/humidity sensor DHT11 that I also can manage with and see its values through the serial terminal. On the other hand I have a Raspberry Pi 4 with Codesys runtime. I want to communicate with the raspberry via Ethernet and be able to send the weight variables of each scale. My idea is through Modbus TCP, I try to configure the Arduino as a Server and the raspberry as a Client to make the queries. I copy the code that I have, to begin with I want to try to read / write fixed values ​​and when I see them in the raspberry correctly modify it by the weight variables. Any help will be a great help. To begin with, in the "Holdresult = modbusTCPServer.configureHoldingRegisters(0x01, nreg); " I get the result of "1" which I see indicates a failure and I don't understand why.

#include <HX711.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <SPI.h>
#include <Ethernet.h>
#include <ArduinoRS485.h> // ArduinoModbus depends on the ArduinoRS485 library
#include <ArduinoModbus.h>


//**********MODBUSTCP**********
byte mac[] = {
  0xA8, 0x61, 0x0A, 0xAE, 0xA8, 0x23
};
IPAddress ip(192, 168, 178, 10);
EthernetServer ethServer(502);
ModbusTCPServer modbusTCPServer;

uint16_t regis[] = {10, 8, 1, 2, 4, 5, 98, 74, 87, 12};

int Holdresult;
int nreg = 10;
int hold;

//***********DHT11*************
int DHTPIN = 13;
int DHTTYPE = DHT11;
int Temp;
int Hum;

DHT dht(DHTPIN, DHT11);

//**********Loadcells**********
HX711 bascula1;     //Decl objeto bascula 1
HX711 bascula2;     //Decl objeto bascula 2
HX711 bascula3;     //Decl objeto bascula 3
HX711 bascula4;     //Decl objeto bascula 4
HX711 bascula5;     //Decl objeto bascula 5
HX711 bascula6;     //Decl objeto bascula 6
HX711 bascula7;     //Decl objeto bascula 7
HX711 bascula8;     //Decl objeto bascula 8

//*****************************

LiquidCrystal_I2C lcd(0x27,20,4);  //Crear el objeto lcd  dirección  0x27 y 20 columnas x 4 filas

const int DOUT_1=A0;   //Declaracion pines bascula 1    
const int CLK_1=A1;    //Declaracion pin CLK bascula 1

const int DOUT_2=A2;   //Declaracion pines bascula 2
const int CLK_2=A3;    //Declaracion pin CLK bascula 2

const int DOUT_3=A4;   //Declaracion pines bascula 3
const int CLK_3=A5;    //Declaracion pin CLK bascula 3

const int DOUT_4=22;   //Declaracion pines bascula 4     
const int CLK_4=23;    //Declaracion pin CLK bascula 4

const int DOUT_5=A8;   //Declaracion pines bascula 5 
const int CLK_5=A9;    //Declaracion pin CLK bascula 5

const int DOUT_6=A10;   //Declaracion pines bascula 6 
const int CLK_6=A11;    //Declaracion pin CLK bascula 6

const int DOUT_7=A12;   //Declaracion pines bascula 7 
const int CLK_7=A13;    //Declaracion pin CLK bascula 7

const int DOUT_8=A14;   //Declaracion pines bascula 8 
const int CLK_8=A15;    //Declaracion pin CLK bascula 8


int sw1_pin =2;     //Declaración n pin interruptor 1
int sw2_pin =3;     //Declaración n pin interruptor 2
int sw3_pin =4;     //Declaración n pin interruptor 3
int sw4_pin =5;     //Declaración n pin interruptor 4
int sw5_pin =6;     //Declaración n pin interruptor 5
int sw6_pin =7;     //Declaración n pin interruptor 6
int sw7_pin =8;     //Declaración n pin interruptor 7
int sw8_pin =9;     //Declaración n pin interruptor 8

int rst_pin =12;     //Declaración n pin 8 reset min/max

int w1;              //Declaracion variable peso1
int w2;              //Declaracion variable peso2
int w3;              //Declaracion variable peso3
int w4;              //Declaracion variable peso4
int w5;              //Declaracion variable peso5
int w6;              //Declaracion variable peso6
int w7;              //Declaracion variable peso7
int w8;              //Declaracion variable peso8

char w1_fixed[4];    //Declaración para mostrar peso con longitud fija
char w2_fixed[4];    //Declaración para mostrar peso con longitud fija
char w3_fixed[4];    //Declaración para mostrar peso con longitud fija
char w4_fixed[4];    //Declaración para mostrar peso con longitud fija
char w5_fixed[4];    //Declaración para mostrar peso con longitud fija
char w6_fixed[4];    //Declaración para mostrar peso con longitud fija
char w7_fixed[4];    //Declaración para mostrar peso con longitud fija
char w8_fixed[4];    //Declaración para mostrar peso con longitud fija

const float scale[9] = {0, 300.3,  297.3, -328.6, -325.6, 333.2, -333.9, -329.9, -333.58}; 

//========================================================

void setup() {

 pinMode(sw1_pin, INPUT_PULLUP);   //Declaración pin interruptor y tipo
 pinMode(sw2_pin, INPUT_PULLUP);   //Declaración pin interruptor y tipo
 pinMode(sw3_pin, INPUT_PULLUP);   //Declaración pin interruptor y tipo
 pinMode(sw4_pin, INPUT_PULLUP);   //Declaración pin interruptor y tipo
 pinMode(sw5_pin, INPUT_PULLUP);   //Declaración pin interruptor y tipo
 pinMode(sw6_pin, INPUT_PULLUP);   //Declaración pin interruptor y tipo
 pinMode(sw7_pin, INPUT_PULLUP);   //Declaración pin interruptor y tipo
 pinMode(sw8_pin, INPUT_PULLUP);   //Declaración pin interruptor y tipo
 
 pinMode(rst_pin, INPUT_PULLUP);   //Declaración pin y tipo
  
 lcd.init();         //Inicializar el LCD
 lcd.clear();        //Borra pantall y situa cursor (0.0)
 lcd.backlight();    //Encender luz LCD
   
 dht.begin();       //inicializacion de sensor DHT11
  
 bascula1.begin(DOUT_1, CLK_1);  //Iniciar sensor 1
 bascula2.begin(DOUT_2, CLK_2);  //Iniciar sensor 2
 bascula3.begin(DOUT_3, CLK_3);  //Iniciar sensor 3
 bascula4.begin(DOUT_4, CLK_4);  //Iniciar sensor 4
 bascula5.begin(DOUT_5, CLK_5);  //Iniciar sensor 5
 bascula6.begin(DOUT_6, CLK_6);  //Iniciar sensor 6
 bascula7.begin(DOUT_7, CLK_7);  //Iniciar sensor 7
 bascula8.begin(DOUT_8, CLK_8);  //Iniciar sensor 8
  
  lcd.setCursor(0,0);
  lcd.print("**Inicializando...**");
  
  bascula1.set_scale(scale[1]); //Escala sensor 1
  bascula2.set_scale(scale[2]); //Escala sensor 2
  bascula3.set_scale(scale[3]); //Escala sensor 3
  bascula4.set_scale(scale[4]); //Escala sensor 4
  bascula5.set_scale(scale[5]); //Escala sensor 5
  bascula6.set_scale(scale[6]); //Escala sensor 6
  bascula7.set_scale(scale[7]); //Escala sensor 7
  bascula8.set_scale(scale[8]); //Escala sensor 8
  
  bascula1.tare();  //Tara sensor 1
  bascula2.tare();  //Tara sensor 2
  bascula3.tare();  //Tara sensor 3
  bascula4.tare();  //Tara sensor 4
  bascula5.tare();  //Tara sensor 5
  bascula6.tare();  //Tara sensor 6
  bascula7.tare();  //Tara sensor 7
  bascula8.tare();  //Tara sensor 8
  
  delay(1000);
  lcd.setCursor(0,1);
  lcd.print("Listo para pesar");
  delay(1000);
  lcd.clear();

//*************MODBUS************//
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("Ethernet Modbus TCP Example");

  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);

  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
    delay(100);
  }

  // start the server
  ethServer.begin();
  
  // start the Modbus TCP server
  if (!modbusTCPServer.begin()) {
    Serial.println("Failed to start Modbus TCP Server!");
    while (1);
  }

 // configure input registers at address 0x00 // int configureInputRegisters(int startAddress, int nb);
 Holdresult = modbusTCPServer.configureHoldingRegisters(0x01, nreg); 

  Serial.print("Holding register initialization Result= ");
  Serial.print(Holdresult);
  Serial.print("\n");
  Serial.print("Modbus server address:");
  Serial.println(Ethernet.localIP());

  // Filling input registers
  for(uint16_t i = 0; i < nreg; i++)
  {
    hold = modbusTCPServer.holdingRegisterWrite((0x00 + i),(i + 1));
    Serial.println(hold, DEC); 
  }
  Serial.println("End of Setup");

}

void LecturaPes() {
  lcd.setCursor(0,0);
  lcd.print("P1: ");
  lcd.setCursor(11,0);
  lcd.print("P2: ");
  lcd.setCursor(0,1);
  lcd.print("P3: ");
  lcd.setCursor(11,1);
  lcd.print("P4: ");
  lcd.setCursor(0,2);
  lcd.print("P5: ");
  lcd.setCursor(11,2);
  lcd.print("P6: ");
  lcd.setCursor(0,3);
  lcd.print("P7: ");
  lcd.setCursor(11,3);
  lcd.print("P8: ");
  lcd.setCursor(4,0);
  w1=bascula1.get_units(16);  //Vact - Tara / Escala. "n" es promedio lecturas. Si se incluye ",n2"-> n2 num decimales si no es entero
  sprintf (w1_fixed, "%4d",w1); // Da formato al dato, en este caso longitud 4 digitos sin signo.
  lcd.print(w1_fixed);
  lcd.setCursor(15,0);
  w2=bascula2.get_units(16);  //Vact - Tara / Escala. "n" es promedio lecturas. Si se incluye ",n2"-> n2 num decimales si no es entero
  sprintf (w2_fixed, "%4d",w2); // Da formato al dato, en este caso longitud 4 digitos sin signo.
  lcd.print(w2_fixed);
  lcd.setCursor(4,1);
  w3=bascula3.get_units(16);  //Vact - Tara / Escala. "n" es promedio lecturas. Si se incluye ",n2"-> n2 num decimales si no es entero
  sprintf (w3_fixed, "%4d",w3); // Da formato al dato, en este caso longitud 4 digitos sin signo.
  lcd.print(w3_fixed);
  lcd.setCursor(15,1);
  w4=bascula4.get_units(16);  //Vact - Tara / Escala. "n" es promedio lecturas. Si se incluye ",n2"-> n2 num decimales si no es entero
  sprintf (w4_fixed, "%4d",w4); // Da formato al dato, en este caso longitud 4 digitos sin signo.
  lcd.print(w4_fixed);
  lcd.setCursor(4,2);
  w5=bascula5.get_units(16);  //Vact - Tara / Escala. "n" es promedio lecturas. Si se incluye ",n2"-> n2 num decimales si no es entero
  sprintf (w5_fixed, "%4d",w5); // Da formato al dato, en este caso longitud 4 digitos sin signo.
  lcd.print(w5_fixed);
  lcd.setCursor(15,2);
  w6=bascula6.get_units(16);  //Vact - Tara / Escala. "n" es promedio lecturas. Si se incluye ",n2"-> n2 num decimales si no es entero
  sprintf (w6_fixed, "%4d",w6); // Da formato al dato, en este caso longitud 4 digitos sin signo.
  lcd.print(w6_fixed);
  lcd.setCursor(4,3);
  w7=bascula7.get_units(16);  //Vact - Tara / Escala. "n" es promedio lecturas. Si se incluye ",n2"-> n2 num decimales si no es entero
  sprintf (w7_fixed, "%4d",w7); // Da formato al dato, en este caso longitud 4 digitos sin signo.
  lcd.print(w7_fixed);
  lcd.setCursor(15,3);
  w8=bascula8.get_units(16);  //Vact - Tara / Escala. "n" es promedio lecturas. Si se incluye ",n2"-> n2 num decimales si no es entero
  sprintf (w8_fixed, "%4d",w8); // Da formato al dato, en este caso longitud 4 digitos sin signo.
  lcd.print(w8_fixed);
  
}

void loop() {

LecturaPes();

  Temp = dht.readTemperature();  // lectura valor temp
  Hum = dht.readHumidity();   // lectura valor humitat
 // Serial.print("Temperatura: ");  
 // Serial.print(Temp);
 // Serial.print(" Humitat: ");
 // Serial.println(Hum);
 // delay(500);

  // listen for incoming clients
  EthernetClient client = ethServer.available();
  
  if (client) {
    LecturaPes();
    // a new client connected
    Serial.println("new client");

    // let the Modbus TCP accept the connection 
    modbusTCPServer.accept(client);
    while (client.connected()) {
      // poll for Modbus TCP requests, while client connected
      modbusTCPServer.poll();
     // LecturaPes();
   }

    Serial.println("client disconnected");
}

}

Thank you very much for your help!

If there is little data I believe it might be interesting to use MQTT.

https://www.baldengineer.com/mqtt-tutorial.html

Thank you very much for the help, it is very interesting and I will try it.
My idea is to send aprox 20 weight tags for each Mega2560. I supose aren't too much data.

If someone can help me with Modbus TCP don't hesitate to do it, it would be a great help to work in parallel with both options.

Thanks!

I found these tips:

Modbus has lots of varients. But if we will compare one Modbus varient with MQTT, it should be Modbus TCP.

*MQTT is a newer protocol than Modbus and developed as Internet of Things(IoT) in mind. Some old devices doesn't support MQTT but just support Modbus TCP.

*With MQTT, you can send data to multiparts by message broker, but Modbus TCP just send data to the its server.

*MQTT is more secure than the Modbus TCP protocol.

*MQTT is supported by many software languages and main cloud service providers such as Amazon AWS, Microsoft Azure, IBM Bluemix and Google Cloud.

*As a result, if your devices and system support MQTT, use it instead of Modbus TCP.

Source: Difference between MQTT and MODBUS protocol? - Stack Overflow

I found this library too, there are other libraries referenced in the article:

Hope it helps, have fun!

The MCU's can run MQTT Client and the Raspberry Pi can run MQTT Broker. The clients can send and receive info from the MQTT Broker. On the RaspberryPi use Node-Red or write your own program to handle communication events.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.