RS485 communication issue

Hi all,

I am using RS485 to communicate between an Uno and Mega over a long distance. The data is then output to the serial monitor using the serial port from the Mega.

I had parts of it working but it just refuses to work with the Mega.

It's a typical master slave network. The master sends out a token which the Uno receives and then transmits data back to the master.

I've tested the slave over the RS485 network using Matlab as the master. This proves that the slave and cable are working fine. Also as part of the setup a hard wired LED goes off every time the transmit enable is turned on. I'm using the same MAX chip wiring as the working slave so I know I got that right. The Mega master is the issue.

I'm stumped. Has anybody worked with this before and have suggestions for what I can try?

Here is the sketch that's not working

#include <TimeLib.h>

//initializing inputs and outputs
int control = 22;
int calibration = 24;
int recording = 26;

int collectSwitch = 30;
int collectSwitchLED = 28;

int streamLED = 46;
int storageLED = 48;
int stream = 52;
int storage = 50;

float inputA[9];
float inputB[9];
int i;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(19200);  //computer
  Serial1.begin(38400); //recorder
  Serial2.begin(19200); //instrument
  delay(20);
  pinMode(control, OUTPUT);
  digitalWrite(control, LOW);

  while (digitalRead(collectSwitch) == 1) {
    //wait until collect data switch is pressed
    Serial.println("stuck");
  }
  digitalWrite(collectSwitchLED, HIGH);
  digitalWrite(calibration, HIGH);
  //delay(90000);
  digitalWrite(calibration, LOW);
  setTime(0);
}

void loop() {

  // put your main code here, to run repeatedly:
  if (digitalRead(collectSwitch) == 0) {   //collect data switch is on


    //Obtains data from instrument using RS485 adaptors

    digitalWrite(control, HIGH);
    delay(20);
    Serial2.println('B');
    Serial2.flush();
    digitalWrite(control, LOW);
    if (Serial2.available()) {
    for (i = 0; i < 9; i++) {
        inputB[i] = Serial2.parseFloat();
      }
    }else{
      Serial.println("Not Available");
    }

    //Outputs data to computer via USB and also to datalogger

    for (i = 0; i < 3; i++) {
    char charVal[10];
      dtostrf(inputB[i], 5, 2, charVal);
      Serial.print(charVal);
      Serial.print(",");
    }
    for (i = 3; i < 6; i++) {
    char charVal[10];
      dtostrf(inputB[i], 8, 6, charVal);
      Serial.print(charVal);
      Serial.print(",");
    }
    for (i = 6; i < 9; i++) {
    char charVal[10];
      dtostrf(inputB[i], 8, 3, charVal);
      Serial.print(charVal);
      Serial.print(",");
    }

    int stamp = now();
                Serial.print(stamp);
                Serial.println("");
  } else {  //when collect data switch is off

    Serial.println("end");

  }
}

Henradrie:
Hi all,

I am using RS485 to communicate between an Uno and Mega over a long distance. The data is then output to the serial monitor using the serial port from the Mega.

I had parts of it working but it just refuses to work with the Mega.

I've got some critiques for your code:

