RS485 (BOB-10124) help

Hi,
I'm using two RS485 modules between two Nano 33 boards and trying to figure this thing out.
One board was set as master, the other as slave, and I'm just trying to send generic characters and read them on the other side.
When I connect both boards (no difference in code) through Serial1 it works fine and I'm able to read on the slave side what is sent by the master, but when using the RS485 - it doesn't work.
I've followed a few guides with no success.
The master sets RTS to '1' when it transmits, the slave sets RTS to '0' at all times. Most of the time the serial monitor doesn't show anything on the salve side, and from time to time it prints a mirrored question-mark, which is an unclear behavior.
My programs:

/// MASTER //

#define RTS 3

void setup() 
{
  Serial1.begin(9600);
  Serial.begin(9600);
  pinMode(RTS, OUTPUT);
}

void loop() 
{
    Serial.println("Sending data...");
    digitalWrite(RTS, HIGH); //set transmitter mode.
    Serial1.write("1");
    delay(1000);
    Serial1.print("0");
    delay(1000);
    digitalWrite(RTS, LOW);
    delay(1000);
}
// SLAVE ///

#define RTS 3

void setup() 
{
  Serial1.begin(9600);
  Serial.begin(9600);
  pinMode(RTS, OUTPUT);
  digitalWrite(RTS, LOW); //set receiver mode.
}

void loop() 
{
  while(Serial1.available() > 0)
  {
    Serial.println(Serial1.read());
  }
}

Would appreciate your help with this!

could you show the wiring of the RS485 modules
there are a number of RS485 modules - which ones are you using
note that the nano 33 uses 3.3V logic so you must be careful not to input 5V signals
have you terminated the A and B signals at each end with a 120ohm resistor?
connect the DE and RE pins together, take high to transmit then low to receive

The Sparkfun BOB-10124 RS485 breakout board uses the Maxlinear SP3485 chip which will will operate from 3.3V.

This is likely to be a wiring issue. Can you detail the wiring from each Nano to its RS485 board, and the wiring between the 2 RS485 boards.

As a side note, you can use the flush() command instead of a fixed delay before setting the RTS signal low at the end of the transmission.

found some code I used to test RS485 with a couple of Arduino Mega boards
sending data between the boards

// RS485 using arduino mega Seial1 pins 18 and 19

#define RS485Serial Serial1   // hardware serial port on Mega
// connect RS485 DI and RO to Mega Serial1
//   Serial Receive pin 19  to RO
//   Serial Transmit pin 18 to DI
//   pin 3 is RS485 Direction control DE & RE jumpered together

#define SSerialTxControl 3   //RS485 Direction control DE & RE jumpered together
#define SSerialTxControl2 2   //RS485 Direction control DE & RE jumpered together

#define RS485Transmit    HIGH
#define RS485Receive     LOW

#define Pin13LED         13

void setup()   /****** SETUP: RUNS ONCE ******/
{
  while(!Serial);
  delay(1000);
  // Start the built-in serial port, probably to Serial Monitor
  Serial.begin(115200);
  Serial.println("Use Serial Monitor, type in upper window, ENTER");
  
  pinMode(Pin13LED, OUTPUT);   
  pinMode(SSerialTxControl, OUTPUT);    
  pinMode(SSerialTxControl2, OUTPUT);    
  pinMode(2, OUTPUT);    
  digitalWrite(2, HIGH);

  digitalWrite(SSerialTxControl, RS485Receive);  // Init Transceiver   
  digitalWrite(SSerialTxControl2, RS485Receive);  // Init Transceiver    
  // Start the RS485 serial port
  RS485Serial.begin(115200);   // set the data rate 
}

void loop() 
{
  digitalWrite(Pin13LED, HIGH);  // Show activity
  if (Serial.available())
  {
    digitalWrite(SSerialTxControl, RS485Transmit);  // Enable RS485 Transmit   
    digitalWrite(SSerialTxControl2, RS485Transmit);  // Enable RS485 Transmit   
    RS485Serial.write(Serial.read());          // Send byte to Remote Arduino 
    digitalWrite(Pin13LED, LOW);  // Show activity    
    RS485Serial.flush();    // wait for byte to be transmitted
    digitalWrite(SSerialTxControl, RS485Receive);  // Disable RS485 Transmit       
    digitalWrite(SSerialTxControl2, RS485Receive);  // Disable RS485 Transmit       
  }
 
  if (RS485Serial.available())  //Look for data from other Arduino
   {
    digitalWrite(Pin13LED, HIGH);  // Show activity
    Serial.write( RS485Serial.read());        // Show on Serial Monitor
    digitalWrite(Pin13LED, LOW);  // Show activity   
   }  
}

I assume it worked at the time!

when working on RS485 I find a USB-RS485 dongle which can be plugged into a PC is very useful for debugging - view traffic using a terminal emulator

1 Like

Terminators should not be put at 'both' ends. There can be a terminator at 1 end, but even that one is optional.
The total resistance between A & B should not be (much) less than 120R or there will be to much current.

The wiring please.

    RS485Serial.flush();    // wait for byte to be transmitted
    digitalWrite(SSerialTxControl, RS485Receive);  // Disable RS485 Transmit       
    digitalWrite(SSerialTxControl2, RS485Receive);  // Disable RS485 Transmit  

well i would wait until the FiFo is empty before i would switch the transceiver into receive mode.
Serial.flush() holds the processor until the output buffer is empty, with a 1 byte fifo, there will still be 2 bytes to be transmitted.

