Modbus Master - Uno - Error - Help

Hi everyone,

I'm working on a project that requires to read some holding registers from a Modbus RTU Slave.

Right now i'm using Arduino Uno R3, the C25B TTL to RS485 module and a ABB M1M Meter with Modbus RTU communication (Addres 1, Parity No, Stop Bits 1-2).

The serial monitor indicates error E0, wich according to the library ( Modbus Master Library )

static const uint8_t ModbusMaster::ku8MBInvalidSlaveID = 0xE0
ModbusMaster invalid response slave ID exception.

But, the slave actually shows on display "Trans" during the modbus intent of reading... The register i wan to read has the address 40103, its a float value.

The wiring is:

Arduino UNO - 5 to C25B - RO
Arduino UNO - 6 to C25B - DI
Arduino UNO - 9 to C25B - RE
Arduino UNO - 10 to C25B - DE
Arduino UNO - 5V to C25B - VCC
Arduino UNO - GND to C25B - GND

The code i'm working on, is this:


#include <ModbusMaster.h>
#include <SoftwareSerial.h>

#define MAX485_RE_NEG  9
#define MAX485_DE      10

//define the rx and tx for Serial1
const byte rxPin =5;
const byte txPin =6;

SoftwareSerial Serial1 (rxPin, txPin); //Define another Serial channel, to use the main for debuggin
ModbusMaster node; // Define a ModbusMaster object called 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);

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

  Serial.begin(9600);
  Serial1.begin(9600); //Define both serial channels at 9600 bps

  node.begin(1, Serial1); //Start the serial comm over node object, with Serial1...

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

void loop()
{
  uint8_t ResultadoLectura;
  ResultadoLectura = node.readHoldingRegisters(0x40103, 8); //Read the 40103 address and 8 registers ahead
  if (ResultadoLectura == node.ku8MBSuccess)
  {
    Serial.print("\nReading in holding registers: ");
    Serial.println(node.getResponseBuffer(0));
  }
  else {
    Serial.print("\nConnection error: ");
    Serial.print(ResultadoLectura, HEX); 
    Serial.print(" , ");
    Serial.println( ResultadoLectura); 
  }

  delay(3000);
}

Can anyone see something that i'm missing?

Thanks for your support, have a great day

I finally could read some holding registers from the modbus rtu slave, this is what i learn:

  1. Yes you can use another serial port (with software serial in my case), but this one only can run as SERIAL_8N1 (default) config: 8 Bit, None parity, 1 stop bit. If not, you have to use hardware serial and specific that config. (It was a problem first for debuggin processes)

  2. The holding register adress should be the address - first register of the device / modbus protocol standar > In mi case, required data address 40157, first register 40001, so this library (ModbusMaster) need the 156 address, on HEX. (0x009C)

  3. In my case, if your device puts the data (Eg. Line frequency = 60.00 , a float) into two 16 bit registers, you need to read 2 16 bit registers, because if you only want to read 1, my device replies Illegal Data Value.

  4. Finally when you red the 2 16 bit values, consider that if the manufacturer is ABB and the value is on "float" format, according to the user manual, you need to print it considering the 2, 16 bit high word and low word format, to clearly verify its whole physical-communication reading process... (This could be in the inverse way, first low word and then high word).

And this is the code that works by now:

 
#include <ModbusMaster.h>
#include <SoftwareSerial.h>

#define MAX485_RE_NEG  2
#define MAX485_DE      3

//define the rx and tx for Serial1
const byte rxPin =5;
const byte txPin =6;

SoftwareSerial Serial1 (rxPin, txPin); //Define another Serial channel, to use the main for debuggin
ModbusMaster node; // Define a ModbusMaster object

void preTransmission()
{
  digitalWrite(MAX485_RE_NEG, 1); 
  digitalWrite(MAX485_DE, 1);
  delay(15); 
}

void postTransmission()
{
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);
  delay(15);
}

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

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

  Serial.begin(9600);
  Serial1.begin(9600); //Define both serial channels at 9600 bps

  node.begin(2, Serial1); //Start the serial comm over node object, with Serial1, Slave ID = 2...

  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);
  pinMode(LED_BUILTIN, OUTPUT); //LED BUILTIN operations just to check the output if you only have 1 Serial HW
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
}

void loop()
{
  uint8_t ResultadoLectura, j, toread;
  uint16_t data[10];
  uint32_t jdata;
  toread = 2;
  float f;
  
  ResultadoLectura = node.readHoldingRegisters(0x0086, toread); //Read
  delay(1500);
  if (ResultadoLectura == node.ku8MBSuccess)
  {
    Serial.println("\nReadings ");
    for (j = 0; j < toread ; j++)
    {
      Serial.println(">word in HEX");
      data[j] = node.getResponseBuffer(j);
      Serial.println(data[j], HEX);
      //f = *(float *)&data[j];
      //Serial.println(f);
    }
    Serial.println("\nReading ");
    memcpy(&f,data,4);
    Serial.println(f);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(1500);
  }
  else {
    Serial.print("\nConnection error: ");
    Serial.println(ResultadoLectura, HEX); 
    digitalWrite(LED_BUILTIN, LOW);
  }
}

Hope this help somebody someday.

1 Like

That's not the library which is wrong, it's the manufacturer which gives you a register number that is only correct for some PLCs which cannot handle different register types but have to differentiate by the register address range. If 156 is the value you used with ModbusMaster, then 156 is the actual register number that is transferred over Modbus.

This is an error of your specific device which the manufacturer should fix. This contradicts the Modbus standard.

Thanks for clearing this, my intention only was to share the expierence to make it work, as other people helped me sharing their experience too.

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