Arduino Modbus Master HELP PLEASE

Have a good day. I am new to Arduino coding. I tried many programs on the internet to get the kg information from the weight indicator I have and write it to the serial port, but I failed. I need help from those who have experience with Arduino modbus master. I have a ttl to rs485 converter MAX485. I was able to read the kg information from the computer with Modbus Poll. I would be glad if you help me with a program that will write the kg information to the Arduino serial port screen.

M02 User's manual - weighing.pdf (1.1 MB)




which Arduino exactly?

The Modbus Master Library from DocWalker is a good start.
Show us your wiring - we need to see to which Arduino pins you have connected to DI, RO, DE/RE

1 Like

It would also help if you posted the code you were using. Remember to place it between code tags otherwise it'll be hard to read and likely incur the wrath of the moderators :frowning_face:

1 Like

I have uno, nano and pro mini. I tried many programs related to Arduino uno. I usually connected DI, RO, DE/RE according to the pins in the codes I found. DE/RE is usually combined into a single pin. I did not share the codes because I could not run them. If I find a code that I think will work with corrections, I will share it. If you have a Modbus master program that reads records from only one address, could you share it? In the Modbus tool, I read kg as low and high from address dec 0 plc 40001.

Ok. When you post the code, we can use it as a starting point to figure out what's going on.

1 Like

something like that might work:

/*******************************************************

  Modbus Client Example D 485halfduplex

  This Modbus Client
  - reads registers from Modbus Servers periodically

  based on an idea or the (incorrect):
  RS485_HalfDuplex.pde - example using ModbusMaster library to communicate
  reading M02  using a half-duplex RS485 transceiver.

  hardware
  - a MAX485-TTL adapter

  by noiasca
  2024-10-27  https://forum.arduino.cc/t/arduino-modbus-master-help-please/1315703
  2022-07-31  OK - tested with Arduino MEGA

 *******************************************************/


/* *******************************************************
   Serial Interface
 * **************************************************** */
// if you don't have enough HW Serial (i.e. on an UNO)
// you are forced to use SoftwareSerial or AltSoftSerial
include <SoftwareSerial.h>
constexpr uint8_t rxPin = 2;                   // for Softserial
constexpr uint8_t txPin = 3;
SoftwareSerial mySerial(rxPin, txPin);

// On a Mega you can simply use
// a Reference to an existing HW Serial:
//HardwareSerial &mySerial = Serial3;

/* **************************************************** *
   Modbus
 * **************************************************** */
#include <ModbusMaster.h>                        // Modbus Master 2.0.0 by Doc Walker - install with Library Manager
constexpr uint8_t modbusEnablePin = 5;           // The GPIO used to control the MAX485 TX pin. Set to 255 if you are not using RS485 or a selfsensing adapter
constexpr uint32_t modbusBaud = 9600;            // use slow speeds with SoftSerial
constexpr uint16_t modbusRestTx = 15000;         // rest time between transmissions - microseconds
uint32_t modbusPreviousTx = 0;                   // timestamp of last transmission - microseconds
ModbusMaster serverA;                            // instantiate ModbusMaster object - slave - node

// this function will be called before the client transmits data
void preTransmission()
{
  while (micros() - modbusPreviousTx < modbusRestTx)   // check last transmission end and wait if the call was to early
  {
    yield();                                           // wait some time and allow background tasks
  }
  digitalWrite(modbusEnablePin, HIGH);
}

// this function will be called after the transmission
void postTransmission()
{
  digitalWrite(modbusEnablePin, LOW);
  modbusPreviousTx = micros();         // remember last timestamp
}

// do all the settings for the Modbus
void modbusInit()
{
  mySerial.begin(modbusBaud);                     // initialize Modbus communication baud rate
  serverA.begin(1, mySerial);                     // communicate with Modbus server ID over the given Serial interface
  pinMode(modbusEnablePin, OUTPUT);               // Init enable pins for modbus master library
  digitalWrite(modbusEnablePin, LOW);
  serverA.preTransmission(preTransmission);       // Callbacks allow us to configure the RS485 transceiver correctly
  serverA.postTransmission(postTransmission);
}

// getdata from Modubs Server(Slave) and print to Serial
void requestData()
{
  constexpr uint16_t interval = 5000;             // interval of modbus requests
  static uint32_t previousMillis = -interval;     // timestamp of last request
  uint32_t currentMillis = millis();

  if (currentMillis - previousMillis > interval)  // set the interval in ms
  {
    previousMillis = currentMillis;
    uint16_t reg = 0x0;
    int result;
    result = serverA.readInputRegisters(reg, 2);  // request from startregster, n Registers
    if (result == serverA.ku8MBSuccess)           // do something if read is successfull
    {
      Serial.print(F("LOW :     ")); Serial.println(serverA.getResponseBuffer(0x00));
      Serial.print(F("High:     ")); Serial.println(serverA.getResponseBuffer(0x01));
     }
    else
    {
      Serial.print(F(" ServerA no success register ")); Serial.print(reg, HEX); Serial.print(F(" result=")); Serial.println(result, HEX);
    }
  }
}

/* **************************************************** *
   setup and loop
 * **************************************************** */

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Modbus Client Example D 485 halfduplex"));

  modbusInit();
}

void loop()
{
  requestData();
}

but it would have been far easier for you if you had provided the information I asked for.

1 Like

I tried your code with the connections below. I tried the Modbus connection with (A-A--B-B) and (A-B--B-A), but I couldn't get any output.

I found this code from the site below but I couldn't edit it according to my weight indicator. Can you help me with this? I just want to read the kg data at address 40001 according to dec 0, hex 0, plc address. 3 different data are read in this code. I added the weight indicator user manual.

