[SOLVED]Trouble with modbus by smarmengol

Hello everyone, I'm faced with a problem, there is a master on arduino mega2560 and a few slaves on arduino nano, all are connected in parallel and at the beginning and at the end of the line the resistors are 120m, when working in mode 1 master -1 slave everything is fine, it is necessary to connect the second slave not both work, which is the problem with the whole head broke, when working on the library easytransfer everything was fine, switched to modbus and there were problems, now I use this GitHub - smarmengol/Modbus-Master-Slave-for-Arduino: Modbus Master-Slave library for Arduino
master

/**
 *  Modbus master example 1:
 *  The purpose of this example is to query an array of data
 *  from an external Modbus slave device. 
 *  The link media can be USB or RS232.
 *
 *  Recommended Modbus slave: 
 *  diagslave http://www.modbusdriver.com/diagslave.html
 *
 *  In a Linux box, run 
 *  "./diagslave /dev/ttyUSB0 -b 19200 -d 8 -s 1 -p none -m rtu -a 1"
 * This is:
 * serial port /dev/ttyUSB0 at 19200 baud 8N1
 * RTU mode and address @1
 */

#include <ModbusRtu.h>

// data array for modbus network sharing
uint16_t au16data[16];
uint8_t u8state;

/**
 *  Modbus object declaration
 *  u8id : node id = 0 for master, = 1..247 for slave
 *  u8serno : serial port (use 0 for Serial)
 *  u8txenpin : 0 for RS-232 and USB-FTDI 
 *               or any pin number > 1 for RS-485
 */
Modbus master(0,1,2); // this is master and RS-232 or USB-FTDI

/**
 * This is an structe which contains a query to an slave device
 */
modbus_t telegram;

unsigned long u32wait;

void setup() {
  Serial.begin(9600);
  master.begin( 9600 ); // baud-rate at 19200
  master.setTimeOut( 2000 ); // if there is no answer in 2000 ms, roll over
  u32wait = millis() + 1000;
  u8state = 0; 
}

void loop() {
  switch( u8state ) {
  case 0: 
    if (millis() > u32wait) u8state++; // wait state
    break;
  case 1: 
    telegram.u8id = 2; // slave address
    telegram.u8fct = 3; // function code (this one is registers read)
    telegram.u16RegAdd = 1; // start address in slave
    telegram.u16CoilsNo = 4; // number of elements (coils or registers) to read
    telegram.au16reg = au16data; // pointer to a memory array in the Arduino

    master.query( telegram ); // send query (only once)
    u8state++;
    break;
  case 2:
    master.poll(); // check incoming messages
    if (master.getState() == COM_IDLE) {
      u8state = 0;
      u32wait = millis() + 100; 
    }
    break;
  }
  Serial.println("");
  Serial.print("Value = ");
  Serial.print(au16data[0]);
  

}

Slaves

/**
 *  Modbus slave example 1:
 *  The purpose of this example is to link a data array
 *  from the Arduino to an external device.
 *
 *  Recommended Modbus Master: QModbus
 *  http://qmodbus.sourceforge.net/
 */

#include <ModbusRtu.h>

// data array for modbus network sharing
uint16_t au16data[16] = {
  3, 1415, 9265, 4, 2, 7182, 28182, 8, 0, 0, 0, 0, 0, 0, 1, -1 };

/**
 *  Modbus object declaration
 *  u8id : node id = 0 for master, = 1..247 for slave
 *  u8serno : serial port (use 0 for Serial)
 *  u8txenpin : 0 for RS-232 and USB-FTDI 
 *               or any pin number > 1 for RS-485
 */
Modbus slave(2,0,10); // this is slave @1 and RS-232 or USB-FTDI

void setup() {
  slave.begin( 9600 ); // baud-rate at 19200
}

void loop() {
  slave.poll( au16data, 16 );
}

Yes, I know that the master code is designed for 1 slave, but the problem is that with 2 slaves it stops responding even 1 slave.
a similar code with a cycle under a few slave is too cumbersome because of another code. the essence remains the same. I give an individual id for slaves)

sorry worked wrong 1 slave under arduino nano, slave on eliwell ttl works, together with arduino everything is polled, but more than 1 nano does not work

