Problem with ModbusMaster library

I am experiencing a problem when trying to communicate with a Modbus slave device (ID 7) connected on Serial2 (UART#2 pin16 and pin17 of my Arduino Mega 2560).

This is what my code looks like (that's pretty much the example sketch provided with the library but specifying another Serial port to create the class object):

#include <ModbusMaster.h>

ModbusMaster node(2,7); //Create class object using Serial2


void setup()
{
  
  
  // initialize Modbus communication baud rate
  node.begin(9600);

}


void loop()
{
  static uint32_t i;
  uint8_t j, result;
  uint16_t data[6];
  
  i++;
  
  // set word 0 of TX buffer to least-significant word of counter (bits 15..0)
  node.setTransmitBuffer(0, lowWord(i));
  // set word 1 of TX buffer to most-significant word of counter (bits 31..16)
  node.setTransmitBuffer(1, highWord(i));
  // slave: write TX buffer to (2) 16-bit registers starting at register 0
  result = node.writeMultipleRegisters(0, 2);
  // slave: read (6) 16-bit registers starting at register 2 to RX buffer
  result = node.readHoldingRegisters(2, 6);
  // do something with data if read is successful
  if (result == node.ku8MBSuccess)
  {
    for (j = 0; j < 6; j++)
    {
      data[j] = node.getResponseBuffer(j);
    }
  }
}

Instead of receiving correct data, my Serial monitor receives unexpected characters.

I checked the Class implementation and noticed that in uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction) the request is transmitted to MBSerial which is hardcoded as Serial (at Global Variables definition)

That's the reason for receiving unexpected characters on Serial monitor. Is there any way to bypass this problem?

Thank you very much.

Are you able to get it to work on Serial0?

ModbusMaster node(7);

While MBSerial is a global variable, it is set to the correct serial port in ModbusMaster::begin(). Since you are using a 2560, which wasn't in existence when I wrote this code, it appears that the case statement does not properly set the serial port. Try changing line #119 in ModbusMaster.cpp:

from:

#if defined(__AVR_ATmega1280__)

to:

#if defined(__AVR_ATmega2560__)

and let me know if it works. If so, I will revise the code accordingly.

Rx

I updated the library to support other hardware besides the ATmega1280. You can try it out by downloading from GitHub (I'm in the process of moving the repo from Google Code):

Download: https://github.com/2-718/ModbusMaster/zipball/master
Source: https://github.com/2-718/ModbusMaster

Let me know how this works.

Rx

Hello!

I tried today your new version of ModbusMaster library. The conditional compilation macro works great and now I don't have problems addressing MBSerial to Serial2 of my Arduino Mega 2560.

For some reason I experienced problems receiving the response from the Modbus slave. Despite the fact you have the instruction MBserial.flush() before receiving the answer, I noticed that the first bytes of my received string did not make sense to me. It seemed as the CRC bytes of the request. I changed your code as follows:

uint8_t rxCtrl; //I declared this control variable

//right after transmitting the request:

rxCtrl = 0; //I initialized the variable
  
  // loop until we run out of time or bytes, or an error occurs
  u32StartTime = millis();
  while (u8BytesLeft && !u8MBStatus)
  {
    if (MBSerial.available())
    {
#if __MODBUSMASTER_DEBUG__
      digitalWrite(4, true);
#endif
    if (rxCtrl < 1)  // condition to discard unexpected bytes
    {
      u8ModbusADU[0] = MBSerial.read();
      rxCtrl++;
    }

    else
    {
      u8ModbusADU[u8ModbusADUSize++] = MBSerial.read();
    }
      u8BytesLeft--;
#if __MODBUSMASTER_DEBUG__
      digitalWrite(4, false);
#endif
    }
    else
    {
#if __MODBUSMASTER_DEBUG__
      digitalWrite(5, true);
#endif
      if (_idle)
      {
        _idle();
      }
#if __MODBUSMASTER_DEBUG__
      digitalWrite(5, false);
#endif
    }

Maybe I could use your u8BytesLeft variable instead of declaring a new one but now it works great!

Thank you!

Are you able to capture and post a conversation between your Arduino and Modbus slave device? Ideally, you would also capture status of pins 4 & 5 so we can use the debug trace the location within ModbusMaster::ModbusMasterTransaction. You should not have to drop the first byte in order for this to work properly.

Thanks.

Rx

Ok. Tomorrow or Tuesday I'll try to send you the conversation between Arduino and Modbus slave. When you say to capture the status of pin#4 and pin#5 what do you mean? To connect a LED and verify its status?

Thank you.

When I wrote the library, I used a Saleae Logic analyzer connected to the serial pins as well as 4&5 to trace the Modbus conversation. If you have the ability to match the debug pins with the conversation, it helps to see where we are within the transaction parsing code.

Rx

logic.png

Dear RX,

after a few tests I realized I was using the old ModbusMaster library but with the conditional compilation macro changed to #if defined(AVR_ATmega2560) . With the last version of your library I receive the data from the Modbus slave without any problem. I uploaded a screenshot with the request, the answer and the transaction result.

I am sorry for any inconvenience :blush: .

Thank you for your time!

Outstanding! I appreciate you bringing up the issue with the serial ports on the ATmega2560; I would not have otherwise known to update my conditional macros to support this device.

Let me know if you need any further assistance.

Rx

Dear Rx,
Can i get the library of MODBUS master. Pls send me the link from where i can download it

hello to all I am doing a project with arduino one and a screen HMI delta DOP-B07S411 in which I use an arduino one as master with the MODBUSMASTER library and the screen as a slave.

for arduino I use the ModbusMaster.h library and the code I use is.

/*

  RS485_HalfDuplex.pde - example using ModbusMaster library to communicate
  with EPSolar LS2024B controller using a half-duplex RS485 transceiver.

  This example is tested against an EPSolar LS2024B solar charge controller.
  See here for protocol specs:
  http://www.solar-elektro.cz/data/dokumenty/1733_modbus_protocol.pdf

  Library:: ModbusMaster
  Author:: Marius Kintel <marius at kintel dot net>

  Copyright:: 2009-2016 Doc Walker

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

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

/*!
  We're using a MAX485-compatible RS485 Transceiver.
  Rx/Tx is hooked up to the hardware serial port at 'Serial'.
  The Data Enable and Receiver Enable pins are hooked up as follows:
*/
#define MAX485_DE      3
#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 115200 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);
}

bool state = true;

void loop()
{
  uint8_t result;
  uint16_t data[6];

  // Toggle the coil at address 0x0002 (Manual Load Control)
  result = node.writeSingleCoil(0x0001, state);
  Serial.print("Error 1: ");
  Serial.println(result, HEX);
  state = !state;

  // Read 16 registers starting at 0x3100)
  result = node.readInputRegisters(0x4001, 1);
  if (result == node.ku8MBSuccess)
  {
    Serial.print("slider: ");
    Serial.println(node.getResponseBuffer(0x00));
  }
  else 
  {
  Serial.print("Error 2: ");
  Serial.println(result, HEX);
  }
  delay(1000);
}

but in no time managed to communicate with the screen the answer I receive is this.

for the HMI screen DOP-B07S411 I am programming it with the software DOPSoft (Version: 2.00.07 Build: 2.00.07.04) and the screen configuration is this.

and the configuration of the registers and contacts is shown in this video

the HMI screen brings a manual for the management of it in slave mode RTU I show you some screens and documentation.




I also uploaded a link to see how I have connected everything

I'm new here on the forum and I have a problem with Arduino UNO ... I'm testing a code to communicate with a datalogger through the Modbus RTU protocol over an rs232 port using a max3232 (RS232 / TTL). During the tests with the datalogger on the serial monitor it always returned a value of 226 and a pattern with squares, researching I found that these special characters is the baud rate ... I set the baud rate of both (Datalogger and code) to 9600 and still the error persisted.
The strange thing is that even disconnecting the arduino from the datalogger and leaving only the USB on the computer (of course ..) the error remains the same! I soon believe that there is a problem with the ModbusMaster library and UNO.

Note: I've already changed the 2x cable, reinstalled the IDE and also tested it with different versions but nothing worked

Please help me...