RS485 Communication network problem

Hello. I have a requirement as follows and need your expertise in resolving the issue. I need to set up a master and two slaves on RS485, RS485 because the distance between master to first slave is 10m and another 10 mt to the other slave. The master is in the middle with the slaves on either side of the master. I will be using MAX485 modules for all the three arduinos.

Each of the slaves will be measuring (3) distances - FL_dist, FC_dist adn FR_dist. The sensors are connected to the slaves using I2C network. That part of the code is currently ommitted for simplicity and a fixed integer values assigned to the three variables.

The master on the other hand will receive the data from each slave and use it to display on a 20x4 LCD over I2C network. That part of the code is also ommitted for simplicity.

To begin with I am using only one master and one slave to set up the circuit and ensure communication and data transfer successfully.

Here is the image of the MAX485 module I am using.

I do not want to use the address selection vide external hardware set up, but would like to use one dedicated line between the master and slave 1 (pins 8 on the master and slave 1) and another dedicated line between the master and slave 2 (pins 9 on the master and slave 2). Master would make and select the dedicated line HIGH to address either the slave 1 or slave 2 and then unselect, one after the other.

I have not used any physical / External pullups or pull downs in the entire hardware.

I have shorted RE and DE pins on the MAX485 module and connected it to pins 4 of the master and slave and is called as Enable.

The Vcc and GND for the MAX485 module

I have used SoftwareSerial library to make pins 2 and 3 for RX and TX.

I have used a twisted pair Ethernet cable between the A and B of the MAX 485 module, where A goes to A and B goes to B using the green terminal block connector on the top right. There is a 120 ohm resistor between the A and B on either side of the twisted pair cable.

As I run the code, the Master is saying that the "Data Request is Sent", while the slave says "Slave Ready to Receive". The master also displays random values received from the slave as FL_dist: -8196, FC_dist: -8196 and FR_dist:-8196 in place of the intended 10, 20 and 30 as per the test codes of Master and Slave Arduinos, provided for your analysis.

Help me understand and correct where I am going wrong and why I am unable to get the set up to work as intended.

// Master_25042024

#include <SoftwareSerial.h>

#define RX_PIN 2       // Define RX pin for SoftwareSerial _ now blue - goes to RO
#define TX_PIN 3       // Define TX pin for SoftwareSerial _ now purple - goes to DI
#define Enable 4       // Define Driver Enable pin for RS485 communication_ now orange
#define ready_Slave 8  // Define pin to indicate readiness to the master

SoftwareSerial rs485(RX_PIN, TX_PIN); // RX is pin 2 and TX is pin 3

int FL_dist, FC_dist, FR_dist;

void setup() 
{
  pinMode(Enable, OUTPUT);
  pinMode(ready_Slave, OUTPUT);    // alternative way of selecting 
  digitalWrite(ready_Slave, LOW);  // puttin TTL-RS485 Module in Receive Mode
  rs485.begin(9600);
  Serial.begin(9600);
}

void loop() {
  digitalWrite(ready_Slave, HIGH);  // Getting Slave ready
  Serial.println("Slave selected");
  delay(5); // Delay for slave to enter into listening mode 

  digitalWrite(Enable, HIGH);  // Putting the RS485 module in Transmit mode
  Serial.println("Ready to send data request");
  delay (5);
  rs485.write('S');  // Send data request command
  delay(10); // Delay for slave to process the request 

  Serial.println("Data Request Sent");  // for troubleshooting

  digitalWrite(Enable, LOW); // Putting the RS485 module in Receive Mode

  // Wait for the slave to send the response
  delay(100); // Adjust the delay as necessary based on the slave processing time

  // Read sensor data from the slave
  while (rs485.available() >= 6) {
    // Read and reconstruct FL_dist
    uint16_t FL_lowByte = rs485.read();
    uint16_t FL_highByte = rs485.read();
    FL_dist = FL_lowByte | (FL_highByte << 8);

    // Read and reconstruct FC_dist
    uint16_t FC_lowByte = rs485.read();
    uint16_t FC_highByte = rs485.read();
    FC_dist = FC_lowByte | (FC_highByte << 8);

    // Read and reconstruct FR_dist
    uint16_t FR_lowByte = rs485.read();
    uint16_t FR_highByte = rs485.read();
    FR_dist = FR_lowByte | (FR_highByte << 8);
  }

  digitalWrite(Enable, HIGH); // Putting the RS485 module in Transmit Mode
  Serial.println("Enable put in transmit mode");
  digitalWrite(ready_Slave, LOW);
  Serial.println("Slave de-selected");

  Serial.print("FL_dist: ");
  Serial.println(FL_dist);
  Serial.print("FC_dist: ");
  Serial.println(FC_dist);
  Serial.print("FR_dist: ");
  Serial.println(FR_dist);
}


