mega 2560 - max485 - inepro pro1-mod modbus does connect but doesn't send data

Dear everybody,

after 2 weekends of being busy with this modbus stuff, my wife is getting fed up with me. Because I haven't got a place to store my Arduino stuff and work on it at the same time, the living is becoming a mess. So please help my wife (and me). :sunglasses:

I have tried lots of different libraries and code but I ended up with the code writtten down below. This code gives an error in the output monitor that says:


Exception errors: 0
Failed requests: 9
Successful requests: 0
Low byte: 0
High byte: 516
Voltage 0.00

Exception errors: 0
Failed requests: 11
Successful requests: 0
Low byte: 0
High byte: 516
Voltage 0.00

The Energy meter, you might not be able to see on the picture, gives the communication blink (com) but sadly doesn't give the output I was hoping for on the PC.

the manual of the inepro pro1-mod is downloadable here manual
On page 25 is the register.

#include <SimpleModbusMaster.h>
//https://arduino.stackexchange.com/questions/50188/arduino-modbus-rtu-master-communication-with-power-meter-problem/50206#50206

#define TxEnablePin 2                    // RS485 modbus direction control pin:
#define baud 9600                           // modbus port speed:
#define timeout 2000                        // modbus timeout in mSec:
#define polling 500                         // modbus scan rate in mSec:
#define retry_count 15

#define TOTAL_NO_OF_REGISTERS 1// number of registers to poll for:



enum
{
 PACKET1,
 TOTAL_NO_OF_PACKETS                       // leave this last entry
};

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

//struct packetPointer packet1 = &packets[PACKET1];
unsigned int regs[TOTAL_NO_OF_REGISTERS];   // master register array
long previousMillis = 0;
long interval = 1200;
unsigned long currentMillis;

void setup() {
 Serial.begin(9600);
 Serial3.begin(9600);
 Serial.println("Hello World");
 modbus_construct(&packets[PACKET1], 001, READ_HOLDING_REGISTERS, 0x5000, 2, 0);  //initialize packet
 modbus_configure(&Serial3, baud, SERIAL_8E1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs);
}

void loop() {
 modbus_update();


 float Power;
 unsigned long temp = (unsigned long)regs[1] << 16 | regs[0];
 Power = *(float*)&temp;

  currentMillis = millis();
 if (currentMillis - previousMillis >= interval)
 {  
   Serial.print("Exception errors: ");
   Serial.println(packets[PACKET1].exception_errors);


   Serial.print("Failed requests: ");
   Serial.println(packets[PACKET1].failed_requests);


   Serial.print("Successful requests: ");
   Serial.println(packets[PACKET1].successful_requests);
   Serial.print("Low byte: ");
   Serial.println(regs[0]);
   Serial.print("High byte: ");
   Serial.println(regs[1]);
   Serial.print("Voltage ");
   Serial.println(Power);
   Serial.println("----------");

   previousMillis = currentMillis;
 }

}

for now I'm trying to read the voltage (register 5000).

If somebody knows, Thanks al lot in advance!!!

I cannot find an obvious error in your code, except that you're requesting two registers but provide space for only one (this doesn't pose a problem yet because the connection fails anyway).

But I recommend not to use SimpleModbusMaster but ModbusMaster instead as it provides return codes that tells you what kind of error occured and is usually easier to use in the end.

Once you've done that, post the return code you got (error code) as well as your changed code!

Check the Modbus ID, baud rate and parity on the meter as well as the polarity of the RS485 connection.

Thank you Pylon,

I've been busy selfteaching me this part of arduino... and finally (with the help of this forum) I got it working :slight_smile:

First, I have changed the parity in the meter from "even" to "none" (which is the default in ModbusMaster)

the code that I've used is as following

#include <ModbusMaster.h>