Suppchik:
sorry worked wrong 1 slave under arduino nano, slave on eliwell ttl works, together with arduino everything is polled, but more than 1 nano does not work

I'm not sure what this is saying.

The master is a MEGA using serial 1 and pin 2 for the TX Enable. The one slave you posted is address 2 using serial 0 and TX enable pin is 10.

What is the code for the second slave?

Why do you have a negative value in your array of unsigned integers?

Suppchik:
uint16_t au16data[16] = { 3, 1415, 9265, 4, 2, 7182, 28182, 8, 0, 0, 0, 0, 0, 0, 1, -1 };

Also be aware the use of millis() in the smarmengol library and examples is incorrect. It will work in short term testing, but not for runtime in the long term.

adwsystems:
I'm not sure what this is saying.

The master is a MEGA using serial 1 and pin 2 for the TX Enable. The one slave you posted is address 2 using serial 0 and TX enable pin is 10.

What is the code for the second slave?

Why do you have a negative value in your array of unsigned integers?

Also be aware the use of millis() in the smarmengol library and examples is incorrect. It will work in short term testing, but not for runtime in the long term.

the author decided to solve the problem with millis, the second sketch is similar to the first one, with the exception of id and txen, negative numbers are normally transmitted, they just go from the other side) here is the sketch of the second slave

/**
 *  Modbus slave example 1:
 *  The purpose of this example is to link a data array
 *  from the Arduino to an external device.
 *
 *  Recommended Modbus Master: QModbus
 *  http://qmodbus.sourceforge.net/
 */

#include <ModbusRtu.h>

// data array for modbus network sharing
uint16_t au16data[16] = {
  3, 1415, 9265, 4, 2, 7182, 28182, 8, 0, 0, 0, 0, 0, 0, 1, -1 };

/**
 *  Modbus object declaration
 *  u8id : node id = 0 for master, = 1..247 for slave
 *  u8serno : serial port (use 0 for Serial)
 *  u8txenpin : 0 for RS-232 and USB-FTDI 
 *               or any pin number > 1 for RS-485
 */
Modbus slave(1,0,2); // this is slave @1 and RS-232 or USB-FTDI

void setup() {
  slave.begin( 9600 ); // baud-rate at 19200
}

void loop() {
  slave.poll( au16data, 16 );
}

PS At the same time only one slave arduino nano can work, and any industrial equipment on a modbus, two slave arduino nano can not work simultaneously

The author did not solve a problem with millis(), he created a problem using millis() incorrectly.

I have one Mega and 4 Nanos running just fine using a corrected version of the smarmengol library, so I know it will work.

adwsystems:
The author did not solve a problem with millis(), he created a problem using millis() incorrectly.

I have one Mega and 4 Nanos running just fine using a corrected version of the smarmengol library, so I know it will work.

you can share the patched library

The correction is to the use of millis() in the examples and in the library. There is a tutorial available on the correct usage of millis().

There are to statements throughout the smarmengol library and examples:

millis() > u32wait

and

u32wait = millis() + 100;

The correct way would be:

u32wait - millis() > 100

and

u32wait = millis();

But that is not your problem during troubleshooting.

Let's focus on why you can't get two nanos and one MEGA working. Have you tried connecting just those three devices (with no [unspecified] industrial equipment) connected?

adwsystems:
The correction is to the use of millis() in the examples and in the library. There is a tutorial available on the correct usage of millis().

There are to statements throughout the smarmengol library and examples:

millis() > u32wait

and

u32wait = millis() + 100;

The correct way would be:

u32wait - millis() > 100

and

u32wait = millis();

But that is not your problem during troubleshooting.

Let's focus on why you can't get two nanos and one MEGA working. Have you tried connecting just those three devices (with no [unspecified] industrial equipment) connected?

tried four nano, now I try with 2 (problem one) without equipment

now it's all collected on the knee) the second nano can not see it aside) works one nano and the controller eliwell)


What code are you running? The output on the monitor does not correspond to any of the programs above.

What does "Request slave = 10" mean? Slave with address 10? Where did address 10 come from, None of the programs posted above say anything about a slave at address 10.

