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?
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.
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):
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!
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.
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?
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.
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.
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.
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.
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