void setup() {
// this code will cause the mega to hang in Serial print, it might miss your switch press event
// because when the Serial input queue fills, println() will wait for characters to be send until
// enough space is open in the queue for the println() to add it's data.
  while (digitalRead(collectSwitch) == 1) {
    //wait until collect data switch is pressed
    Serial.println("stuck");
  }

// try this instead
if(digitalRead(collectSwitch)==1){
  Serial.println("stuck");
  while (digitalRead(collectSwitch) == 1) ; // hang until keypressed
  }
Serial.println("Starting collection run");  

// cut

void loop() {

  // put your main code here, to run repeatedly:
  if (digitalRead(collectSwitch) == 0) {   //collect data switch is on


    //Obtains data from instrument using RS485 adaptors

    digitalWrite(control, HIGH);
    delay(20);
    Serial2.println('B');  // sends 'B' LF
    Serial2.flush();
    digitalWrite(control, LOW);
// nothing can be in the Serial2 input buffer. you just switched back into RX mode a couple of microseconds ago. 
// you need to wait for a response for a few milliseconds at least. at 19200 baud, each character
// takes about 520microseconds to move through the UART.
// I'd put a 50 millisecond delay, give your instrument a bit of time to respond.
// 50ms delay allow enough time for about 96 characters to move thru the UART
// but the input buffer is only 63 characters deep, so if your instruments reply is greater than
// 63 characters this section needs to be different.

delay(50);

    if (Serial2.available()) {
    for (i = 0; i < 9; i++) {
        inputB[i] = Serial2.parseFloat();
      }
    }else{
      Serial.println("Not Available");
    }


// I would change your 'input' section to something a little more complex, something that 
// parses the data with a timeout
    bool timeoutError=false;
    i = 0;
    while(!timeoutError && ( i < 9)) {
        timeoutError = getFloat(&Serial2,&inputB[i],100); // parse Float from Serial2, with 100ms timeout
        if(!timeoutError) i++;
        }
    If(i<9){
      Serial.println(" Instrument read Timeout.");
      Serial.print(i,DEC);
      Serial.println(" parameters read."); 
      }
// cut


bool getFloat( HardwareSerial *S, float *F, unsigned long TO){
unsigned long myTO = millis();
S->setTimeout(TO); // reset stream timeout to TO ms from 1 sec
*F = S->parseFloat();
S->setTimeout(1000); // return to default timeout for Stream.
if((millis()-myTO >=TO)) { // timeout occured 
  return false;
  }
return true;
}

I would also place a 4.7k to 10k pullup resistor on the RX pin of the RS485 Serial port. when you switch to TX mode (high), the RO output from the MAX485 floats, the UART usually starts seeing a bunch of 0xFF's

Chuck.

Thanks you Chuck for the suggestions.

In order to diagnose the problem further I removed the instrument reading and switch aspects of the sketch. This allowed me to get to the heart of what was wrong.

It turns out that the chip isn't able to send data but is able to receive data. That's not how it's supposed to work and I'm trying to figure out why.

Once I overcome this hurdle I'll implement some of your ideas about the switch.

Henradrie:
Thanks you Chuck for the suggestions.

It turns out that the chip isn't able to send data but is able to receive data. That's not how it's supposed to work and I'm trying to figure out why.

Once I overcome this hurdle I'll implement some of your ideas about the switch.

Good luck, those MAX485 are pretty durable.

Chuck.

Not durable enough, I fried 4 of them. No wonder nothing was working.

Henradrie:
Not durable enough, I fried 4 of them. No wonder nothing was working.

Have you identified what is wrong with your circuit?

The MAX485 should handle up to 7v common mode error.

What is the voltage between A and B when the net is idle? should be > 0.2V and < 5V

What is the voltage between A and GND and B and GND? should be < 5.0V

A problem with RS485 shows up with ground loops, The network is not galvanic isolated. So if you have a difference between the GND potential between nodes, the current works against the driver.

I'm interested in what problem you found.

Chuck.

The voltage between A and B when idle: 2.7V
Between A and GND when idle: 3.8V
Between B and GND when idle: 3.8V

No voltage difference between nodes.

I figure the problem was static or improperly applied voltage. My workplace has lots of static, I regularly produce 0.5 cm sparks by walking to the door and touching it with a key. The power system for the whole unit comes from a single 12V power supply. It powers two Uno's, 2 IMU's, an SD card reader, and a Mega. When I turn the power off but leave the Mega plugged in using the USB port some of that power travels to the instrument. It created a global low power situation that may have had something to do with it.

I also got the soldering iron too close so some of them and fried them.

I anticipate that something else will go wrong so I bought 12 more. Now I know that when they get hot to change them out.

Henradrie:
The voltage between A and B when idle: 2.7V
Between A and GND when idle: 3.8V
Between B and GND when idle: 3.8V

No voltage difference between nodes.

I figure the problem was static or improperly applied voltage. My workplace has lots of static, I regularly produce 0.5 cm sparks by walking to the door and touching it with a key. The power system for the whole unit comes from a single 12V power supply. It powers two Uno's, 2 IMU's, an SD card reader, and a Mega. When I turn the power off but leave the Mega plugged in using the USB port some of that power travels to the instrument. It created a global low power situation that may have had something to do with it.

I also got the soldering iron too close so some of them and fried them.

I anticipate that something else will go wrong so I bought 12 more. Now I know that when they get hot to change them out.

Sounds like you have it handled, Good luck on your project.

I'm currently designing an Arduino compatible board that uses the 328PB, I am adding circuits to share the second serial between SPI, RS485 and RS232. It will express all of the extra pins of the SMT version, A0..A7, even the second I2C port. I'm thinking to stretch it almost as long as the Mega. I was thinking of swapping the Mega Serial3 with the PB's Serial1. I haven't decided if I want the second I2C port on pins 20,21?

I think I should be able to treat the RS485 like another SPI device, except I'll have to change from SPI mode to UART, I am adding tristate buffers. The RS232 will also use tri-state buffers with CTS/RTS handshaking. I figure that if when I need to shift function I can stop the other end using RTS. I'll need a dedicated pin for CS on the RS485, and another pin for CS of the RS232. One addition pin for DE on the RS485 circuit that I will share as RTS on the RS232 section. The RS232 will need an interrupt pin for CTS.

I'm hoping that by the time I have finished PCB's the Arduino environment will have the PB's register defines integrated.

I wish you success with your project.

Chuck.