Do not pay attention to this code, I just hooked https://www.eliwell.com/download/downloader.php?cat=prd_docs&id=350[\url], to test polls of several slaves, I'm looking for why not working 2 nano and more with another sketches

I know of at least two other people here that have successfully used the smarmengol library with three or more devices. Specifically, I have four nano slaves and one mega master running using the smarmengol library.

Whatever the reason is that you cannot get two nanos and a mega to work is specific to either your code or to your hardware. To answer your question, you will need to post your code.

Edit: You will also need to provide a common ground between all of the MAX485 boards.

part one of code

#include <SPI.h>
#include "EmonLib.h"  // библиотека для работы I²C
#include <Wire.h>
#include <avr/wdt.h>
#include <Ethernet.h>
#include "TroykaRTC.h"
#include <ModbusRtu.h>

EnergyMonitor emon[3];
RTC clock;

#define TXRX 43 
#define LEN_TIME 12
#define LEN_DATE 12
#define LEN_DOW 12 
char time[LEN_TIME];
char date[LEN_DATE];
char weekDay[LEN_DOW];
char    *month[12] = {"jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"};

byte mac[] = { 0x90, 0xA2, 0xDA, 0x05, 0x59, 0x67 };  
EthernetClient client;
IPAddress ip(192, 168, 56, 110);
byte dNs[]={192, 168, 254, 181};
byte gAtE[]={192, 168, 56, 199};


// data array for modbus network sharing
uint16_t au16data[64];
unsigned long curtime=0,timer2=0,timer1=0,u32wait;
String dataString = "",TempString = "",WaterString ="";
uint16_t timenext;
uint8_t u8state,u8query,timeready=0;

Modbus master(0,1,2);

modbus_t telegram[4];
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{  
  Serial.begin(9600);
  Serial.println("Enableing");
  wdt_enable(WDTO_8S);
 // if (Ethernet.begin(mac) == 0) {
 //   Serial.println("Failed to configure Ethernet using DHCP"); 
 //   Ethernet.begin(mac, ip, dNs, gAtE); 
 // }
  delay(500);

  telegram[0].u8id = 1; // slave address for waterlog
  telegram[0].u8fct = 3; // function code (this one is registers read)
  telegram[0].u16RegAdd = 1; // start address in slave
  telegram[0].u16CoilsNo = 8; // number of elements (coils or registers) to read
  telegram[0].au16reg = au16data; // pointer to a memory array in the Arduino

  telegram[1].u8id = 2; // slave address for thermolog KITchen
  telegram[1].u8fct = 3; // function code (this one is registers read)
  telegram[1].u16RegAdd = 3; // start address in slave
  telegram[1].u16CoilsNo = 5; // number of elements (coils or registers) to read
  telegram[1].au16reg = au16data+10; // pointer to a memory array in the Arduino

  telegram[2].u8id = 3; // slave address for thermolog hall
  telegram[2].u8fct = 3; // function code (this one is registers read)
  telegram[2].u16RegAdd = 0; // start address in slave
  telegram[2].u16CoilsNo = 5; // number of elements (coils or registers) to read
  telegram[2].au16reg = au16data+15; // pointer to a memory array in the Arduino

  telegram[3].u8id = 10; // slave address for refrigirators
  telegram[3].u8fct = 3; // function code (this one is registers read)
  telegram[3].u16RegAdd = 297; // start address in slave
  telegram[3].u16CoilsNo = 4 ; // number of elements (coils or registers) to read
  telegram[3].au16reg = au16data+20; // pointer to a memory array in the Arduino
  wdt_reset();


  
  master.begin( 9600 ); // baud-rate at 19200
  Serial.println("Master on");
  master.setTimeOut( 4000 ); // if there is no answer in 5000 ms, roll over
  u32wait = millis() + 1000;
  u8state = u8query = 0; 
  
  clock.begin(); 
  clock.set(__TIMESTAMP__);
  wdt_reset();

  digitalWrite(10,HIGH);


  emon[0].voltage(0, 142  , 1.0);   // Voltage: pin, calib, phasecal, line phase.
  emon[0].current(3, 180);             // Current: pin, calib.

  emon[1].voltage(1, 143, 1.0);   // Voltage: pin, calib, phasecal, line phase.
  emon[1].current(4, 170);             // Current: pin, calib.

  emon[2].voltage(2, 140, 1.0);   // Voltage: pin, calib, phasecal, line phase.
  emon[2].current(5, 200);             // Current: pin, calib.
    // создаём файл для записи

    clock.read();
 curtime=  clock.getUnixTime();
 timer1=curtime;
 timer2=curtime;
 wdt_reset();
 Serial.println("Setting ok!");
}