//Slave

#include <arduino.h>
#include <SoftwareSerial.h>

#define RX_PIN 2 // Define RX pin for SoftwareSerial_(goes to RO on TTL-RS485 module)
#define TX_PIN 3 // Define TX pin for SoftwareSerial_(goes to DI on TTL-RS485 module)
#define Enable 4 // Define Driver Enable pin for RS485 communication_(Pins DE & RE shorted on the TTL-RS485 module)
#define slave1 8 // Direct line between Master and Slave, this line will be pulled HIGH by the Master to initiate start of communication

SoftwareSerial rs485(RX_PIN, TX_PIN); // Create a SoftwareSerial object for RS485 communication

int FL_dist = 10; // Replace with real time Sensor data later
int FC_dist = 20;
int FR_dist = 30;

char incoming;
Serial.flush();

void setup()
{
pinMode(Enable, OUTPUT); // Set Enable as an output pin
pinMode(slave1, INPUT); // Set slave1 as an input pin
rs485.begin(9600); // Initialize SoftwareSerial with baud rate 9600
Serial.begin(9600); // Initialize Serial communication for debugging
digitalWrite (slave1, HIGH); // Putting the slave TTL-RS485 into Transmit Mode
}

void loop()
{
if (digitalRead(slave1) == HIGH)
{
digitalWrite(Enable, LOW); // put the module into receive mode
Serial.println("Slave ready to receive");
//delay(5); // changed 26042024_0843

if (Serial.available() > 0) // 
{  // checking for data request from Master
   incoming = Serial.read();

  if (incoming == 'S') 
  {
    Serial.println("Data Request Received");

    digitalWrite(Enable, HIGH);  // put the module into Transmit mode
    Serial.println("Enable HIGH");

    // Send sensor data
    rs485.write((uint8_t*)&FL_dist, sizeof(FL_dist));
    rs485.write((uint8_t*)&FC_dist, sizeof(FC_dist));
    rs485.write((uint8_t*)&FR_dist, sizeof(FR_dist));
    delay (5);  // delete if needed

    Serial.flush();
    digitalWrite(Enable, LOW); // put Enable back into Receiving mode
    Serial.println("Data Sent and Enable is now LOW");
  }
  else
  {
    Serial.println("mismatch");
  }
}
else 
{
  Serial.println("Data Request NOT Received");
}

}
else
{
Serial.println("Direct line is LOW");
}
}

I must mention here that this piece of code mentioned below is NOT written by me.

// Read and reconstruct FL_dist
    uint16_t FL_lowByte = rs485.read();
    uint16_t FL_highByte = rs485.read();
    FL_dist = FL_lowByte | (FL_highByte << 8);

    // Read and reconstruct FC_dist
    uint16_t FC_lowByte = rs485.read();
    uint16_t FC_highByte = rs485.read();
    FC_dist = FC_lowByte | (FC_highByte << 8);

    // Read and reconstruct FR_dist
    uint16_t FR_lowByte = rs485.read();
    uint16_t FR_highByte = rs485.read();
    FR_dist = FR_lowByte | (FR_highByte << 8);

I moved your topic to an appropriate forum category @madhavdivya.

In the future, please take some time to pick the forum category that best suits the subject of your topic. There is an "About the _____ category" topic at the top of each category that explains its purpose.

This is an important part of responsible forum usage, as explained in the "How to get the best out of this forum" guide. The guide contains a lot of other useful information. Please read it.

Thanks in advance for your cooperation.

1 Like

How quickly will the slave reply once it receives the request? Your code will keep the master in transmit mode for 10+ milliseconds after the command has been sent.

If the slave responds in less than 10ms, then all of or part of the response will be lost.

I would suggest you simplify your project first to get the basics working, then add in more functionality, testing as you go.

1 Like

thanks @markd833, I will implement it and get back to you with the results. May I request you to take a minute to check if there are any other bottlenecks?

@pert : Thank you for pointing me in the right direction. I will bear this in mind the next time. On the other hand, how can I find the appropriate forum it had been moved to? Please help me with this aswell .

The fact you are here replying on the topic proves that you already found it. Just continue to participate in the discussion here and you are set.

1 Like

thanks @pert

1 Like

@markd833 : Just give me a couple of days more to get back with the implementation. My daughter is heading back to the USA and I am slightly tied up with her.

@markd833: I am now back to my table and as per your suggestion, have removed the delay of 10+mS - without luck. I have also tried to send across only a character from master to slave - no luck. Can you point where I am going wrong?