M02 User's manual - weighing.pdf (1.1 MB)

// github link: https://github.com/4-20ma/ModbusMaster
#include <ModbusMaster.h>

/* Modbus stuff */
#define MODBUS_DIR_PIN  5 // connect DR, RE pin of MAX485
#define MODBUS_RX_PIN 0 // Rx pin  
#define MODBUS_TX_PIN 1 // Tx pin 
#define MODBUS_SERIAL_BAUD 9600 // Baud rate for modbus rtu communication

// voltage, current and frequency register of Energy Meter
// if you want to read more parameters, then increase the array size
//and, write the address
uint16_t data_register[3] = {0x0000, 0x0008, 0x0036};

//Initialize the ModbusMaster object as node
ModbusMaster node;

// Pin 4 made high for Modbus transmision mode
void modbusPreTransmission()
{
  delay(500);
  digitalWrite(MODBUS_DIR_PIN, HIGH);
}

// Pin 4 made low for Modbus receive mode
void modbusPostTransmission()
{
  digitalWrite(MODBUS_DIR_PIN, LOW);
  delay(500);
}

void setup() {
  //we initialize the built-in hardware serial communication 
  //using the Serial.begin() function with two parameters.
  //The first parameter is the desired baud rate (9600 bits per second), 
  //and the second parameter is SERIAL_8E1, 
  //which specifies the data format (8 data bits, even parity, and 1 stop bit).
  //to set these two parameter, please read your sensor datasheet first
  Serial.begin(9600, SERIAL_8E1);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  pinMode(MODBUS_DIR_PIN, OUTPUT);
  digitalWrite(MODBUS_DIR_PIN, LOW);

  //modbus device slave ID 14
  node.begin(14, Serial);

//  callbacks allow us to configure the RS485 transceiver correctly
   node.preTransmission(modbusPreTransmission);
   node.postTransmission(modbusPostTransmission);
}

void loop()
{
    uint8_t result;
    //for store 32-bit data
    uint16_t data[2];
    int i;
    float reading;
    // this loop is to read voltage, current and power factor register of Energy Meter
    for(i=0; i<=2; i++){
      //Modbus function code (0x04) Read Input Registers according to energy meter datasheet
      result = node.readInputRegisters(data_register[i], 1);
     
        if (result == node.ku8MBSuccess) {
          Serial.println("Success, Received data: ");

          //Retrieve the data from getResponseBuffer(uint8_t u8Index) function.
          //that is return 16-bit data. our energy meter return 32-bit data everytime.
          //that's why, we take the value to a array called data
           data[0]=node.getResponseBuffer(0x00);
           data[1]=node.getResponseBuffer(0x01);
          
           //read voltage
           if(data_register[i] == 0x0000){
            Serial.print("Volatge: ");
            reading = *((float *)data);
            Serial.print(reading);
            Serial.println(" Volt");
           }
           //read current
           if(data_register[i] == 0x0008){
            Serial.print("Current: ");
            reading = *((float *)data);
            Serial.print(reading);
            Serial.println(" Amps");
           }
           //read Frequency
           if(data_register[i] == 0x0036){
            Serial.print("Frequency: ");
            reading = *((float *)data);
            Serial.print(reading);
            Serial.println(" Hz");
           }
        } else {
          Serial.print("Failed, Response Code: ");
          Serial.print(result, HEX);
          Serial.println("");
          delay(5000); 
        }
      
    }
  //one second delay
    delay(1000);
  }

Mixing the modbus and the printout on one Serial is not the best idea.
You could use SoftSerial with Pin 2 and 3 as in my sketch. and use HW-Serial (0, 1) for the debug infomation to Serial Monitor.

doesn't tell much.
If you don't see ANY output on the Serial Monitor - your wiring might be faulty.
You MUST be able see the Serial.println from setup().

1 Like

Actually, this is the output I got

Weight indicator settings

slave adres 1
b rtu
8-n-1
Lo-Hı

you find all errorcodes in the ModbusMaster.h

E2 is

/**
ModbusMaster response timed out exception.

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

@ingroup constant
*/

The master doesn't receive an answer.

I suspect a wrong wiring not fitting to the code.
Do you understand now why I ask for pictures?!?

2 Likes

I made the connections like this. I couldn't find where I made a mistake. I didn't know if the weight indicator modbus settings were suitable for this code or not. I changed the settings and tried again and again. Thank you for your help.

Weight indicator settings

slave adres 1
115200
b rtu
8-n-1
Lo-Hı

M02 User's manual - weighing.pdf (1.1 MB)

What is the 115200 value in your weight indicator settings? Is that the baud rate of your RS485 port?

Way back in post #1 one of your screenshots indicated that it was 9600.

1 Like

Could you drop the baud rate back to 9600 and try the code on post #6 . Rx on 2 and Tx on 3 like that code defines.
Abandon your will to use pins 0 and 1 for now.

1 Like

Yes, the baut rate of the RS485 port. I tried both for your code. I can change the modbus settings with the F2 parameters in the weight indicator.

I did what you said and the result was like this

slave adres 1
9600
b rtu
8-n-1
Lo-Hı

Result 1 means illegal function exception. That means you have response from your device.
Replace this line: result = serverA.readInputRegisters(reg, 2);
with
result = serverA.readHoldingRegisters(reg, 2);

2 Likes

Yes it worked. Thanks for your help. How can we increase the scanning speed? Data does not come instantly. Rows come very late. When I press the loadcell in reverse - signed numbers appear as numbers with 65555 on the serial port. - How can I print signed numbers as 0?

try 1000 for example

1 Like