Reading data from energy meter through modbus protocol

Hi All,

Im trying to read holding register values of Elmeasure LG1129 and BM5140 energy meter using Modbus protocol through Arduino. I used RS485 to TTL converter between Energy meter and Arduino Mega but I haven’t succeeded. Please help me

This is the board i used for RS485 communication:
https://robokits.co.in/control-boards/interface-boards/max485-ttl-to-rs485-converter-module?gclid=EAIaIQobChMIhMDH_d2J5gIVizUrCh2MKwVHEAQYAiABEgKyZvD_BwE

Typical circuit diagram connection:

IMG_20191127_115511%20(1)

Some reference Code I got from forum and burned the same in Arduino:

#include <SimpleModbusMaster.h>

#define baud 9600
#define timeout 1000
#define polling 2000 // the scan rate
#define retry_count 10


#define TxEnablePin 2

#define TOTAL_NO_OF_REGISTERS 31


enum
{
  PACKET1,
  PACKET2,
  

  TOTAL_NO_OF_PACKETS // leave this last entry
};

// Create an array of Packets to be configured
Packet packets[TOTAL_NO_OF_PACKETS];

// Masters register array
unsigned int regs[TOTAL_NO_OF_REGISTERS];

void setup()
{
  // Initialize each packet
  Serial.begin(9600);
Serial1.begin(9600);
  
  
  modbus_construct(&packets[PACKET1], 1, READ_HOLDING_REGISTERS, 40133, 2, 10); 
  modbus_construct(&packets[PACKET2], 1, READ_HOLDING_REGISTERS, 40135, 2, 12); 
  
  modbus_configure(&Serial1, baud, SERIAL_8E1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs);
}

void loop()
{
  modbus_update();

  int A, B, C, D, E, F, G, H, I, J, K, L, M, N, O;

  A = regs[10];
  B = regs[12];

  
  Serial.print("A = ");
  Serial.println(A);


  Serial.print("B = ");
  Serial.println(B);

  Serial.println("============================================");
  delay(1000);

  
  Serial.print("successful_requests: ");
  Serial.println(packets[PACKET1].successful_requests);
  Serial.println("                        || ");
  Serial.print("failed_requests: ");
  Serial.print(packets[PACKET1].failed_requests);
  Serial.println("     || ");
  Serial.print("exception_errors: ");
  Serial.print(packets[PACKET1].exception_errors);
  Serial.println("     || ");
  Serial.print("connection: ");
  Serial.print(packets[PACKET1].connection);
  Serial.println("           || ");
 delay(1000);
}

Also Please clarify me this line of code what does number 10 represents although we have register number starting from 0 to 30

modbus_construct(&packets[PACKET1], 1, READ_HOLDING_REGISTERS, 40133, 2, 10); 

Hi This is a forum for Particle and its products and we really can’t offer much guidance on Arduino products. Can I suggest you register with this forum (or similar)

https://forum.arduino.cc

3 Likes

(post withdrawn by author, will be automatically deleted in 24 hours unless flagged)

The code used in that post uses the ModbusMaster library which makes addressing individual devices straight forward.
If you look in post #51 in that thread you will find this

and with that the answer would be straight forward for any other slave ID.

However, since this is not an Arduino forum and hence has no affinity to the SimpleModbusMaster library you appear to be using it's beyond our scope to make it fit a library currently not Particle user seems to be using.

(post withdrawn by author, will be automatically deleted in 24 hours unless flagged)

If you want another meter (aka node) you’d also need two node objects (with an unique ID for each of them).
To keep the code changes minimal I’d do this

// ModbuusMaster node; // repalce with
ModbusMaster *actNode;
ModbusMaster node[2] = { ModbusMaster(Serial2, ID0), ModbusMaster(Serial2, ID1) }; 
...
void setup() {
  ...
  node[0].begin();
  node[1].begin();
  ...
}

Then replace all node.* calls with actNode->* and before requesting data from a specific node just set the pointer accordingly (e.g. actNode = &node[0]; or actNode = &node[1];).

While there is a lot more potential in streamlining your code above, this should get you unstuck.

(post withdrawn by author, will be automatically deleted in 24 hours unless flagged)

Hi @ScruffR, we use that library with ESP32 to read up to 4 slaves, I think the code can be compiled with Particle photon just require to edit the IO accordingly.
here is full example --> ModbusMaster Multiple slaves
here is the library --> SensorModbusMaster

(post withdrawn by author, will be automatically deleted in 24 hours unless flagged)

Actually no, not ModBus.
However, as said earlier

So NodeMCU is not our focus but your question is very specific to that board and has nothing to do with Particle whatsoever.

Hi @priya I am also trying to interface energy meter from selec model No. EM2M but I am unable to read the data from it I am getting error as follow