I suggest you start with a very simple sketch:

a) remove the 485 module and do a direct connection between Soft RX/TX from one Arduino to the oder. Dont forget to connect GND also. Send a simple Hello from A to B. If you can receive "Hello" on B go to the next step.
b) on B check for the incoming "Hello" and send back an answer, for example the millis().
c) now remove the direct connections and install the RS485 Modules on both side, implement the DE/RE pin and redo your sketches.

I highly recommend to read and work through this tutorial:

it explains how to read data from Serial.

1 Like

The address is typically inside the protocol..
For you can be as simple as sending either a 1 or 2..
Each board waits for his specific data request..

Curious though as I don't see it mentioned what Arduino boards are you interfacing??
That module is a 5v unit, not all Arduino's are..

good luck.. ~q

Please go to the IDE and under the EDIT menu Item click on Copy for Forum and paste the code for the slave here. Your original attempt did not work

So you have 4 wires going between the Master and slave:
A
B
Select
Ground
Is that correct?

I suggest starting your project with the basic comms as @noiasca suggested above.

Check each step as you progress making sure that each increment in functionality is working as you want it. Keep adding functionality and testing till you have your complete project working as you want it.

1 Like

@noiasca : I will do that and post back on the developments. Thank you for your time.

@qubits-us : Thank you, I appreciate that. However, I would still like to go with a dedicated line betweent the master and each of the slaves. Yes, I overlooked mentioning the board type - I am using UNO compatible boards, not the originals.

@jim-p: Thank you for pointing the failure to upload the code in proper format. Here is the code. I am using arduino uno (not original).

On the TTL-RS485 modules (master and slave), I have RE and DE shorted and going to Enable (pin 4) of arduino. The RO and DI on the TTL-RS485 modules are connected to RX (pin2) and TX (pin3) on the master and slave arduino respectively. The A from the master module goes to A on the slave and so does B from the master to B on the slave. The VCC and GND of each module goes to +5 and GND on each of the arduino.

type//Slave

#include <arduino.h>
#include <SoftwareSerial.h>

#define RX_PIN 2 // Define RX pin for SoftwareSerial_(goes to RO on TTL-RS485 module)
#define TX_PIN 3 // Define TX pin for SoftwareSerial_(goes to DI on TTL-RS485 module)
#define Enable 4 // Define Driver Enable pin for RS485 communication_(Pins DE & RE shorted on the TTL-RS485 module)
#define slave1 8 // Direct line between Master and Slave, this line will be pulled HIGH by the Master to initiate start of communication

SoftwareSerial rs485(RX_PIN, TX_PIN); // Create a SoftwareSerial object for RS485 communication

int FL_dist = 10; // Replace with real time Sensor data later
int FC_dist = 20;
int FR_dist = 30;

char incoming;
//Serial.flush();

void setup()
{
pinMode(Enable, OUTPUT); // Set Enable as an output pin
pinMode(slave1, INPUT); // Set slave1 as an input pin
rs485.begin(9600); // Initialize SoftwareSerial with baud rate 9600
Serial.begin(9600); // Initialize Serial communication for debugging
digitalWrite (slave1, LOW); // Putting the slave TTL-RS485 into Transmit Mode
}

void loop()
{
if (digitalRead(slave1) == HIGH)
{
digitalWrite(Enable, LOW); // put the module into receive mode
//Serial.println("Slave ready to receive");
//delay(5); // changed 26042024_0843

if (Serial.available() > 0) // 
{  // checking for data request from Master
   incoming = Serial.read();

  if (incoming == 'S') 
  {
    // Serial.println("Data Request Received");

    digitalWrite(Enable, HIGH);  // put the module into Transmit mode
    // Serial.println("Enable HIGH");

    // Send sensor data
    rs485.write((uint8_t*)&FL_dist, sizeof(FL_dist));
    rs485.write((uint8_t*)&FC_dist, sizeof(FC_dist));
    rs485.write((uint8_t*)&FR_dist, sizeof(FR_dist));
    delay (5);  // delete if needed

    Serial.flush();
    digitalWrite(Enable, LOW); // put Enable back into Receiving mode
    Serial.println("Data Sent and Enable is now LOW");
  }
  else
  {
    Serial.println("mismatch");
  }
}
else 
{
  Serial.println("Data Request NOT Received");
}
}
else
{
Serial.println("Direct line is LOW");
}
} or paste code here

@markd833 : Thank you, I will go and study the basic comms as @noiasca suggested and post back here.

The GNDs of both arduinos also need to be connected together.
See post #13

@jim-p : Thank you, yes the GNDs of both the arduinos are connected together.