Reading two RS485 energy meters

Hi everyone,

I am using the MKR RS485 shield to read values like voltage and power from an energy meter. I have two scenarios, in first scenario, I have a single meter and I can read the values successfully. In the second scenario, I have two identical meters. I have shown the way I want to connect them in the attached image. Right now, I have only meter, so I don't know if I would be able to read the two meters the way I have shown and explained below.

For single meter, I use the code as that works correctly:

#include <ArduinoRS485.h>
#include <ArduinoModbus.h>

void setup() {

  Serial.begin(115200);
  while (!Serial) {
    //
  }
  if (!ModbusRTUClient.begin(9600)) {
    Serial.println("Failed to start Modbus RTU Client!");
    while (1);
  } else {
    Serial.println("Connected");
  }
}

void loop() {

  float volt = readVoltage();
  Serial.print("Voltage is: ");
  Serial.print(volt, 1);
  Serial.println(" V");
  delay(500);
  
  float L1 = readPower();
  Serial.print("Power is: ");
  Serial.print(L1, 2); 
  Serial.println(" W");
  delay(500);
}

float readVoltage() {
  float volt = 0.;
  if (!ModbusRTUClient.requestFrom(0x01, HOLDING_REGISTERS, 0x00F3, 1)) {           // make the call to the register
    Serial.print("failed to read voltage! ");
    Serial.println(ModbusRTUClient.lastError());                                    // error handler
  } else {
    uint16_t word1 = ModbusRTUClient.read();                                        // read data from the buffer
    volt = word1 / 10.0;
  }
  return volt;
}

float readPower() {
  float watt = 0;
  if (!ModbusRTUClient.requestFrom(0x01, HOLDING_REGISTERS, 0x00FD, 2)) {           // make the call to the register
    Serial.print("failed to read power! ");
    Serial.println(ModbusRTUClient.lastError());                                    // error handler
  } else {
    int16_t word1 = ModbusRTUClient.read();                                         // read data from the buffer
    int16_t word2 = ModbusRTUClient.read();
    int32_t WATT = word1 << 16 | word2;                                             // bit math
    watt = WATT * 1.2;
  }
  return watt;
}

For two meters, will the code work like that?

#include <ArduinoRS485.h>
#include <ArduinoModbus.h>

void setup() {

  Serial.begin(115200);
  while (!Serial) {
    //
  }
  if (!ModbusRTUClient.begin(9600)) {
    Serial.println("Failed to start Modbus RTU Client!");
    while (1);
  } else {
    Serial.println("Connected");
  }
}

void loop() {

// Meter 1
 
 float volt = readVoltage();
  Serial.print("Meter 1 Voltage is: ");
  Serial.print(volt, 1);
  Serial.println(" V");
  delay(500);
  
  float L1 = readPower();
  Serial.print("Meter 1 Power is: ");
  Serial.print(L1, 2); 
  Serial.println(" W");
  delay(500);

// Meter 2 

  float V1 = read_Voltage();
  Serial.print("Meter 2 Voltage is: ");
  Serial.print(V1, 1);
  Serial.println(" V");
  delay(500);

  float P1 = readPower_P1();
  Serial.print("Meter 2 Power is: ");
  Serial.print(P1, 2);
  Serial.println(" W");
  delay(500);
}

float readVoltage() {
  float volt = 0.;
  if (!ModbusRTUClient.requestFrom(0x01, HOLDING_REGISTERS, 0x00F3, 1)) {           // make the call to the register
    Serial.print("failed to read voltage! ");
    Serial.println(ModbusRTUClient.lastError());                                    // error handler
  } else {
    uint16_t word1 = ModbusRTUClient.read();                                        // read data from the buffer
    volt = word1 / 10.0;
  }
  return volt;
}

float readPower() {
  float watt = 0;
  if (!ModbusRTUClient.requestFrom(0x01, HOLDING_REGISTERS, 0x00FD, 2)) {           // make the call to the register
    Serial.print("failed to read power! ");
    Serial.println(ModbusRTUClient.lastError());                                    // error handler
  } else {
    int16_t word1 = ModbusRTUClient.read();                                         // read data from the buffer
    int16_t word2 = ModbusRTUClient.read();
    int32_t WATT = word1 << 16 | word2;                                             // bit math
    watt = WATT * 1.2;
  }
  return watt;
}

