Interfacing RS485 (Modbus RTU) energy meter with arduino uno error

Hi,

Hope you're doing well.

I'm trying to interface an energy meter (A9MEM2050) with an Arduino Uno using the MAX485 chip. I keep getting the following error:
"Failed, Response Code: E2"

Has anyone dealt with such an error before? I'd be happy to put up my code- it's a build up on the example halfduplex code (but has no comments- I know, it's a crime, sorry!).

Thank you.

My code is attached below:

#include <ModbusMaster.h>

// pin names
#define ledPin 13
#define MAX485_DE 5
#define MAX485_RE_NEG 5
#define MODBUS_RX_PIN 0
#define MODBUS_TX_PIN 1 

#define MODBUS_SERIAL_BAUD 9600 

uint16_t data_register[3] = {0x0BD4, 0x0BB8, 0x0BEE}; //Voltage, current and powe

ModbusMaster node;

void preTransmission()
{
  delay(500);
  digitalWrite(MAX485_RE_NEG, HIGH);
  digitalWrite(MAX485_DE, HIGH);
}

void postTransmission()
{
  digitalWrite(MAX485_RE_NEG, LOW);
  digitalWrite(MAX485_DE, LOW);
  delay(500);
}


void setup()
{
  Serial.println("Start ");
  pinMode(ledPin,OUTPUT);

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

  digitalWrite(MAX485_RE_NEG, LOW);
  digitalWrite(MAX485_DE, LOW);

  Serial.begin(9600);

  // Modbus Slave ID1
  node.begin(1, Serial);

  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
}

bool state = true;

void loop()
{
  uint8_t result;
  uint16_t data[2];
      
  // result = node.readHoldingRegisters(0x001E, state);
  // state = !state;

  // result = node.readInputRegisters(0x0031, 16);
  // if (result == node.ku8MBSuccess)
  // {
  //   Serial.print("Meter name: ");
  //   Serial.println(node.getResponseBuffer(0x04)/100.0f);
  // }

    int i;
    float reading;
        for(i=0; i<=2; i++){
            result = node.readInputRegisters(data_register[i], 1);
     
        if (result == node.ku8MBSuccess) {
          Serial.println("Success, Received data: ");

           data[0]=node.getResponseBuffer(0x00);
           data[1]=node.getResponseBuffer(0x01);
          
           //read voltage
           if(data_register[i] == 0x0BD4){
            Serial.print("Voltage: ");
            reading = *((float *)data);
            Serial.print(reading);
            Serial.println(" Volts");
           }
           //read current
           if(data_register[i] == 0x0BB8){
            Serial.print("Current: ");
            reading = *((float *)data);
            Serial.print(reading);
            Serial.println(" Amps");
           }
           //read power
           if(data_register[i] == 0x0BEE){
            Serial.print("Frequency: ");
            reading = *((float *)data);
            Serial.print(reading);
            Serial.println(" kW");
           }
        } else {
          Serial.print("Failed, Response Code: ");
          Serial.print(result, HEX);
          Serial.println("");
          delay(5000); 
        }
      
    }

  digitalWrite(ledPin,HIGH);//turn the LED on 
  delay(1000);               //wait
  digitalWrite(ledPin,LOW); //turn the LED off 
  delay(1000);               //wait

//   delay(10000);
}


Can you provide a link to the user manual for that device that details the communications protocol.

Is that an error on the Arduino side - perhaps from the ModbusMaster library, or is it displayed on the energy meter?

Any code is better than no code, and the full code (or a small sketch that demonstrates the problem) is better that some code snippet.

1 Like

based on the missing code, missing schematic and missing pictures I guess its due to


    /**
    ModbusMaster response timed out exception.
    
    The entire response was not received within the timeout period, 
    ModbusMaster::ku8MBResponseTimeout. 
    
    @ingroup constant
    */
    static const uint8_t ku8MBResponseTimedOut           = 0xE2;

You are probably not sending the correct line ending with your commands.

Hi Mark,

The user manual can be found under - [Communication via Modbus - iEM2050 (schneider-electric.com)] https://www.productinfo.schneider-electric.com/iem2050/5b3e7b76d674a900015d9be8/iEM2050%20User%20Manual/English/BM_iEM2000seriesUserManual_0000207501.ditamap/$/chapter4

The error is displayed on the serial monitor on Arduino IDE.

I'll put my code in my original post now.

Thank you for your time.

Hi John,

Could you elaborate what you mean by that please?

Thank you.

ezrax123,
It was just a guess based on the line in post #3 from noiasca, that said:

The entire response was not received within the timeout period,
ModbusMaster::ku8MBResponseTimeout.

Maybe the meter is expecting a Newline or Carriage Return (or both) after any command that you are sending to it.

Not the answer to your problem, but you've got a spelling mistake in the word Voltage:

Serial.print("Volatge: ");

Also

Serial.println(" Volt");

should say " Volts" to be consistent with:

 Serial.println(" Amps");
1 Like

It's a bad idea to use the hardware serial port on the UNO for your serial printing and modbus Comms.

Thanks Mark!

I was recommended to use Arduino Mega as a way to overcome the serial ports issue. But I've only got an Adafruit Metro M0 express. Reckon it will work better than UNO? I believe there's a way to set multiple serial ports on Metro M0. (Please excuse if my wordings aren't correct, English is not my first language).

I want to ensure if the Mega will be able to run it before committing to buying one.

You can use Software Serial on your Uno to get an extra serial port.

@ezrax123 apologies for my short reply earlier, i was using a phone screen.

With an UNO, you can create a software serial port that's good for 9600 baud - maybe 19200. See the link that @JohnLincoln provided.

Change your node.begin() call to use the new software serial port and it should work fine.

That is corrent.
Use Serial1.begin() to setup the serial port on the TX and RX pins.
You need to set the speed and protocol. The meter uses even parity
Serial1.begin(9600, SERIAL_8E1)

Thank you very much! Had a read through SoftwareSerial.

Just a quick clarification-
When introducing another serial port, such as Serial1,
In the 'loop' section, would the code change from the following:

if(data_register[i] == 0x0BD4){
Serial.print("Volatge: ");
reading = *((float *)data);
Serial.print(reading);
Serial.println(" Volt");
}

to

if(data_register[i] == 0x0BD4){
Serial.print("Volatge: ");
reading = *((float *)data);
Serial1.print(reading);
Serial.println(" Volt");
}

or are there any other changes to be made?

Use Serial to print to the serial monitor.
Use Serial1 to talk on the Modbus.

1 Like

Hmm, not sure if I understand that. So to read the value off, basically reading- would be done through Serial1? Or would I just be using Serial1 in my 'setup' bit to talk to the energy meter.

Would my circuit still be the same- RS485 a and b connected to pins 10 and 11 (considering they are the set Serial1 rx, tx) through a TTL convertor (MAX485)).

For now, I think there's something wrong with my mcu considering it's not even running a basic blink. But that's solvable.

Before we go any further, which board will you be using, Metro M0, Mega 2560, Uno or other?

I was originally using Arduino Uno Rev 3 (the code I mentioned above is written for/tested with Uno).

I was advised and given a Adafruit Metro ESP32-S2 ( Adafruit Metro ESP32-S2 | The Pi Hut) to play around with because it can have multiple serial ports (I was told Uno can't)

Not the M0?

No, thought I had an M0 as well- my mistake.