The modules are also powered by a twisted pair, and they have a common ground

part two

int convertnegative(uint16_t value)
{
  if(value>65000)
  return value-65536;
  }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void send_data(String data,String ToPHP)
{
   wdt_reset();
 //  if (client.connected()) { 
 //   client.stop();  // DISCONNECT FROM THE SERVER
 // }
  //  if (client.connect("192.168.254.135",80)) { // REPLACE WITH YOUR SERVER ADDRESS
   // client.println("POST /add.php HTTP/1.1"); //
//    client.println(ToPHP);
 //   client.println("Host: 192.168.254.135"); // SERVER ADDRESS HERE TOO
 //   client.println("Content-Type: application/x-www-form-urlencoded"); 
  //  client.print("Content-Length: "); 
 //   client.println(data.length()); 
 //   client.println(); 
 //   client.print(data);
    Serial.print(data);
    Serial.println("OK");


 // } 
 // else Serial.println(data);


 // if (client.connected()) { 
 //   client.stop();  // DISCONNECT FROM THE SERVER
  //} 
}
void loop()
{
   wdt_reset();

int IRMS[3];
int voltage[3];
clock.read();
  // сохраняем текущее время, дату и день недели в переменные
  clock.getTimeStamp(time, date, weekDay);
        
if(timeready<32)
timeready++;
for(int i=0;i<3;i++)
  {

    emon[i].calcVI(20,100);    // 2 h.c. for buffering + 14 h.c. for measuring
    IRMS[i]=emon[i].Irms;             //extract Vrms into Variable
    voltage[i]= emon[i].Vrms;
  }


if(timeready>3)
      {
         switch( u8state ) {
  case 0: 
    if (millis() > u32wait) u8state++; // wait state
    break;
  case 1: 
    master.query( telegram[u8query] ); // send query (only once)
    u8state++;
    Serial.println("");
    Serial.print("Query slave number ");
    Serial.print(telegram[u8query].u8id);
  u8query++;
  if (u8query > 4) u8query = 0;
    break;
  case 2:
  Serial.println("check incoming");
    master.poll(); // check incoming messages
    if (master.getState() == COM_IDLE) {
      u8state = 0;
      u32wait = millis() + 1000; 
    }
    break;
  }
Serial.println(" ");
Serial.print("Request slave = ");
Serial.print(telegram[u8query].u8id);
Serial.println("");
Serial.print("Status master is = ");
Serial.print(master.getState());
Serial.print(" last error = ");
Serial.print(master.getLastError());
Serial.println("");
Serial.print("value 1 = ");
Serial.println(au16data[0]);
Serial.print("value 2 = ");
Serial.println(au16data[10]);

Serial.print("value ref = ");
Serial.println(au16data[20]);
      
            String energy = "id=9&volt1=" + String(voltage[0]) +"&volt2=" + String(voltage[1])+"&volt3=" + String(voltage[2])+"&irms1=" + String(abs(IRMS[0]))+"&irms2=" + String(abs(IRMS[1]))+"&irms3=" + String(abs(IRMS[2])); 
              send_data(energy,"POST /receive/add.php HTTP/1.1"); 
  //            for(int kj=0;kj<64;kj++)   
  //        {
  //          Serial.print("Num= ");
  //          Serial.print(kj);
   //         Serial.print(" value= ");
  //          Serial.println(au16data[kj]);
    //      }
       if(curtime>timer1+299)
        {
           String WaterString="id=9&resH="+String(au16data[0])+"&resC="+String(au16data[1])+"&tempcold="+String(au16data[3])+"&temphot="+String(au16data[2]);
             send_data(WaterString,"POST /receive/addwater.php HTTP/1.1");
             timer1=clock.getUnixTime();
             wdt_reset();
        }
          
       if(curtime>timer2+359)   
        {
          String refrigirators="id=9&i235=" +String(convertnegative(au16data[21]))+"&o235="+String(convertnegative(au16data[38]));
          refrigirators+="&i237="+String(convertnegative(au16data[20]))+"&o237="+String(convertnegative(au16data[36]));
          refrigirators+="&i242="+String(convertnegative(au16data[35]))+"&o242="+String(convertnegative(au16data[28]));
          refrigirators+="&i234="+String(convertnegative(au16data[27]))+"&o234="+String(convertnegative(au16data[39]));
          refrigirators+="&i244="+String(convertnegative(au16data[24]))+"&o249="+String(convertnegative(au16data[30]));
          refrigirators+="&i245="+String(convertnegative(au16data[26]))+"&o245="+String(convertnegative(au16data[31]));
          refrigirators+="&o241="+String(convertnegative(au16data[32]))+"&o240="+String(convertnegative(au16data[34]));
          
          refrigirators+="&i247="+String(convertnegative(au16data[37]))+"&o247="+String(convertnegative(au16data[22]));//n3,5
          refrigirators+="&o250="+String(convertnegative(au16data[23]))+"&o246="+String(convertnegative(au16data[25]));
          /*
 
          */
          send_data(refrigirators,"POST /receive/addref.php HTTP/1.1");
          wdt_reset();
          timer2=clock.getUnixTime();
          String hall="id=9&temphall=" +String(au16data[15])+"&tempkitchen="+String(au16data[10]);
          send_data(hall,"POST /receive/addhall.php HTTP/1.1");
          
         
        }
       
        
              ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      }   

 wdt_reset();
 curtime=  clock.getUnixTime();
}
if(timeready<32)
timeready++;