interesting! the hardware designers I worked with always enabled termination resistors at both ends of a RS485 bus, e.g. RS485 wiring guide

Serial.flush() states Waits for the transmission of outgoing serial data to complete.
Must admit I have never attempted anything serious with Arduino RS485 - usually used Microchip PIC24 microcontrollers and waited for the UART hardware to tell me transmission was complete

just ran the code of #4 OK on an Arduino Mega using a RS485 module connected to PC using a FTDI USB-RS485-WE-1800-BT
serial monitor displays

Use Serial Monitor, type in upper window, ENTER
test 1 from PC
test2 from PC 1234567890
bye from PC

PC terminal emulator displays (local echo is on)

hello from mega
test 2 from mega
test 1 from PC
test2 from PC 1234567890
test 3 from mega 1234567890
bye from PC
bye from mega

@dekel12121 , there have been several requests for you to detail how you've wired up your RS485 boards and how you have then connected the RS485 boards together. Can you provide details so we can assist you further?

just tested with an Arduino Due (3.3V logic) to a different USB-RS485 dongle to a PC - all OK

wiring diagram

Hi guys,
sorry for the delay.
I appreciate all of your replies!

I'm graphically limited, but I'll try to be as clear as I can.
Between both RS485 modules:
A -> A (no resistors)
B -> B (no resistors)
Each G is connected to its Arduino's ground
Vcc -> 3.3V (500mA current limit - no problem here)

Between each Arduino Nano 33 and its RS485 module:
D3 -> RTS
TX -> RX
RX -> TX
GND -> GND

I'll mention that I've tried crossing the TX & RX connections - there was no change.

I'm not sure I understand. Did you mean more than 120R? And another thing - can I use in someway the internal resistors of the Arduinos?

Thanks! That's great to know as a future improvement. For the meanwhile, my focus is on making the system work properly.

Thank you!

Would truely appreciate some help from you guys!

How far have you got?

Have you tried the code that @horace posted in #4?

EDIT: The Sparkfun BOB-10124 board has on-board 120R resistors. There doesn't seem to be a non-destructive way of disabling them.

Here i would like to add that despite the common misconception that RS485 is a 2 wire standard, RS485 is actually a 3 wire communication standard. Meaning that between each rs485 transceiver there must the A wire, the B wire and a common wire. Most of the times one may get away with only the A and B wire if there is some common PSU ground or if the distance is really short but it is always a good practice to provide a dedicated common wire for the RS485 signals.

I dont think that this is whats wrong in your particular case but i think its worth mentioning.

The UART/USART and the RS232/422/485 all lie on the physical layer of the OSI model. So when you transmitt or receive information, your code does not care how that information reached your UART port.
Imagine this as you posting an envelop. You dont really care if the postal service deliver it using airplain or train or a truck. You represent the mcu, the envelop represents the information and the postal service represents the physical layer (UART, RS485 etc).

What i mean is that if the wiring between the cmu - transceiver - transceiver - mcu is correct then the code should work on every occasion unless if you use control signals for enableing or disableing the transceivers or changing them from transmitt mode to receive mode.

do i make sense ?

Here is a good article i found describing the above.
https://www.cuidevices.com/blog/rs-485-serial-interface-explained

So connecting shared ground should work if I get you correctly.

Make total sense! But yet, I don't understand why I don't see the expected signals on the lines..
Thanks for the detailed article.

I cant tell for sure.
Personally i use the SN65HVD82 ts422/485 transceiver chip for dealing with 485 communication. It's esenntially the same thing as the module but on a single chip.
I have never used the rs485 module before.

Hmmm have you tried the Serial.print() function instead of the Serial.write() ?

By master and slave do you mean transmitting device and receiving device ? Because the physical layer doesnt really care who is the master and who is the slave in a system.
Do you need bi-directional comminication or uni-directional ? Do data flow from the "master" to the "slave only" or back and forth ?

Actually yes, but it didn't change anything unfortunately.

Yes, and I agree with you.

At this point I'm trying to keep it as simple as possible, just to make sure that I know how make the RS485 work. Therefore, it's a uni-directional communication (from master to slave only. One device always transmits, the other always receives).

The misconception i had was that it is a 3 wire standard. The GND from the master will act as shielding, but devices on the bus do not have to share common GND, and in most situations, shouldn't share common GND.

The receiver actually just measures the voltage difference between the A & B wires which have alternating polarity depending on the logic level at input.
In case of longer cables, it is important to use a twisted pair of wires. This is what the whole system is meant for. The magnetic effect of the coils of the wires will counteract the effects of the wires capacitance on the output waveform, making it possible to cover much longer distances at higher speeds.

Then destructive it must be at times.
The max485 datasheet shows some typical connection circuits, and in case of 2 nodes there can be 120R terminators, but any additional nodes do not have a terminator !

Well in that case, how about you first have a successful communication between the 2 UARTs to begin with Tx(1) to RX(2) add a 1K resistor in series just in case. And start sending messages from 1 end to the other and receive them successfully. Once you have done that, put the MAX485 transceivers in between with the twisted pair, and get that to work. Once you know that the software works, you can properly test the hardware.

Thanks for your reply.
I've tested the software between two Arduino Nano 33 and it works great. When I try to integrate the two RS485 modules - it doesn't go well. In either case I don't use any resistors. Is that mandatory?
Regrading ground connections for the RS485 - each module is connected to its corresponding Arduino's ground, meaning the modules don't share it.

No.

Just show us the full schematic. On the transceiver in drive mode (the master) DE & !RE should be connected to VCC. on the slave these pins need to be connected to GND.