Read MODBUS registers using MAX RS 485 to TTL module using arduino mega

I want to read MODBUS Register from an Energy Meter (Model : Elite 100 , Make : SECURE). But I unable to communicate to the Meter. in SERIAL MONITOR shows the faild to communicate and response code is "E2".

Elite 100 Energy Meter Modbus Register : DPM MODBUS_Elite 103_303_307_V0E02.xlsx - Google Sheets

Parameter set in meter :- Baud Rate : 9600 , Parity Bit : None , Stop Bit: 1

#include<ModbusMaster.h>


/*  DI =  UNO / NANO TX PIN / arduino mega pin 1 TX pin
    RO =  UNO/ NANO RX PIN / arduino mega pin 0 RX Pin
*/
#define MAX485_DE      3
#define MAX485_RE_NEG  2

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);



  // Serial.begin(9600, SERIAL_8N1);
  Serial.begin(9600);
  //slave ID 1
  node.begin(1, Serial);

  Serial.println("Starting Modbus Transaction:");
  // Callbacks allows us to configure the RS 485 transreceiver correctly
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
}


uint16_t newData = 0;
float floatData;
double dataOne;



void loop() {                           // loop starts from here.

  static uint32_t i;
  uint8_t j, result;
  uint16_t data[10];

  // uint8_t result;

  i++;
  // Frequency = 40172 / 00AC
  result = node.readHoldingRegisters(40172, 2); // read holding registars

  Serial.println(" ");
  /*
    if (result == node.ku8MBSuccess) {

      Serial.print("\nSuccess, Received data 0: ");

      for (j = 0; j < 2; j++) {    // THIS FUNCTION READ SINGLE REGISTAR
        data[j] = node.getResponseBuffer(j);
        floatData, dataOne = node.getResponseBuffer(j);
        Serial.print("\nHex data:");
        Serial.print(data[j], HEX);
        Serial.print(" ");
        Serial.print("\nDec data:");
        Serial.print(data[j], DEC);
        Serial.print("\nfloat data:");
        Serial.print(floatData);
  */
  //================


  if (result == node.ku8MBSuccess) {


    //    Serial.println("--------------------");
    //    Serial.println("Frequency");
    //    Serial.println(node.getResponseBuffer(0x00AC) / 100.0f );


    Serial.print("\nSuccess, Received data 0: ");

    for (j = 0; j < 2; j++) {
      data[j] = node.getResponseBuffer(j);
    }

    unsigned long temp = (unsigned long)data[0] + (unsigned long)data[1] * 65536;
    floatData = *((float*)&temp);

    Serial.print(floatData);

  }


  //}
  //}


  else {
    Serial.print("Failed, Response Code: ");
    Serial.print(result, HEX);
    Serial.println(" ");
    delay(5000); // 5000
  }







  delay(1000);
}
1 Like

Are you sure that you want to use Serial for debug messages and for MODBUS? Try Serial1 instead?

I've use Serial1. but output is same as above. "Failed, Response Code: 2 "

#include<ModbusMaster.h>


/*  DI =  UNO / NANO TX PIN / arduino mega pin 18 TX1 pin
    RO =  UNO/ NANO RX PIN / arduino mega pin 19 RX1 Pin
*/
#define MAX485_DE      3
#define MAX485_RE_NEG  2

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);



  // Serial.begin(9600, SERIAL_8N1);
  Serial.begin(9600);
  Serial1.begin(9600) ; //, SERIAL_8N1);
  //slave ID 1
  node.begin(1, Serial1);

  Serial.println("Starting Modbus Transaction:");
  // Callbacks allows us to configure the RS 485 transreceiver correctly
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
}


uint16_t newData = 0;
float floatData;
double dataOne;



