Reading data from energy meter using RS485 to TTL converter using Arduino Atmega2560

I need to read data from the holding register of the energy meter. The registers were starting from 40101 float type. I tried to fetch the data using the RS485 to USB, where I could see the meter reading, but when I tried to read data using the RS485 ttl converter with Arduino 2560, I got an error code like 224. I have attached the code and the RS485 below.



#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      3
#define MAX485_RE_NEG  2

// 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);
  Serial1.begin(9600);

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

bool state = true;

void loop()
{
  uint8_t result;
  uint16_t data[6];
  
  result = node.readHoldingRegisters(157, 1);
  getResultMsg(result); // Interpret and print the result
}

bool getResultMsg(uint8_t result)
{
  String tmpstr2;

  switch (result) {
    case node.ku8MBSuccess:
      Serial.println("Success");
      return true;
      break;
    case node.ku8MBIllegalFunction:
      tmpstr2 = "Illegal Function";
      break;
    case node.ku8MBIllegalDataAddress:
      tmpstr2 = "Illegal Data Address";
      break;
    case node.ku8MBIllegalDataValue:
      tmpstr2 = "Illegal Data Value";
      break;
    case node.ku8MBSlaveDeviceFailure:
      tmpstr2 = "Slave Device Failure";
      break;
    case node.ku8MBInvalidSlaveID:
      tmpstr2 = "Invalid Slave ID";
      break;
    case node.ku8MBInvalidFunction:
      tmpstr2 = "Invalid Function";
      break;
    case node.ku8MBResponseTimedOut:
      tmpstr2 = "Response Timed Out";
      break;
    case node.ku8MBInvalidCRC:
      tmpstr2 = "Invalid CRC";
      break;
    default:
      tmpstr2 = "Unknown error: " + String(result);
      break;
  }
  Serial.println(tmpstr2);
  return false;
}

Please do not post in "Uncategorized"; see the sticky topics in https://forum.arduino.cc/c/using-arduino/uncategorized/184.

Your topic has been moved.

Thanks for the PM. I'll put my thoughts here so that others may benefit (or not!).

Here's the datasheet I found that specifies the Modbus registers:
elmeasure_multifunction_meter_modbus_register_1_.pdf (74.1 KB)

Firstly, I would put a delay in your loop() function so that you are not hammering the meter with requests.

Are you trying to read the frequency here? I think you need to try reading register 156 instead.

Frequency is a float according to that datasheet I found. I would think that means that you would need 4 bytes to hold the value. In which case you need to ask for 2 registers like this:

result = node.readHoldingRegisters(156, 2);

Please see the output when I am connecting using Modbus software

Have a read of:
Standard Modbus Data Address Format.
Especially the section titled " Coil Number Register Number and Data Offset" as that may help.

As you said i have modified the address but still i am getting invalid slave ID for this below code

#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      3
#define MAX485_RE_NEG  2

// 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);
  Serial1.begin(9600);

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

bool state = true;

void loop()
{
  uint8_t result;
  uint16_t data[6];
  
  result = node.readHoldingRegisters(156, 2); 
  delay(2000);
  getResultMsg(result); // Interpret and print the result
}

bool getResultMsg(uint8_t result)
{
  String tmpstr2;

  switch (result) {
    case node.ku8MBSuccess:
      Serial.println("Success");
      return true;
      break;
    case node.ku8MBIllegalFunction:
      tmpstr2 = "Illegal Function";
      break;
    case node.ku8MBIllegalDataAddress:
      tmpstr2 = "Illegal Data Address";
      break;
    case node.ku8MBIllegalDataValue:
      tmpstr2 = "Illegal Data Value";
      break;
    case node.ku8MBSlaveDeviceFailure:
      tmpstr2 = "Slave Device Failure";
      break;
    case node.ku8MBInvalidSlaveID:
      tmpstr2 = "Invalid Slave ID";
      break;
    case node.ku8MBInvalidFunction:
      tmpstr2 = "Invalid Function";
      break;
    case node.ku8MBResponseTimedOut:
      tmpstr2 = "Response Timed Out";
      break;
    case node.ku8MBInvalidCRC:
      tmpstr2 = "Invalid CRC";
      break;
    default:
      tmpstr2 = "Unknown error: " + String(result);
      break;
  }
  Serial.println(tmpstr2);
  return false;
}

And I also tried by changing the address to 40101 but still iam getting invalid slave address

Just to clarify your hand drawn schematic in post #1, the TX1 signal (pin 18) should go to the pin marked DI (you have DO). And the RX1 signal (pin 19) should go to the pin marked RO (you have RI).

Usually the invalid slave ID suggests that the RS485 is being switched from TX to RX (or RX to TX) too soon or too late.

You are using a MEGA2560 and one of the hardware serial ports, so I think you need to insert a flush() command into the postTransmission() function like this:

void postTransmission()
{
  Serial1.flush();        // <---- Add this line to your code
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);
}

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