Help with ModBus RTU Master-Slave: SimpleModbus [SOLVED]

Hello,

I want to read data from a DC 1040 PID Controller, with my Arduino and I am using RS485-TTL module . I'am using a simple modbus master library it's default communication is :

Protocol: MOdBUS RTU
Baud Rate: 38400
Parity: ODD
Stop Bits: 1
Data Bits: 8

I want to read PV Value which is register 138.

this is my code....

#include <SimpleModbusMaster.h>
//////////////////// Port information ///////////////////
#define baud 38400
#define timeout 1000  
#define polling 300 // the scan rate
#define retry_count 50

// used to toggle the receive/transmit pin on the driver
#define TxEnablePin 2 

// The total amount of available memory on the master to store data
#define TOTAL_NO_OF_REGISTERS 13

// This is the easiest way to create new packets
// Add as many as you want. TOTAL_NO_OF_PACKETS
// is automatically updated.
enum
{
  PACKET1,
  PACKET2,
  PACKET3,
  PACKET4,
  TOTAL_NO_OF_PACKETS // leave this last entry
};

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

// Masters register array
unsigned int regs[TOTAL_NO_OF_REGISTERS];

void setup()
{
  // Initialize each packet
  Serial.begin(38400);
  
  modbus_construct(&packets[PACKET1], 1, READ_HOLDING_REGISTERS,138, 1, 10);
 // modbus_construct(&packets[PACKET2], 1, READ_HOLDING_REGISTERS, 0000, 1, 11);
  //modbus_construct(&packets[PACKET4], 1, READ_HOLDING_REGISTERS, 1, 1, 12);
  //modbus_construct(&packets[PACKET1], 1, PRESET_MULTIPLE_REGISTERS,1, 1,0);
  
  // Initialize the Modbus Finite State Machine
  modbus_configure(&Serial, baud, SERIAL_8O1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs);
  
  
}

void loop()
{
  modbus_update();
  float pv;
  pv = regs[10];

  delay(1000);
  Serial.print("requests: ");    
  Serial.println(packets[PACKET1].requests);
  Serial.print("successful_requests: ");  
  Serial.println(packets[PACKET1].successful_requests);
  Serial.print("failed_requests: ");  
  Serial.println(packets[PACKET1].failed_requests);  
  Serial.print("exception_errors: ");  
  Serial.println(packets[PACKET1].exception_errors); 
  Serial.print("pv: ");  
  Serial.println(regs[10]);                          
}

The following attachment include connection made, datasheet, comm regs mapping,output

DC1040.pdf (855 KB)

COMMUNICATION MANUAL.pdf (380 KB)

just as a quick tipp: in the manual page 27 you find

PV
Process Value
008A 138 03H -1999~9999

on page

03 (03H) Reading multiple registers value from slave controller

in the pdf of the library you will find following information:

Function 4 - READ_INPUT_REGISTERS 4 // Reads the binary contents of input registers (3X references) in
the slave. Not writable.

therefore I guess your modbus_construct is wrong.

I change the construct in my code ...

