Practical Limits of Serial communications?

Hi everyone,
As you may have read elsewhere, I am grappling with implementing RS485 on the Arduino platform using the hardware serial ports on the 1284P and the 328P. I am now wondering if I was over-complicating matters... whether it doesn't make more sense to just stick to serial communications between Arduinos and drop RS485 altogether. The folk at the Openenergy project are showing something akin, i.e. using 74AHC125 driver chips to isolate Arduinos from the serial line until needed - not unlike RS485 chips, mind you.

What other options should I be considering for line sets shorter than 50' and multiple arduinos?

line sets shorter than 50' and multiple arduinos

Entire books can be (and have been) written on the subject when there are so few constraints. Your question is not unlike this one: "How can I best travel 5 miles? I will need to make 3 stops." If the route is through suburban neighborhoods then foot, bicycle, scooter, motorcycle, and car are all reasonable choices. If the route is through rugged mountainous terrain, none of those choices are reasonable.

Start with these constraints: Will the communications cable pass through electrically noisy areas? Any large motors or fluorescent lights along the path?

Will the communications cable pass between buildings? Will the cable need to be electrically isolated? Protected from lighting?

in general the longer the lines the lower the baudrate that works.

googled baud rate cable length => http://www.chipkin.com/articles/cable-lengths-and-baud-rates-fro-rs485-or-bacnet-mstp -

Hi Coding Badly,

Indoor application only. Unlikely to be hit by large EMI sources as described above. Just a link between various dataloggers running on Arduinos to share power and a communications bus. My preferred implementation would be to use Ethernet wiring, thanks to to the abundance of cables at different pre-confectioned lengths, twisted pairs, and 8 conductors, where I'm proposing to use two pairs for power, one pair for interrupt signaling, and one pair for the serial / RS485 communications.

Communication / power sharing is happening among a master unit (1284p processor) and various modules that are using 328Ps.

Reading up more on the travails by others re: RS485 a couple of things have become apparent. For one, there are some considerations that have to be made regarding the hardware serial buffer, since those are the pins I am using right now. I also wonder if it would make sense for me to not use the hardware serial pins on the 328Ps and go with the SoftSerial library instead - I have spare pins.

Additionally, I neglected to use resistors as described here to give the FTDI header on the 328P boards priority whenever it is connected. But that shouldn't be a big concern on the 1284p since it has two serial ports. On the 328P boards, I worry if the FTDI cable may be causing some trouble, but I kind of doubt it - it just sits there on the bus, listening.

No need for super-fast comms. The RS485 chips are rated for 5+MBits/s and I'm going to use maybe 250kbit/s...

How many nodes will be connected?

Typically 1 node. Max probably around 5.

I'm starting to wonder if I shouldn't just sacrifice one of the power pairs and go with full-duplex 485... allegedly 'transparent' as far as the UARTs go?

Is it a master-slave network or peer-to-peer?

Master / Slave. The 1284p is the master, all other modules are slaves and only respond when addressed by the master.

I was hoping to keep it to half-duplex to minimize the number of lines necessary. However, I keep having trouble with getting anything intelligible across the divide.

As for other implementations, I wonder if the 74AHC125 chip from NXP might make sense. The openenergymonitor crew built a network around it that could transmit significant distances while maintaining simple TTL signalling. Not as robust perhaps as RS485 with its differential signalling, but unlikely a problem given the above parameters, I hope. Plus, a lot easier to troubleshoot since any FTDI cable and understand what is being sent.

I wonder if the 74AHC125 chip from NXP might make sense

You still have the problem of disabling a slave's transmitter# (line driver) when the slave is not transmitting. With the new interrupt driven Serial (and lack of buffer management methods) that will be difficult.

How are you handling that now with RS-485? Or are you?

# The other three points (slave's receiver, master's transmitter, master's receiver) can be left active all the time.

If you can't get half-duplex running with RS-485 you won't get it running with the buffers, the software will be exactly the same.

Can you post your code? My guess is that are not waiting for the bytes to go before to turn the line around.

With the new interrupt driven Serial (and lack of buffer management methods) that will be difficult.

I feel that this will cause problems with many programs, the new buffered output should have been an option I think, extra parameter, ability to 0 the buffer size or whatever.


Rob

I'm not even trying to turn the line at this point... strictly one-way communication not happening.

Here is some code from the Yourduino site I adjusted for the Slave. Note the constantly-'LOW' RE/DE pin, i.e. receive mode only.

/* YourDuino RS485 Slave Node A Example
 terry@yourduino.com */

/*-----( Declare Variables )-----*/
int ledPin=13;
int EN = 6;
byte Val;

void setup()/****** SETUP: RUNS ONCE ******/
{
  pinMode(ledPin, OUTPUT );
  pinMode(EN, OUTPUT );
  Serial.begin (28800);
  Serial.println("Setup Complete.");
}//--(end setup )---

void loop()  /****** LOOP: RUNS CONSTANTLY ******/
{
  // receive Data
  digitalWrite (EN, LOW ); // enable receive
  Val = Serial.read ();
  Serial.println(Val);
  if (-1 != Val) 
  {
    if ( 'A' == Val) 
    {
      digitalWrite (ledPin, HIGH );
      delay (500);
      digitalWrite (ledPin, LOW );
      delay (500);
    }
  
  }
}//--(end main loop )---

And here is the master code. It is running on a 1284P, the first serial bus ends in the FTDI header, while Serial1 is attached directly to the RS485 chip inputs. I probably should simplify this to the point where the RE/DE pin is always high and see if that makes any difference.

/* YourDuino RS485 Master Node Example
 terry@yourduino.com */

/*-----( Declare Variables )-----*/
int EN = 12;
int LED_PIN =7;