/*!
 * 
 * 
 * 
 *
 This program is made to read data from a "Inepro PRO1-Mod energy meter" (EAN 08717438668840) 
 it's a 45amp single phase energy meter
 https://ineprometering.com/pro1/#Types
 documentation:
 https://ineprometering.com/wp-content/uploads/2018/09/PRO1-user-manual-V2.18.pdf
   I'm using a MAX485-compatible RS485 Transceiver.
https://opencircuit.nl/Product/MAX485-TTL-to-RS485-module
and a mega 2560
  Rx/Tx is hooked up to the hardware serial port at 'Serial3' which is port 14 and 15.
  The Data Enable and Receiver Enable pins are hooked up as follows:
*/
#define MAX485_DE      3 // I do not use this port since I only receive data
#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 9600 baud
  Serial.begin(9600);
  Serial3.begin(9600);  // standard config = 8N1 (8 bits, none parity, 1 stopbit) if else: 8E1 (8 bits, even parity, 1 stopbit)  Serial3.begin(9600, SERIAL_8E1) 
                        // Serial3 is port 14 & 15 @ mega 2560

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

bool state = true;

void loop()
{
  uint16_t result;
 

  // Read 2 registers starting at 0x4003)
  // for the INEPRO mod1 energy meter, these registers are data typed as:  Signed
  result = node.readHoldingRegisters(0x4003, 2);
  if (result == node.ku8MBSuccess)
  {
    Serial.print("Modbus ID: ");                   //modbus id
    Serial.println(node.getResponseBuffer(0x00));  // read register 4003
    Serial.print("Baud rate: ");                   // baud rate
    Serial.println(node.getResponseBuffer(0x01));  // read register 4004
   
  }

// Read 1 register starting at 0x400B)
  // for the INEPRO mod1 energy meter, these registers are data typed as:  Signed
 result = node.readHoldingRegisters(0x400B, 1);
  if (result == node.ku8MBSuccess)
  {
    Serial.print("Meter Amps: ");                   // max ampere of this meter
    Serial.println(node.getResponseBuffer(0x00));  // read register 400B
  }
 
 
// Read 2 registers starting at 0x5000)
// for the INEPRO mod1 energy meter, these registers are data typed as:  float ABCD
// register length of 0x5000 is 2 so this is 2 times 16 bit = 32 bit
// so we are receiving 32-bit data in two parts of 16 bit via data[0] and data[1] 
// the data is part of the 32-bit binary32 (IEEE-754) standard
// to get the decimal number, we need to construct the data 
// decimalvalue = data[0] << 16 | data[1]   example: 0x43680000 + 0xD747 = 0x4368D747

  result = node.readHoldingRegisters(0x5000, 2);
  if (result == node.ku8MBSuccess)
  {

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

 result = node.readHoldingRegisters(0x5000, 2);
  if (result == node.ku8MBSuccess)
  {

    float x;
unsigned long *p;
p = (unsigned long*)&x;
*p = (unsigned long)node.getResponseBuffer(0x00) <<16 | node.getResponseBuffer(0x01);

Serial.print("Voltage: ");    //voltage of the grid
Serial.println(x, 1); // 1 decimal   (x, 2)= x with 2 decimal
  } 
   
 result = node.readHoldingRegisters(0x6000, 2);
  if (result == node.ku8MBSuccess)
  {

    float x;
unsigned long *p;

p = (unsigned long*)&x;

*p = (unsigned long)node.getResponseBuffer(0x00) <<16 | node.getResponseBuffer(0x01);

Serial.print("Current: ");      //total usage of kWh
Serial.print(x, 5); 
Serial.println(" kWh");
  }  

  result = node.readHoldingRegisters(0x5012, 2);
  if (result == node.ku8MBSuccess)
  {

    float x;
unsigned long *p;

p = (unsigned long*)&x;

*p = (unsigned long)node.getResponseBuffer(0x00) <<16 | node.getResponseBuffer(0x01);

Serial.print("Active Power: ");     // kW used at this moment
Serial.print(x, 5); 
Serial.println(" kW");
  }   
node.clearResponseBuffer();

  delay(1000);
}

the wiring is as follows:

First, I have changed the parity in the meter from "even" to "none" (which is the default in ModbusMaster)

No, it's just configured that way in your code.

Change the line

Serial3.begin(9600);

to

Serial3.begin(9600, SERIAL_8E1);

and you can activate the parity bit again (which is not a bad choice).