Arduino UNO R3 + MAX 485 ModBus protocol(and code Node.js)

Hello! Please, I need help :smiling_face_with_tear:. I only have an Arduino Uno and a MAX 485 converter. I need to communicate via modbus protocol. And to be more specific, so that the message from the Arduino Uno is sent to RS 485 and the sent data is shown in the code terminal (which is written in Visual Studio Code and written in Javascript). I connect the installation itself to my PC via a USB to RS485 converter. here are photos of how it's all connected




Here is the code written for Arduino Uno

#include <ModbusRTUSlave.h>

#define MODBUS_SLAVE_ID 5
#define MODBUS_REGISTER_START 0

#define RS485_TX 10
#define RS485_RX 11
#define DE_RE 2


ModbusRTUSlave modbus(Serial, DE_RE);

uint16_t ModbusData[4]; 

void setup() {
    Serial.begin(9600);
    modbus.begin(MODBUS_SLAVE_ID, 9600);
    modbus.configureHoldingRegisters(ModbusData, 4);
}

void loop() {
    float Data1 = 5;
    float Data2 = 7;


    Serial.print("Data 1: ");
    Serial.println(Data1);

    Serial.print(" Data 2: ");
    Serial.print(Data2);

    uint16_t* posPtr = (uint16_t*)&Data1;
    uint16_t* distPtr = (uint16_t*)&Data2;

    ModbusData[0] = posPtr[0];
    ModbusData[1] = posPtr[1];
    ModbusData[2] = distPtr[0];
    ModbusData[3] = distPtr[1];

    modbus.poll();
    delay(500);
}

And this is code written in Visual Studio Code in Node format.js for RS-485

const ModbusRTU = require('modbus-serial');
const client = new ModbusRTU();

const portName = 'COM3';
const baudRate = 9600;

client.connectRTUBuffered(portName, { baudRate: baudRate })
  .then(() => {
    console.log('Modbus connection open');

    client.setID(5);

    setInterval(() => {
      client.readHoldingRegisters(0, 4)
        .then(data => {
          const buffer = Buffer.alloc(8);
          buffer.writeUInt16LE(data.data[0], 0);
          buffer.writeUInt16LE(data.data[1], 2);
          buffer.writeUInt16LE(data.data[2], 4);
          buffer.writeUInt16LE(data.data[3], 6);

          const Data1 = buffer.readFloatLE(0);
          const Data2 = buffer.readFloatLE(4);

          console.log('Data received from Arduino:');
          console.log(`Data 1: ${Data1}`);
          console.log(`Data 2: ${Data2}`);
        })
        .catch(err => {
          console.error('Error reading Modbus data:', err.message);
        });
    }, 150);
  })
  .catch(err => {
    console.error('Error opening Modbus connection:', err.message);
  });

There are also screenshots of what is displayed in the Serial port and in the terminal



Here, I hope someone can help me with this problem :sweat_smile:

what is the problem? what does it or doesn't do?

thank you so much for being interested in my problem!:"D
the problem is that in the Node program.js does not send the data that I sent in the Arduino Uno code to RS-485. More precisely, it shows via USB that it receives something, but for some reason it does not want to reproduce it into the terminal itself and duplicate this information. It only stops at the message "Modbus connection open" and stands without sending any more information (although it should show the data sent to it from the Arduino Uno on the code)

i've written code to send/receive data over RS-485 but am not familiar with the library you're using.

such code, with 2 serial interfaces, would typically check for input on one interface and re-transmit what it receives on the other interface. i don't see that in your Arduino code

looks like you're repeatedly

  • setting the values of Data1 and 2
  • printing them on the serial monitor
  • setting posPtr and distPtr to the locations of Data 1 and 2
  • setting values in ModbusData [] to the values of the ptrs

all of the above could have been done once in setup()

i'll guess that modbus.poll() must be checking the input pin for data and to do so, it needs to repeatedly check that pin ...
but there's a 500 msec delay between each time poll() is invoked, so i doubt it will see changed on the pin quickly enough

You are using hardwareserial on slave sketch, not pins 10 and 11

OH, that is, in order for it to send data normally, should all the code from the loop be transferred to setup? thus finally having time to send the necessary data once?

No, just setup software serial on pins 11 and 10 and remove that delay likje gcjr wrote.

#include <SoftwareSerial.h>
#include <ModbusRTUSlave.h>

#define MODBUS_SLAVE_ID 5
#define MODBUS_REGISTER_START 0

#define RS485_TX 10
#define RS485_RX 11
#define DE_RE 2

SoftwareSerial mySerial(RS485_RX, RS485_TX);
ModbusRTUSlave modbus(mySerial, DE_RE);

uint16_t ModbusData[4]; 

void setup() {
    Serial.begin(9600);
    modbus.begin(MODBUS_SLAVE_ID, 9600);
    modbus.configureHoldingRegisters(ModbusData, 4);
}

void loop() {
    float Data1 = 5;
    float Data2 = 7;


    Serial.print("Data 1: ");
    Serial.println(Data1);

    Serial.print(" Data 2: ");
    Serial.print(Data2);

    uint16_t* posPtr = (uint16_t*)&Data1;
    uint16_t* distPtr = (uint16_t*)&Data2;

    ModbusData[0] = posPtr[0];
    ModbusData[1] = posPtr[1];
    ModbusData[2] = distPtr[0];
    ModbusData[3] = distPtr[1];

    modbus.poll();
    //delay(500);
}

see the example

looks like you need Software Serial

Hello again, I apologize, but my plans have changed. Now, I need to send a message from the computer to the USB-to-RS485 converter, but I still can't get it to work no matter how hard I try. To be more specific, the Node.js code gets stuck at "Preparing to send data..." and doesn't proceed any further, and there are no messages about this data in the Arduino Uno.

const ModbusRTU = require('modbus-serial');
const client = new ModbusRTU();

const portName = 'COM3';
const baudRate = 9600;

client.connectRTUBuffered(portName, { baudRate: baudRate })
  .then(() => {
    console.log('Modbus connection open');
    client.setID(1);
    return new Promise(resolve => setTimeout(resolve, 1000));
  })
  .then(() => {
    console.log("Preparing to send data...");
    return client.writeRegisters(0, [10]); 
  })
  .then(() => {
    console.log("Data was sent, reading back...");
    return client.readHoldingRegisters(0, 1); 
  })
  .then(sms => {
    console.log("Received response:");
    console.log(sms.data); 
  })
  .then(() => {
    console.log("The data has been sent successfully");
  })
  .catch(err => {
    console.error("Error:", err);
  })
  .finally(() => {
    client.close();  
  });

this is code written in Visual Studio Code in Node format.js for RS-485

#include <ModbusRTUSlave.h>

#define RS485_TX 10
#define RS485_RX 11
const byte dePin = 2; 

SoftwareSerial mySerial(RS485_RX, RS485_TX);
ModbusRTUSlave modbus(Serial, dePin);

uint16_t holdingRegisters[1];

void setup() {
  Serial.begin(9600); 
  modbus.begin(1, 9600);
  modbus.configureHoldingRegisters(holdingRegisters, 1); 
}

void loop() {
  modbus.poll(); 

  if (holdingRegisters[0] == 10) {
    Serial.println("Received value: 10");
  }
}

Here is the code written for Arduino Uno

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