17:40:13.381 -> Reading register: 30021 regSize: 1 sizeof(data): 2 XMITDELAY: 3000
17:40:13.449 -> 
17:40:18.405 -> LT: Response timed out. Trying again. 
17:40:23.422 -> LT: Failed. Response timed out. Adjust the XMITDELAY and/or ku8MBResponseTimeout? 
17:40:28.463 -> LT: Failed. Response timed out. Adjust the XMITDELAY and/or ku8MBResponseTimeout? 

can you please help me out I am following the code that you have pasted I am using an Arduino Mega board

@priya Yes the code is working and even though you deleted your post I was still able to access them and if you are sharing knowledge its good.

You have tried to read the data from the Selec EM2M energy meter. please can you share me you code and circuit diagram, please .

@Lucky76654 I don’t have any access to my system I’ll share you the circuit and basic code tomorrow.

sir please share the circuit diagram and the code. because I trying with this meter for the past 10 days. please.

Sorry, @Lucky76654 forgot to share the code. I am sharing a basic code with you which is working with Arduino Mega and Uno. Please note it is a basic code from where you can get started. Also, the result which you will get will be HEX format Use this link to convert from hex to float. Also, you will need to reverse the hex to get the correct output.


#include <ModbusMaster.h>

/*!
  We're using a MAX485-compatible RS485 Transceiver.
  Rx/Tx is hooked up to the hardware serial port at 'Serial'.
  The Data Enable and Receiver Enable pins are hooked up as follows:
*/
#define MAX485_DE      13
#define MAX485_RE_NEG  12


#define DEBUGON 1

// Transmission delay between modbus calls
#define XMITDELAY 1000

// 0 for 0-based, 1 for 1-based numbering
#define BASED_NUMBERING 1

// instantiate ModbusMaster object
ModbusMaster node;

void preTransmission()
{
  digitalWrite(MAX485_RE_NEG, 1);
  digitalWrite(MAX485_DE, 1);
}

void postTransmission()
{
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);
}

void setup()
{
  pinMode(MAX485_RE_NEG, OUTPUT);
  pinMode(MAX485_DE, OUTPUT);
  // Init in receive mode
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);

  // Modbus communication runs at 115200 baud
  Serial.begin(9600);
  Serial2.begin(9600);

  // Modbus slave ID 1
  node.begin(1, Serial2);
  // Callbacks allow us to configure the RS485 transceiver correctly
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
}

bool state = true;

void loop()
{
 uint16_t data[50];
 Serial.println("Data Register of 21: ");
 getHoldingRegisterData( 21,2,data); 
 Serial.println(); 
 delay(1000);
 Serial.println("Data Register of 21: ");
 getHoldingRegisterData( 27,2,data); 
 Serial.println();
 node.clearResponseBuffer();
 node.clearTransmitBuffer();
 Serial2.flush();
 Serial.flush();
}


bool getHoldingRegisterData(uint16_t registerAddress, uint16_t regSize, uint16_t* data){

uint8_t j, result, test;

if(DEBUGON){
  Serial.print(F("Reading register: "));
  Serial.print(registerAddress);
  Serial.print(F(" regSize: "));
  Serial.print(regSize);
  Serial.print(F(" sizeof(data): "));
  Serial.print(sizeof(&data));
  Serial.print(F(" XMITDELAY: "));
  Serial.println(XMITDELAY);
  Serial.println("");
}

// Delay and get register data.

result = node.readInputRegisters(registerAddress-BASED_NUMBERING, regSize);
Serial.print("Result is time 1: ");
Serial.println(result);
delay(XMITDELAY);

// LT is sleeping, ping it a couple more times.

if (result == node.ku8MBSuccess) {
  if(DEBUGON){
    Serial.print(F("LT: Success, Received data: "));
  }

  for (j = 0; j < regSize; j++) {

    data[j] = node.getResponseBuffer(j);
   
    if(DEBUGON){
      Serial.print(data[j], HEX);
      Serial.print(F(" "));
    }
    
  }

  if(DEBUGON){
    Serial.println("");
  }

  node.clearResponseBuffer();
  node.clearTransmitBuffer();
  return true;

}


if(result ==node.ku8MBResponseTimedOut){

        if(DEBUGON){
          Serial.println(F("LT: Response timed out. Trying again. "));
        }

    int i =0;

    while(i < 50){

      result = node.readInputRegisters(registerAddress-BASED_NUMBERING, regSize);
      Serial.print("Result is time 2: ");
      Serial.println(result);
      delay(XMITDELAY);

   
      if(result == node.ku8MBResponseTimedOut){
        if(DEBUGON) Serial.println(F("LT: Failed. Response timed out. Adjust the XMITDELAY and/or ku8MBResponseTimeout? "));
      }
      else break;

      i++;

    }

}


else{
  if(DEBUGON){
  Serial.print(F("Failed, Response Code: "));
  Serial.println(result, HEX);
  }
}

node.clearResponseBuffer();
node.clearTransmitBuffer();
return false;
}

thankyou very much
this will work with Selec EM2M energy meter

which library you are using because can you share me the link

Link of the library I am using. Yes, this code is working code just you will need to make the desired changes such as hex to float conversion and reversing the hex string else everything is working.