0

I'm using an Arduino Mega to send serial commands to a device that supports RS485 or RS422 half-duplex. To do this, I'm using the following code:

bool foo(int A, int B)
//...
//Const global int to byte 1&2
//Math on int A and int B to make bytes 3-8
//...
  unsigned char cmd[8]={[byte1],[byte2],[byte3],[byte4],[byte5],[byte6],[byte7],[byte8]};
  while(rep)
  {
    for (int i=0; i< 8; i++)
    {
      Serial2.write(cmd[i]);   // Send C string
    }
    if(Serial2.available())
    {
      //device echoed == command recieved
      rep=false;
    }
  }

The odd thing is that sometimes the loop gets it right on the first try, other times it takes 50+ tries to receive a command. This makes me think that there is something in my code that is making the data transmission unreliable. I believe it could be one of the following three things.


  1. I still need an RS485 module

In a previous version of my software, I was using the software serial library and used an RS485 module similar to the one shown here:

Arduino Uno to RS485

As I'm no longer using the software serial library and instead using the Mega's Serial2 port, I thought I could get rid of the module. Is this incorrect? If so, why would the commands work after N attempts as opposed to never working at all?


  1. Looping the Serial2.write()

Previously, while using the above module, I had to have two lines of code that would shift the DE and RE pins high or low depending on if I was sending or receiving data. I realized that these needed to be outside the for (int i=0; i< 8; i++) loop as otherwise, the device would not be able to read/understand the data being passed. Do I need to reimplement some version of this with the Arduino Mega's native serial? If so, how would I do this?


  1. I'm Not supporting a tri-state the transmit buffer

I was rereading the device's manual and found this line:

The converter must have the hardware and software support to tri-state the transmit buffer following the message transmission.

Honestly, I have no idea what this means. Does Arduino do this? If not, how can I make this happen?


Additional things of note:

  • I'd much rather use something like Majenko's pointer way to send data to my device so that I could make the code not rely on the fact that there are always 8 bytes transmitted. However, sometimes a byte will be \0 (or any other termchar) which would stop the loop prematurely. Is there a way to avoid this?
  • I'm still pretty new here, Is there some way that I can do this better than the way I'm currently doing it?

1 Answer 1

2

As I'm no longer using the software serial library and instead using the Mega's Serial2 port, I thought I could get rid of the module. Is this incorrect? If so, why would the commands work after N attempts as opposed to never working at all?

You still need the module. RS-485 and RS-422 are electrically incompatible with CMOS.

Previously, while using the above module, I had to have two lines of code that would shift the DE and RE pins high or low depending on if I was sending or receiving data. I realized that these needed to be outside the for (int i=0; i< 8; i++) loop as otherwise, the device would not be able to read/understand the data being passed. Do I need to reimplement some version of this with the Arduino Mega's native serial? If so, how would I do this?

Absolutely. Also you need to flush the serial after transmitting and switching back to receiving:

digitalWrite(DE_PIN, HIGH); 
Serial2.write(cmd, 8);
Serial2.flush();
digitalWrite(DE_PIN, LOW); 

Flushing the serial pauses your program until the entire command has been transmitted. That means not only sent from the TX buffer to the TX FIFO in the UART hardware, but also the last byte from the FIFO has been shifted out onto the wire. If you don't do that your command will get truncated by the transceiver module as you switch back to receive mode prematurely.

Note: I forget which is which for the DE pin - HIGH/LOW or LOW/HIGH. Change it appropriately. Also note that you don't need to manually loop - the Serial code already has that facility for you.

The converter must have the hardware and software support to tri-state the transmit buffer following the message transmission.

That is what the DE/RE pins do - switch the module between active drive (transmit) and high-impedance (receive).

I'd much rather use something like Majenko's pointer way to send data to my device so that I could make the code not rely on the fact that there are always 8 bytes transmitted. However, sometimes a byte will be \0 (or any other termchar) which would stop the loop prematurely. Is there a way to avoid this?

That is only applicable with strings. With binary data you always have to know the length (though that doesn't have to be hard coded). All you need is a maximum length for any buffers you have.

I'm still pretty new here, Is there some way that I can do this better than the way I'm currently doing it?

Besides my notes above, this method:

while(rep)
{
  for (int i=0; i< 8; i++)
  {
    Serial2.write(cmd[i]);   // Send C string
  }
  if(Serial2.available())
  {
    //device echoed == command recieved
    rep=false;
  }
}

is completely wrong. You are sending a command and then immediately looking for a response. You haven't given that response time to either be generated by the remote end or be received by the Mega.

Instead it should be:

  1. Send the command.
  2. Look for some response data
  3. If some data has arrived then add it to the response buffer
  4. If the whole response has not yet arrived go back to 2

You can also add 2.5: if it's been checking too long then abort with a "timeout".

2
  • Ok, I'll add the module back in. If they're electrically incompatible, any idea why it works sometimes? Is this the CS equlivlant to a stopped clock being right twice per day?
    – ATE-ENGE
    Aug 7, 2017 at 14:56
  • 1
    @ATE-ENGE Pretty much ;) Without the module you're connecting a differential pair to a single-ended TX / RX pair. The module is needed to convert single ended into differential and back again.
    – Majenko
    Aug 7, 2017 at 14:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.