#include <SimpleModbusMaster.h>[color=#222222][/color]
//////////////////// Port information ///////////////////[color=#222222][/color]
#define baud 38400[color=#222222][/color]
#define timeout 1000  [color=#222222][/color]
#define polling 300 // the scan rate[color=#222222][/color]
#define retry_count 50[color=#222222][/color]
[color=#222222][/color]
// used to toggle the receive/transmit pin on the driver[color=#222222][/color]
#define TxEnablePin 2 [color=#222222][/color]
[color=#222222][/color]
// The total amount of available memory on the master to store data[color=#222222][/color]
#define TOTAL_NO_OF_REGISTERS 13[color=#222222][/color]
[color=#222222][/color]
// This is the easiest way to create new packets[color=#222222][/color]
// Add as many as you want. TOTAL_NO_OF_PACKETS[color=#222222][/color]
// is automatically updated.[color=#222222][/color]
enum[color=#222222][/color]
{[color=#222222][/color]
  PACKET1,[color=#222222][/color]
  PACKET2,[color=#222222][/color]
  PACKET3,[color=#222222][/color]
  PACKET4,[color=#222222][/color]
  TOTAL_NO_OF_PACKETS // leave this last entry[color=#222222][/color]
};[color=#222222][/color]
[color=#222222][/color]
// Create an array of Packets to be configured[color=#222222][/color]
Packet packets[TOTAL_NO_OF_PACKETS];[color=#222222][/color]
[color=#222222][/color]
// Masters register array[color=#222222][/color]
unsigned int regs[TOTAL_NO_OF_REGISTERS];[color=#222222][/color]
[color=#222222][/color]
void setup()[color=#222222][/color]
{[color=#222222][/color]
  // Initialize each packet[color=#222222][/color]
  Serial.begin(38400);[color=#222222][/color]
  [color=#222222][/color]
  modbus_construct(&packets[PACKET1], 1, READ_MULTIPLE_REGISTERS,138, 1, 10);[color=#222222][/color]
 [color=#222222][/color]
  // Initialize the Modbus Finite State Machine[color=#222222][/color]
  modbus_configure(&Serial, baud, SERIAL_8O1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs);[color=#222222][/color]
  [color=#222222][/color]
  [color=#222222][/color]
}[color=#222222][/color]
[color=#222222][/color]
void loop()[color=#222222][/color]
{[color=#222222][/color]
  modbus_update();[color=#222222][/color]
  float pv;[color=#222222][/color]
  pv = regs[10];[color=#222222][/color]
[color=#222222][/color]
  delay(1000);[color=#222222][/color]
  Serial.print("requests: ");    [color=#222222][/color]
  Serial.println(packets[PACKET1].requests);[color=#222222][/color]
  Serial.print("successful_requests: ");  [color=#222222][/color]
  Serial.println(packets[PACKET1].successful_requests);[color=#222222][/color]
  Serial.print("failed_requests: ");  [color=#222222][/color]
  Serial.println(packets[PACKET1].failed_requests);  [color=#222222][/color]
  Serial.print("exception_errors: ");  [color=#222222][/color]
  Serial.println(packets[PACKET1].exception_errors); [color=#222222][/color]
  Serial.print("pv: ");  [color=#222222][/color]
  Serial.println(regs[10]);                          [color=#222222][/color]
}       [color=#222222][/color]

Still no output.......

please correct me.

I change my construct in my code..

#include <SimpleModbusMaster.h>
//////////////////// Port information ///////////////////
#define baud 38400
#define timeout 1000  
#define polling 300 // the scan rate
#define retry_count 50

// used to toggle the receive/transmit pin on the driver
#define TxEnablePin 2 

// The total amount of available memory on the master to store data
#define TOTAL_NO_OF_REGISTERS 13

// This is the easiest way to create new packets
// Add as many as you want. TOTAL_NO_OF_PACKETS
// is automatically updated.
enum
{
  PACKET1,
  PACKET2,
  PACKET3,
  PACKET4,
  TOTAL_NO_OF_PACKETS // leave this last entry
};

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

// Masters register array
unsigned int regs[TOTAL_NO_OF_REGISTERS];

void setup()
{
  // Initialize each packet
  Serial.begin(38400);
  
  modbus_construct(&packets[PACKET1], 1, READ_MULTIPAL_REGISTERS,138, 1, 10);
 
  // Initialize the Modbus Finite State Machine
  modbus_configure(&Serial, baud, SERIAL_8O1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs);
  
  
}

void loop()
{
  modbus_update();
  float pv;
  pv = regs[10];

  delay(1000);
  Serial.print("requests: ");    
  Serial.println(packets[PACKET1].requests);
  Serial.print("successful_requests: ");  
  Serial.println(packets[PACKET1].successful_requests);
  Serial.print("failed_requests: ");  
  Serial.println(packets[PACKET1].failed_requests);  
  Serial.print("exception_errors: ");  
  Serial.println(packets[PACKET1].exception_errors); 
  Serial.print("pv: ");  
  Serial.println(regs[10]);                          
}

Please correct me if anything else..

Hello All,

I am facing trouble with interfacing Selec Panel Meter MFM376C with RS485 Modbus. Somebody please help me out.

Microcontroller - Arduino Mega 2560
Panel Meter - MFM376C
Library - SimpleModbusMaster V2.2

Connections are done like -

Set the slave device as per mentioned configuration
Panel Meter - Selec MFM376C
Baud Rate - 19200
Bits,Parity,Stop bits - 8N1 (8Bits, No Parity, Stop bit 1)
Slave ID - 5
RS485 Pin - 7 +Ve, 14 -Ve

Conversion Module
RS485 to RS232 Conversion Module
VCC - External Stable Power 5V DC
GND - Common with all circuit
A - Connected to 7 MFM376C (+Ve)
B - Connected to 14 MFM376C (-Ve)
DI - Arduino TX1 Pin
RO - Arduino RX1 Pin
DE - RO - Connected together attached to one digital pin of Arduino 22

The code -

//Main header file for operation
#include <SimpleModbusMaster.h>

//Inititalize the modbus communication parameters
#define Baud_Rate 19200 //Baud rate for the Sslave
#define Time_Out 1000 //Time out for the Slave
#define Polling 100 //Number of times data retreival for Slave
#define Retry_Count 10 //Retry count for failures of Slave
#define RX_TX_Enable 22 //Toggling pin for the data retreival & transmission

//Initialize the master device configurations
#define Total_Registers 1 //Total number of registers data reads

//Packet configuration
enum
{
Packet_1,
Total_Packets //Total number of packets created
};

//Create an array of Packets to be configured
Packet Packets[Total_Packets];

//Defining the data storage array in master
unsigned int Data[Total_Registers];

//Variables for normal Arduino operations
long Old_Time = 0; //Storing the millisec for the last phase
long Wait_Time = 1200; //Defines the wait before the next printing
unsigned long Curr_Time; //Defines the current millisec

//Setting up the Arduino
void setup()
{
//Configuring the serial communication
Serial.begin(9600);
Serial.println("MODBUS Testing");

//Inititalizing the packet
//Packet Identity, Slave ID, Operation Code, Address of register, No of register, Local start ID
modbus_construct(&Packets[Packet_1], 5, READ_HOLDING_REGISTERS, 0x3903, 2, 0);

// Initialize the Modbus Finite State Machine
modbus_configure(&Serial1, Baud_Rate, SERIAL_8N1, Time_Out, Polling, Retry_Count, RX_TX_Enable, Packets, Total_Packets, Data);
}

void loop()
{
modbus_update();

float Active_Power;
unsigned long Temp_Val = (unsigned long)Data[1] << 16 | Data[0];
Active_Power = (float)&Temp_Val;

Curr_Time = millis();
if (Curr_Time - Old_Time >= Wait_Time)
{
Serial.print("Exception errors: ");
Serial.println(Packets[Packet_1].exception_errors);

Serial.print("Failed requests: ");
Serial.println(Packets[Packet_1].failed_requests);

Serial.print("Successful requests: ");
Serial.println(Packets[Packet_1].successful_requests);

Serial.print("Low byte: ");
Serial.println(Data[0]);

Serial.print("High byte: ");
Serial.println(Data[1]);

Serial.print("Active_Power ");
Serial.println(Active_Power);
Serial.println("----------------------------------");

Old_Time = Curr_Time;
}
}

Now I am frustated trying all the options, please please please help me out.

a)

GND - Common with all circuit

please check twice:
to the MEGA?
to the RS485 module ?
to your slave device ?
to your external Power device ?

b)
What result do you get on the Serial Monitor?

c)
Additionally, please provide a link to the datasheet of your device.

Thanks Noiasca,

Apologies I mentioned a wrong panel meter, actual meter that I have connected is EM6430. Datasheet is available in the below link

I have made all the ground terminals common except the slave device, because it’s a electrical panel meter and I donot have a separate ground for it.

Can you please explain how do I make ground common with the panel meter. If it is actually needed?

In the serial terminal I see that failed requests increases and the high byte value also increases and then it overflows. Attached error pic.

I could read the values using my USB to RS485 module in pc via demo software, I checked the resistance across A&B of the usb module it shows nothing in this case but when

I checked the resistance across the A&B of the RS485 to RS232 module it shows 120Ohms. Can this be a reason?

Can you check if I have mentioned the address correctly or it should be some different formats.

if the panel doesn't have ground on RS485, just use two wire connection A&B. If it is missing you can't connect the ground - in this particular case it should be ok.

What I see from your code, these two parts do not fit together:

#define Total_Registers 1      //Total number of registers data reads

versus

 //Packet Identity, Slave ID, Operation Code, Address of register, No of register, Local start ID
  modbus_construct(&Packets[Packet_1], 5, READ_HOLDING_REGISTERS, 0x3903, 2, 0);

If you check the datasheet register 0x3903 is a float so you have to read 4 bytes. You will need:

#define Total_Registers 4      //Total number of registers data reads

and

 //Packet Identity, Slave ID, Operation Code, Address of register, No of register, Local start ID
  modbus_construct(&Packets[Packet_1], 5, READ_HOLDING_REGISTERS, 0x3903, 4, 0);

This alone will not solve your problem, but has to be correct also (and might help to solve the jumping value of your high byte).

There should be a termination resistance on both sides/end of the line - on your meter and the RS485 module.

As you mentioned, that you are able to read with the PC, there might be an issue in your hardware-wiring which we can't check. Please make a very good picture of your setup where we can see clearly each connection from Mega to RS485 - to your slave. Double check the proper RX/TX lines on the MEGA - I had already cheap MEGA clones where the labeling of RX/TX were wrong.

P.S.: if you copy Serial Output to this board, don't make screenshots, just CTRL-C/CTRL-V will do the same. To make your postings more readable, post code - and Serial Output in Code-Tags

Thanks Noiasca,

The Serial Monitor Output after making the following changes as you suggested:


MODBUS Testing
Exception errors: 0
Failed requests: 4
Successful requests: 0
Low byte: 0
High byte: 0
Active_Power 0.00

Exception errors: 0
Failed requests: 8
Successful requests: 0
Low byte: 0
High byte: 0
Active_Power 0.00

Exception errors: 0
Failed requests: 10
Successful requests: 0
Low byte: 0
High byte: 0
Active_Power 0.00

Note: External Power Supply, RS485 Module and Arduino Mega has common ground.
Termination Resistance has been attached at both ends: RS485 has its own termination resistance and Panel Meter has 120ohms attached externally.


After doing all these I tried with the below-mentioned code:

#include <ModbusMaster.h>
#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 19200 baud
Serial1.begin(19200);
Serial.begin(19200);

// Modbus slave ID 1
node.begin(5, Serial1);
// Callbacks allow us to configure the RS485 transceiver correctly
node.preTransmission(preTransmission);
node.postTransmission(postTransmission);
}
bool state = true;
void loop()
{
uint8_t result;
uint32_t data[6];

// Toggle the coil at address 0x0002 (Manual Load Control)
//result = node.writeSingleCoil(0x0003, state);
//state = !state;
// Read 16 registers starting at 0x3100)
result = node.readHoldingRegisters(3900, 30);
if (result == node.ku8MBSuccess)
{
Serial.println("---------------------------------------------");
Serial.print("Frequency: ");
Serial.println(node.getResponseBuffer(15)/100.0f);
Serial.print("L - N Voltage: ");
Serial.println((node.getResponseBuffer(11)+node.getResponseBuffer(12))/100.0f);
Serial.print("V1 - N Voltage: ");
Serial.println(node.getResponseBuffer(27)/100.0f);
}
delay(1000);
}

And the Serial Monitor Output shows:


Frequency: 169.68
L - N Voltage: 402.10
V1 - N Voltage: 172.67

Frequency: 169.68
L - N Voltage: 402.10
V1 - N Voltage: 172.67

Frequency: 169.68
L - N Voltage: 402.10
V1 - N Voltage: 172.67

Frequency: 169.68
L - N Voltage: 402.10
V1 - N Voltage: 172.67

Frequency: 169.68
L - N Voltage: 402.10
V1 - N Voltage: 172.67

Frequency: 169.68
L - N Voltage: 402.10
V1 - N Voltage: 172.67

Frequency: 169.68
L - N Voltage: 402.10
V1 - N Voltage: 172.67

Frequency: 169.68
L - N Voltage: 402.10
V1 - N Voltage: 172.67

It's getting communicated properly, because whenever I am changing baud-rate, parity or stop bit in the Panel Meter, immediately the output is stopped. And again after correcting the changes, the output gets resumed. But the output which I am getting is completely different from the one showing in the display.

Note: In this connection, no termination resistance has been used, and all grounds are made common. And the connection diagram is shown in the attached image.

Kindly help me out.

Now using the library modbus master and doing some circuitry tweaking I could connect the slave but not getting the desired value.

For frequency it should be 50, but I am receiving 16968. node.getResponseBuffer(15) might needs some data conversion?

Can some one help.

a) I see in your new code

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

Based on the drawing you made it's clear for me why simplemodbus is not working. Simplemodbus handles only one enable PIN. So if you want to use simplemmodbus, you have to connect DE/RE to one PIN (by the way this is for me anyway the preferable way then handle two pins in the same time).

b) check the datasheet. Register 3900 + 15 for frequency is definied as float. So you will need to read 2 (or 4) bytes and 3915/3916/3917/3918 and combine them to a proper value. I don't understand why the manual sometimes says 2 bytes. For me float is 4 bytes. Even the Intervall between some values are 2 byte, some are 4bytes, so what ever the manufacturer thought how to encode this values - good luck :wink:

i have an error on simplemodbus i am connecting pm710 with arduino uno.
the error which i have is this.

SimpleModbusMasterArduino:141:70: error: 'modbus_construct' was not declared in this scope

modbus_construct(packet1, 1, READ_HOLDING_REGISTERS, 0, 1, readRegs);

^

SimpleModbusMasterArduino:171:119: error: too many arguments to function 'void modbus_configure(long int, unsigned int, unsigned int, unsigned char, unsigned char, Packet*, unsigned int)'

modbus_configure(&Serial, baud, SERIAL_8N2, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS);

^

In file included from C:\Documents\Arduino\libraries\SimpleModbusMasterV12\examples\SimpleModbusMasterArduino\SimpleModbusMasterArduino.ino:1:0:

C:\Documents\Arduino\libraries\SimpleModbusMaster/SimpleModbusMaster.h:143:6: note: declared here

void modbus_configure(long baud, unsigned int _timeout, unsigned int _polling,

^

C:\Documents\Arduino\libraries\SimpleModbusMasterV12\examples\SimpleModbusMasterArduino\SimpleModbusMasterArduino.ino: In function 'void loop()':

SimpleModbusMasterArduino:178:17: error: too few arguments to function 'unsigned int modbus_update(Packet*)'

modbus_update();

^

In file included from C:\Documents\Arduino\libraries\SimpleModbusMasterV12\examples\SimpleModbusMasterArduino\SimpleModbusMasterArduino.ino:1:0:

C:\Documents\Arduino\libraries\SimpleModbusMaster/SimpleModbusMaster.h:142:14: note: declared here

unsigned int modbus_update(Packet* packets);

^

Multiple libraries were found for "SimpleModbusMaster.h"
Used: C:\Documents\Arduino\libraries\SimpleModbusMaster
Not used: C:\Documents\Arduino\libraries\SimpleModbusMasterV2rev2
Not used: C:\Documents\Arduino\libraries\SimpleModbusMasterV12
exit status 1
'modbus_construct' was not declared in this scope

Good Morning,
Using the simplemodbusmaster library it is possible to use this packet format so that I can use the maximum register (28), in this small test when I execute only first line connection ok, reading ok, when I run the two lines, OK connection, NOK reading , displays zero values.

  modbus_construct(&packets[PACKET1], 10, READ_HOLDING_REGISTERS, 1024, 8, 10);
  modbus_construct(&packets[PACKET1], 10, READ_HOLDING_REGISTERS, 1038, 6, 19);

visualizing the code I noticed that the records run through an array, but I'm not sure how the packages work on this occasion.
Another detail I'm using STM32F103 (BluePill), with some changes I made the library functional, if anyone interested.

hallo all, im noob, just want ask something,

  1. modbus_construct(&packets[PACKET1], 1, READ_HOLDING_REGISTERS, 0, 6, 0) --> i read from simplemodbusmaster guide ... how i can get "1" ? its declare how many slave?

  2. 0,6,0--> please explain that number , where it come ?

  3. regs [0] what that mean ? why people put different number? it declare some thing at whole coding?

i m trying understand this structure and so many people post code with different number so confusing

thanks ....

following page 2 and 9 in SimpleModbusMasterManual.pdf for your example

the first parameter is the packet pointer
1, ... the slaves modbus adress
READ_HOLDING_REGISTERS, ... the function you use to access the register on your device
0, ... start adress where you start reading
6, ... how many bytes do you want to read
0 ... the start byte of your holding register (where to store the received data)

to set this parameters correct it is essential to have a datasheet available of your slave wherein you have detailed information about

  • how to set up the device adress,
  • what registers are available
  • using which function,
  • and how the data is encoded

hallo again,

I dont know this is repost or not, my reply didnt shown at my computer

following tk4s communication address as below :

Im trying read PV @ input_register_address

  1. it said address 17 from master, but at colum it writen 11H, which one is slave modbuss address ?

  2. Start address is 1000? im counting 3001001 - 300001 = 1000 or 3E8, should I use 0x1000 or 0x3E8 ?

  3. About how many byte, i must count all byte from slave address, data, function until CRC so its 8 byte ? or only need 1 byte for read data only ?

  4. start byte og input register is 300001 so it will 1 ?

  5. regarding #define TOTAL_NO_OF_REGISTERS ( ? ) because i just read PV so it will be #define TOTAL_NO_OF_REGISTERS 1 ?

  6. TOTAL_NO_OF_REGISTERS will be declare at regs [1] ? since only read PV?

Thanks in advance

Hi Andrew,

Did you get this working?

Regards

Ian G

I am a beginner, does anyone have a modbus code example for powerlogic pm5350?
Please help me. thanks .

Hi guys,

I am trying to read DDM1000CTR 3 phase device over Modbus RTU and I am receiving 16323 as a value, but it should be float in kWh.
Please check attached image, it's software ShortBus Modbus Scanner I used to test and it works with proper configuration.

Please can someone help me with sample for arduino, how to setup same thing as on PC software.
I do not know how to swap byte order and read result as floating point.

Thanks

Hello Guys, As a fellow Arduinoist.

I need your advice, (Most especially from JuanB, Rockwallaby, Noiasca, or anyone with a reliable product)

I have devices with RS485 ports and MODBUS protocol. I want to be able to read and

write data from these devices from a remote site on a website. I have been reading through this thread for a

while now, I observed that few guys have been developing products (i hope for the market) for SCADA.

I don't have the time to develop my own and I don't want a product that is not flexible, I want a device that

will be programmable. With such a community, I believe you can help me.

Thanks