float read_Voltage() {
  float volt = 0.;
  if (!ModbusRTUClient.requestFrom(0x02, HOLDING_REGISTERS, 0x00F3, 1)) {           // make the call to the register
    Serial.print("failed to read voltage! ");
    Serial.println(ModbusRTUClient.lastError());                                    // error handler
  } else {
    uint16_t word1 = ModbusRTUClient.read();                                        // read data from the buffer
    volt = word1 / 10.0;
  }
  return volt;
}

float readPower_P1() {
  float watt = 0;
  if (!ModbusRTUClient.requestFrom(0x02, HOLDING_REGISTERS, 0x00FD, 2)) {           // make the call to the register
    Serial.print("failed to read power! ");
    Serial.println(ModbusRTUClient.lastError());                                    // error handler
  } else {
    int16_t word1 = ModbusRTUClient.read();                                         // read data from the buffer
    int16_t word2 = ModbusRTUClient.read();
    int32_t WATT = word1 << 16 | word2;                                             // bit math
    watt = WATT * 1.2;
  }
  return watt;
}

Will it work if I just change the address of second meter to 0x02?

I just test made a test where I connected one energy meter and an another device having RS485 port. I connected the MKR shield to the other device first and from there I extended the connection my energy meter. I don't read anything from the first device. However, I tried to read the energy meter using the address 0x02 but I got this error:
failed to read voltage! Response not from requested slave
Meter 1 voltage is: 0.0 V
failed to read power! Response not from requested slave
Meter 1 Power is: 0.00 W

There is one difference between the energy meter and the other device I have. The energy meter has A, B, and GND connection for communication while the other device has only A and B. So, I connected the Y to A, Z to B on the device from the shield but didn't connect the GND. Then I gave the connection from other device to energy meter as: A to A and B to B and GND not connected.

So, I want to know if my connections are correct and if the code would work, or do I need to make some changes on the code and connection?

Looking forward to your help. Thank you very much.

I guess when you wrote the title of the thread about "simultaneous", you were not really think about what that means. You have single processor and it cannot do anything simultaneously with something else. With TWO completely separated serial communication streams, you can interleave transmission and reception that seem to be simultaneous because they are interrupt driven.
But more to your project. You are reading registers of power meters that are never updates instantaneously with the power values at that particular instant. So why not proceed with your second schematic connection and code accordingly?
If you really do need to separate the readings, you need to completely duplicate the first first schematic for the second meter and duplicate the software parts for the second serial port of your Arduino. And then the readings will be interleaved, not simultaneous.
You will need an Arduino board with more than one hardware serial connection.

Paul

My bad Paul, the word simultaneously was totally wrong here. Hence, I erased it.

Yes, of course, I would like to go with the second scenario that I have drawn. I will read meter 1 and then the values from meter 2. Meter 1 will give me the power values of the 3 phase grid, while meter 2 will give me the power values from PV and the wind. The thing is both the meters are identical with the identical protocol and I will use the same set of commands. What I don't understand here is, how would I read the two meters differently? How can I assign address 1 to one meter and address 2 to the second meter? By default, the meter has address 1. I also read the meter address from the protocol via Arduino and it is 1. Attached is the protocol of the meter page 17.
167 ACR10RH外置互感器(三相+谐波)v1.5-英文.pdf (695.1 KB)

Para 6.2.6.2 "Communication Setting" of the pdf you provided appears to detail how to change the device address.

Yes, in particular (just copied that for here):

After entering the user setting interface,press the upper and downer keys to select the communication settings,and press the enter key to enter the communication settings interface.Press the itens that need to be changed under the communication setting interface to make it in the anti-white state press the key to change the communication address(1-247),the communication baud rate (1200bps,2400bps,4800bps,9600bps,19200bps,48400bps),the check mode(no check,odd check even check,2bits),645 protocol address.

HTH

a7

It worked. Thank you very much @markd833, @alto777 and @Paul_KD7HB. Have a great day.

Hi, i've same project like your. But i'm new at arduino. Can you help me pls.

I've to read data of distance from level meter sensor device. For this must to request command: 01 03 00 01 00 01 D5 CA
Protocol device: RS485 Protocol.pdf (128.3 КБ)

How can i request this command line???