void loop() {                           // loop starts from here.

  static uint32_t i;
  uint8_t j, result;
  uint16_t data[10];

  // uint8_t result;

  i++;
  // Frequency = 40172 / 00AC
  result = node.readHoldingRegisters(40172, 2); // read holding registars

  Serial.println(" ");
  /*
    if (result == node.ku8MBSuccess) {

      Serial.print("\nSuccess, Received data 0: ");

      for (j = 0; j < 2; j++) {    // THIS FUNCTION READ SINGLE REGISTAR
        data[j] = node.getResponseBuffer(j);
        floatData, dataOne = node.getResponseBuffer(j);
        Serial.print("\nHex data:");
        Serial.print(data[j], HEX);
        Serial.print(" ");
        Serial.print("\nDec data:");
        Serial.print(data[j], DEC);
        Serial.print("\nfloat data:");
        Serial.print(floatData);
  */
  //================


  if (result == node.ku8MBSuccess) {


    Serial.print("\nSuccess, Received data 0: ");

    for (j = 0; j < 2; j++) {
      data[j] = node.getResponseBuffer(j);
    }

    unsigned long temp = (unsigned long)data[0] + (unsigned long)data[1] * 65536;
    floatData = *((float*)&temp);

    Serial.print(floatData);

  }


  //}
  //}


  else {
    Serial.print("Failed, Response Code: ");
    Serial.print(result, HEX);
    Serial.println(" ");
    delay(5000); // 5000
  }







  delay(1000);
}

Hi brother ,
If your problem is solved for this project, kindly share your code and changes that you have done.
Thank you.

@harshsuthar53 , post the code you are using, as I think I might see why the code posted by @jerromy_shmith isn't working.

#include <ModbusMaster.h> //Library for using ModbusMaster

#define MAX485_DE 2
#define MAX485_RE_NEG 3

#define MAX485_DI 21
#define MAX485_RO 20
ModbusMaster node; //object node for class ModbusMaster

void preTransmission() //Function for setting stste of Pins DE & RE of RS-485

{
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);
pinMode(4,INPUT);
pinMode(5,INPUT);

digitalWrite(MAX485_RE_NEG, 0);
digitalWrite(MAX485_DE, 0);

Serial.begin(9600); //Baud Rate as 9600
node.begin(1, Serial); //Slave ID as 1

node.preTransmission(preTransmission); //Callback for configuring RS-485 Transreceiver correctly
node.postTransmission(postTransmission);

}
void loop()

{
int value = node.readHoldingRegisters(0x40001,2); //Writes value to 0x40000 holding register
Serial.println(value);
}

Summary

This text will be hidden

From your screenshot, you are using an Arduino MEGA2560 board. Here's your code modified to read 2 holding registers at address 40001 & 40002. I'm using serial #1 at 9600 baud for the Modbus comms to device #1.

Note that my RS485 module doesn't use separate RE & DE signals. Adjust the code accordingly.

// FOR MEGA2560 with Modbus device #1 on Serial #1 @ 9600 baud.

#include <ModbusMaster.h> //Library for using ModbusMaster

#define MAX485_REDE_PIN 5
#define MAX485_DE 2
#define MAX485_RE_NEG 3

ModbusMaster node; //object node for class ModbusMaster

void preTransmission() //Function for setting stste of Pins DE & RE of RS-485
{
//  digitalWrite(MAX485_RE_NEG, 1);
//  digitalWrite(MAX485_DE, 1);
  digitalWrite(MAX485_REDE_PIN, 1);
}
void postTransmission()
{
//  digitalWrite(MAX485_RE_NEG, 0);
//  digitalWrite(MAX485_DE, 0);
  digitalWrite(MAX485_REDE_PIN, 0);
}

void setup()
{
//  pinMode(MAX485_RE_NEG, OUTPUT);
//  pinMode(MAX485_DE, OUTPUT);
  pinMode(MAX485_REDE_PIN, OUTPUT);

//  digitalWrite(MAX485_RE_NEG, 0);
//  digitalWrite(MAX485_DE, 0);
  digitalWrite(MAX485_REDE_PIN, 0);
  
  Serial.begin(9600); //Baud Rate as 9600
  Serial.println( MAX485_REDE_PIN );
  
  Serial1.begin(9600); //Baud Rate as 9600
  node.begin(1, Serial1); //Slave ID as 1 on Serial #1

  node.preTransmission(preTransmission); //Callback for configuring RS-485 Transreceiver correctly
  node.postTransmission(postTransmission);
}