void setup() /****** SETUP: RUNS ONCE ******/
{
  pinMode(EN, OUTPUT );
  pinMode(LED_PIN, OUTPUT );
  Serial.begin (28800);
  Serial1.begin (28800);
}//--(end setup )---

void loop()    /****** LOOP: RUNS CONSTANTLY ******/
{
  // Send Data
  digitalWrite(LED_PIN, HIGH ); // turn on light
  Serial.print ( 'A' ); //FTDI Header Send

  digitalWrite(EN, HIGH ); // enable send
  delay (1); //wait for RS485 chip to be active
  Serial1.print ( 'A' ); //RS485 Bus Send
  delayMicroseconds (660); ////delay recommended by Nick Gammon to deal with the serial buffer clearing before TX is complete
  digitalWrite(EN, LOW ); // disable send
  
  delay(1000);  
  digitalWrite(LED_PIN, LOW ); // turn off light
  Serial.print ( 'B' );//FTDI Header Send
  
  digitalWrite(EN, HIGH ); // enable send
  delay(1); //wait for RS485 chip to be active
  Serial1.print ( 'B' ); //RS485 Bus Send
  delayMicroseconds (660);  //delay recommended by Nick Gammon to deal with the serial buffer clearing before TX is complete
  digitalWrite(EN, LOW ); // disable send
  delay (1000);
}//--(end main loop )---

One problem

Val = Serial.read ();

You're not waiting for a char for be received.

Check out Serial.available()


Rob

Graynomad:
Check out Serial.available()


Rob

Thanks graynomad,

I had used that in the past. No change in behavior.

/* YourDuino RS485 Slave Node A Example
 terry@yourduino.com */

/*-----( Declare Variables )-----*/
int ledPin=13;
int EN = 6;
byte Val;

void setup()/****** SETUP: RUNS ONCE ******/
{
  pinMode(ledPin, OUTPUT );
  pinMode(EN, OUTPUT );
  Serial.begin (9600);
  Serial.println("Setup Complete.");
}//--(end setup )---

void loop()  /****** LOOP: RUNS CONSTANTLY ******/
{
  // receive Data
  digitalWrite (EN, LOW ); // enable receive
  if (Serial.available()>0) {
    Val = Serial.read ();
    if ( 'A' == Val) 
    {
      digitalWrite (ledPin, HIGH );
      delay (500);
      digitalWrite (ledPin, LOW );
      delay (500);
    }
  else Serial.println(Val);
  }
}//--(end main loop )---

I get a "Setup complete" and then nothing on the slave. I get some chatter on the slave as I connect and disconnect the master. I re-verified electrical continuity from one RS485 to the other. Enabling / Disabling the terminators does nothing either. I'm feeling rather blue, I must say.

I would just print the HEX of whatever you get without the tests.


Rob

Done. Using this code, I get "Setup complete", two zeros, nothing more. I wonder if one of the RS485 chips is dead... Re-verified that the RE/DE on the receiver is 0V and that the RE/DE on the transmitting chip is 5V. Nuts.

/* YourDuino RS485 Slave Node A Example
 terry@yourduino.com */

/*-----( Declare Variables )-----*/
int ledPin=13;
int EN = 6;
byte Val;

void setup()/****** SETUP: RUNS ONCE ******/
{
  pinMode(ledPin, OUTPUT );
  pinMode(EN, OUTPUT );
  Serial.begin (9600);
  Serial.println("Setup Complete.");
}//--(end setup )---

void loop()  /****** LOOP: RUNS CONSTANTLY ******/
{
  // receive Data
  digitalWrite (EN, LOW ); // enable receive
  if (Serial.available()>0) {
    Val = Serial.read ();
    Serial.println(Val,HEX);
  }
}//--(end main loop )---

According to the posted code your slave is running at 9600, master at 28800.


Rob

Hi Graynomad,

Thanks for the reply. I changed both of them down to 9,600 baud since my FTDI adapter seems to be flaky at 28,800. Might have to to with Win 7 not allowing the driver to be changed easily. So, they're both running at 9,600 baud now. I flipped the FTDI cable back and forth among the two Arduinos, I get clear-text messages on both (i.e. "setup complete", etc.) serial busses, just no communication between the two chips. I have a third RS485 board at home, I'll see if I can eliminate one of the RS485 chips as a possible culprit.

See current Master code below:

/* YourDuino RS485 Master Node S Example
 terry@yourduino.com */

/*-----( Declare Variables )-----*/
int EN = 12;
int LED_PIN =7;

void setup() /****** SETUP: RUNS ONCE ******/
{
  pinMode(EN, OUTPUT );
  pinMode(LED_PIN, OUTPUT );
  Serial.begin (9600);
  Serial1.begin (9600);
  Serial.println ("Setup Complete."); //FTDI Header Send
}//--(end setup )---

void loop()    /****** LOOP: RUNS CONSTANTLY ******/
{
  // Send Data
  digitalWrite(LED_PIN, HIGH ); // turn on light
  digitalWrite(EN, HIGH ); // enable send
  Serial.print ( 'A' ); //FTDI Header Send
  delay (1); //wait for RS485 chip to be active
  Serial1.print ( 'A' ); //RS485 Bus Send

  delay(1000);  
  digitalWrite(LED_PIN, LOW ); // turn off light
  Serial.print ( 'B' );//FTDI Header Send
  Serial1.print ( 'B' ); //RS485 Bus Send
  delay (1000);
}//--(end main loop )---

The code looks OK I think, you don't need delay(1) but you should be seeing something if the hardware is kosher.

You could try not using a transceiver at all, just pin-to-pin.

This is where proper test equipment comes into its own.


Rob

The good news is that I got it to work with one of my other modules.

I presume the RS485 chip is either toast on the other module or the serial pins are not where I expected them to be. Hopefully it's the former!