Modbus RS485 Communication using Arduino as Master

I am trying to read holding registers from a Schneider PowerLogic PM5650 using Arduino. Communication I am using is RS485. Moreover, I am using TTL to 485 module with following pinout
RS485 module----------------- Schneider
A ---------------------------------- A
B ---------------------------------- B

RS485 module ----------------Arduino UNO
DI -------------------------- TX (Pin 1)
DE -------------------------- Pin 3
RE -------------------------- Pin 2
RO -------------------------- RX (Pin 0)
Vcc to Arduino 5 v and GND to Arduino GND
So when I use simple RS485 to USB and use software (Modscan) to Read the Holding Register, it shows me the data when I put in the Register Address. But when I try to do same with the Arduino uno I can’t get any data. This is the code I am using

#include <ModbusMaster.h>

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

// Modbus communication runs at 9600 baud

Serial.begin(9600);

// Modbus slave ID 1

node.begin(1, Serial);

// Callbacks allow us to configure the RS485 transceiver correctly

node.preTransmission(preTransmission);

node.postTransmission(postTransmission);

}

void loop()

{

uint8_t resultMain;

resultMain = node.readHoldingRegisters(0x3035, 6);

Serial.println("Reading Register: ");

if (resultMain == node.ku8MBSuccess)

{

Serial.println("--------");

Serial.print ("Voltage Avg: ");

Serial.println(node.getResponseBuffer(0x00));

Serial.print ("V avg 2: ");

Serial.println(node.getResponseBuffer (0x01));

Serial.print ("Data_3: ");

Serial.println(node.getResponseBuffer(0x04));

Serial.print ("Data_4: ");

Serial.println(node.getResponseBuffer(0x05));

}

delay(1000);

}

This is my Output

image

This the the register Address

I am stuck in it. Please guide what should I do

How did you decide on 0x3035 ? The addresses in the table appear to be decimal, so it should be 3035, assuming you need to subtract 1.

I tried decimal as well result remain the same.
HEX value of address is BDB, tried it as well (0x0BDB) but it does not work either

You are using the same serial port as you are you using for serial monitor, that is not a good idea.

How did you decide 9600 is the correct baud rate? Are you sure that 8,N,1 framing is correct?

Please post a link to the data sheet for the device you are using.

i have tried different serial pin as well but result is the same

Data Sheet

Schneider Device

Any change i need to do in my code or circuit ?

Uno only has one serial port, so if you are using that for the serial monitor, you will need to use SoftwareSerial for communication.

can you suggest me code changes and pin changes ?

Here is an example sketch I used to control a relay module. You should be able to adapt it to your needs.

/*!
 * @file
 * @brief Example ModbusMaster on Arduino Uno.
 * @author Bob Cousins
 *
 * Example showing use of ModbusMaster to control a relay module.
 * SoftwareSerial is used because Serial is used for serial monitor.
 */
 
#include <ModbusMaster.h>
#include <SoftwareSerial.h>

#define TX 3
#define RX 2

#define TX_ENABLE   4
#define RX_ENABLE_N 5

#define BAUD_RATE 9600

#define SLAVE_ADDRESS 1

ModbusMaster master;

SoftwareSerial modbus_serial (RX, TX);

void pre_transmit (void)
{
  digitalWrite (TX_ENABLE, 1);
  digitalWrite (RX_ENABLE_N, 1);
}

void post_transmit (void)
{
  digitalWrite (TX_ENABLE, 0);
  digitalWrite (RX_ENABLE_N, 0);
}

void setup() 
{
  pinMode (TX, OUTPUT);
  pinMode (RX, INPUT);

  pinMode (TX_ENABLE, OUTPUT);
  pinMode (RX_ENABLE_N, OUTPUT);

  Serial.begin (115200);

  modbus_serial.begin (BAUD_RATE);
  master.begin (SLAVE_ADDRESS, modbus_serial);

  master.preTransmission(pre_transmit);
  master.postTransmission(post_transmit);
}

void loop() 
{
  uint8_t result;

  // turn on relay 0
  result = master.writeSingleCoil (0, 1);
  if (result == ModbusMaster::ku8MBSuccess)
    Serial.println("It worked!");
  else
  {
    Serial.print("I can't do that: ");
    Serial.println (result, HEX);
  }

  delay (1000);

  // turn off relay 0
  result = master.writeSingleCoil (0, 0);
  delay (1000);
}

I used this code

#include<ModbusMaster.h>


#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() {
  
  Serial.begin(9600);
 // Serial2.begin(9600);

  pinMode(MAX485_RE_NEG, OUTPUT);
  pinMode(MAX485_DE, OUTPUT);

  // Init in receive mode
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);

  //My slave uses 9600 baud
  delay(1000);
  Serial.println("starting arduino: ");
  Serial.println("setting up Serial ");
  Serial.println("setting up RS485 port ");
//  slave id
 node.begin(1, Serial);
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
}

void loop() {
  uint16_t result;
  
//slave address and length
  result = node.readHoldingRegisters(3035 ,2);

  if (result == node.ku8MBSuccess)
  {
      Serial.print("V avg : ");
      Serial.println(node.getResponseBuffer(1));
      Serial.print("Flow : ");
      Serial.println(node.getResponseBuffer(2));
  }

  Serial.print("\n");
  
  delay(500);
}

and its giving me this output

image

When I change the register address the output changes
Thanks for your time, plz look into this and guide

V avg on power analyzer is 245.5

This Code is giving me the values as when I use CT with the Schneider meter and check I avg register it start giving me values and as I remove load from CT it gives me 0. it means it is giving me register values now how can I interpret those values ?

This is the code in which i am using voltage register (V avg) value on meter was around 245-250

#include<ModbusMaster.h>


#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() {
  
  Serial.begin(9600);
 // Serial2.begin(9600);

  pinMode(MAX485_RE_NEG, OUTPUT);
  pinMode(MAX485_DE, OUTPUT);

  // Init in receive mode
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);

  //My slave uses 9600 baud
  delay(1000);
  Serial.println("starting arduino: ");
  Serial.println("setting up Serial ");
  Serial.println("setting up RS485 port ");
//  slave id
 node.begin(1, Serial);
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
}

void loop() {
  uint16_t result;
  
//slave address and length
  result = node.readHoldingRegisters(3035 ,2);

  if (result == node.ku8MBSuccess)
  {
      Serial.print("V avg : ");
      Serial.println(node.getResponseBuffer(0));
      Serial.print("Flow : ");
      Serial.println(node.getResponseBuffer(1));
      
  }

  Serial.print("\n");
  
  delay(500);
}

Output:
image

I think the problem may be in the way you are interpreting the modbus response from the meter.

That table you posted in your post #1 says that the "Voltage L-N Avg" is a 32 bit value (2x INT16s) but should be interpreted as a FLOAT32.

I think that to get the whole value you would need to request 2 registers - as your code in post #12 does. However, the 2 values returned are the 2 halves of the 32-bit floating point number. You need to combine the 2 16-bit values received into one 32-bit value which you would then interpret as a floating point number.

With a bit of massaging, I get the following:

17273 = 0x4379
56781 = 0xDDCD

If I combine the 2 into one 32- bit value, I get:

0x4379DDCD

When that is interpreted as an IEE754 32-bit floating point number, it works out as 249.8664V.

Thanks @markd833 , that really helps can you plz help me in providing code lines that i could use in my code to convert it in the required formate.

Have a read of this:

Thanks, i will use it and post the working code here

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