void loop()
{
  uint8_t result = node.readHoldingRegisters(0x0000, 2); // Reads Holding Registers 40001 & 40002
  
  Serial.println( result );

  if (result == node.ku8MBSuccess)
  {
    Serial.print("data : ");
    Serial.print(node.getResponseBuffer(0));
    Serial.print(" ");
    Serial.println(node.getResponseBuffer(1));
  }
  Serial.print("\n");

  delay(3000);
}

I have a Modbus slave simulator setup with address 40001 holding the value 12, and address 40002 holding the value 34. My IDE serial monitor shows:

15:06:36.985 -> 0
15:06:36.985 -> data : 12 34
15:06:36.985 -> 
15:06:40.255 -> 0
15:06:40.255 -> data : 12 34
15:06:40.255 -> 

Thank you for your reply and support but still i'm facing problem and i'm unable to read holding register.

so basically I'm working on project which is about to read the holding register data (start from 40001 to 40006) which is comes from the potentiometer and want to print that data directly on serial monitor.

Here I'm attaching a connection diagram. One thing I also want to add that I'm bad at codding so, if possible please give some guidance and if possible give me the code regarding my project.

Thanking you in advance.

I'm facing this type of error.

Which Rx and Tx are you using on your MEGA2560?

Your drawing doesn't show any connection to the VCC pin on the RS485 module.

You may also need a GND connection between your MEGA2560 and your 5ch analogue module.

tx = 1 and rx= 0

RS485 Vcc is connected with MEGA 2560 Vin and GND is also connected with MEGA 2560 GND.

4-20 mA potentiometer and 5ch analog module are connected to 24 v dc battery.

I did all the connection correctly as per your correction. Now please help me out from this errors.

Ok, a few ideas.

Firstly, I would suggest that you stay away from RX (0) and TX (1). They are used to communicate with the on-board USB-Serial adapter. Use RX1 (19) and TX1 (18) instead.

Secondly, how are you powering your MEGA2560 board? Are you powering it via the USB cable? If so, then I don't believe that there is any usable voltage on Vin. Use the 5V socket on your MEGA2560 to power your RS485 module (assuming it's one of the standard MAX485 based breakout boards).

i changed to RX1(19) and TX1(18) but it still getting error code 226.And the MAX485 module get power supply via arduino mega. and one more thing that arduino has separate power supply and ground as well and also connected to PC for serial monitor to watch data output. Now all the connections are as per your correction. and secondly i separate the connection of DE & RE.

Are you feeding the "separate power supply" into your MEGA2560 via the black barrel socket? What voltage is that power supply?

yes and voltage of power supply is 5V

Ok. Just needed to check what your Vin voltage was as you mentioned that you used it to power your RS485 board.

We've established that you are using a MEGA2560 board. What RS485 module are you using? Does it look like this one:

Can you provide details on your 5 channel isolation analog input module. Model no & link to datasheet etc.

yes , i use same module that you have mention. this rs485 modules vcc and gnd connect with MEGA2560

link for 5ch analog input module

A quick look at the user manual for that unit suggests that it supports a protocol called DCON as well as MODBUS with a software programmable baud rate. You need to figure out what the current comms settings are for your unit.

Appendix A on page 120 says that the module has an INIT mode where it can be set to known default settings.

Another thing I would recommend is to try and get hold of any manufacturer software that may be able to talk to the module. I did a bit of a search for you and discovered a program called DCON Utiltiy pro. The webpage says: "DCON Utility Pro is a toolkit that can help user easily to search, configure and test I/O modules". One of the images on that web page shows tM series modules and at the bottom of the web page it shows a table indicating support for the tM series modules.

If you can talk to your unit with the manufacturers software, then it (a) gives you confidence that you module is working, (b) tells you what protocol the module is configured for - hopefully MODBUS, (c) tells you the baud rate and (d) tells you the MODBUS address of the module.

You can then use your MEGA2560 as an RS485 MODBUS sniffer and print out the messages being transferred between the PC app and your module. That should confirm baud rate and module address. You should also be able to see the actual MODBUS message that reads the values you want.

You can then adjust your original MEGA2560 code accordingly and hopefully duplicate the MODBUS comms and talk to your module from the MEAG2560.