This line confused me for a while. I did not notice the increment was condition. I always you {} for all if statements if only a single line. Just a suggestion, not a problem.

Now that I see the master code, that helps. Unfortunately I don't see anything obvious and cannot correlate to the slave code. Will you be posting those shortly?

It appears by your drawing you only have termination resistors at the ends. Good. Do you have any if idle line resistors installed?

Have you dropped back and loaded the advanced examples on to the nanos and Mega? We need to separate library troubles from hardware problems from problems in your program. Unfortunately this boils down to one equation (your setup) and three unknowns (see previous).

I think the problem is in the hardware, there was an experience with another mega2560 it did not work at all with the modbus, tomorrow I'll try the software serial library, I'll unsubscribe, and then the timeready condition was used so that when calibrating to the server the data was not sent, I would redo the millis)

Don't try software serial. It is not compatible with half-duplex RS-485 modules.

Drop back and test with the advanced modbus examples or another simple basic set of programs.

Hi

I am scanning about 10 nanos with modbus at 19200 and some at 115200. Found that it is critical to have about a 50ms inter transaction delay for all the nanos to settle. If it is not there then thay tend to go out of sync with the incomming data packet.

I am using the VansoftModbus slave library that I wrote based on the SimpleModbusSlaveV10 library.
The vansoft library supports Coil, Discreate, Register and Holding register commands and single coil and holding write commands.

There is also a modbus tester that can simulate a master or a slave. Use that to first sort out the individual bards before hooking them together.

Check out www,vansoft.co.za to download.

Regards

Louis

vansoft:
Hi

I am scanning about 10 nanos with modbus at 19200 and some at 115200. Found that it is critical to have about a 50ms inter transaction delay for all the nanos to settle. If it is not there then thay tend to go out of sync with the incomming data packet.

I am using the VansoftModbus slave library that I wrote based on the SimpleModbusSlaveV10 library.
The vansoft library supports Coil, Discreate, Register and Holding register commands and single coil and holding write commands.

There is also a modbus tester that can simulate a master or a slave. Use that to first sort out the individual bards before hooking them together.

Check out www,vansoft.co.za to download.

Regards

Louis

Not to drift off the OP, but I am very curious, are the slaves running at 19200 and 115200 on the same RS-485 network? If so, How do the slaves at 19200 understand the telegram transmitted at 115200 is not for them? How do the slaves at 115200 understand the telegram transmitted at 19200?

No they are on two different networks. I use a module from eBay that handles the 485 for about 1$, makes life so much easier.