How can I implement RS485 2 wires bidirectional communication in .NET?

jv42 picture jv42 · Sep 4, 2013 · Viewed 8.1k times · Source

I'm trying to get bidirectional communication using RS485 2 wires and everything I've tried so far failed.

I can send data and have my peripheral react as expected (so the wiring is correct), but I never receive any reply.


I'm using the .NET SerialPort, I've tried using the DataReceived event and also a loop in a Thread polling the port. I've even tried just blocking on read until enough data is received.


I have tried several hardware options:

  • PCI RS232 Card with a Sena RS232-RS485 converter
  • PCI RS232 Card with a Moxa RS232-RS485 converter
  • PCI RS485 Card

I have played with driver settings: - FIFO Interrupt Trigger levels - Receiver FIFO Flow Control Thresholds - RS485 Buffer enable (Normal, Active High, Active Low)


Following various leads (like Can't receive serial data in .net 2.0, using rs232 to rs485 converter), I've tried setting DtrEnable to true, or false, or switching it.

I've also tried switching RtsEnable when sending and receiving (following http://en.wikipedia.org/wiki/RS-232#RTS.2FCTS_handshaking).


I don't see anything else to try right now without resorting to different wiring. What could be wrong?


As requested, some code (it's only a snapshot after many attempts):

Open:

_serialPort = new SerialPort(comboBoxSerialPort.Text, 9600, Parity.None, 8, StopBits.One)
{
    WriteTimeout = 500,
    ReadTimeout = 500,
    Handshake = Handshake.None
};

_serialPort.Open();
_serialPort.DtrEnable = true;
_serialPort.RtsEnable = true;

Send:

_serialPort.RtsEnable = false;
_serialPort.Write(data, 0, data.Length);
_serialPort.RtsEnable = true;

Thread.Sleep(1);
_dataSent.Set();

Reader thread:

var port = form1._serialPort;
byte[] buffer = new byte[128];
int read = 0;
do
{
    Array.Clear(buffer, 0, buffer.Length);
    read = 0;

    try
    {
        form1._dataSent.WaitOne();

        //if (port.BytesToRead > 0)
        read = port.Read(buffer, 0, buffer.Length);
    }
    catch (TimeoutException)
    {
    }
    catch (Exception ex)
    {
        form1.Invoke(form1.AddErrorMethod, ex.ToString());
        continue;
    }

    if (read > 0)
    {
        form1.Invoke(form1.AddOutputMethod, ByteListToString(buffer));
    }

    Thread.Sleep(20);
}
while (_continue);

Note: data packets are 10 bytes long, in both directions.

Answer

jv42 picture jv42 · Sep 6, 2013

I've fixed the issue on one hardware configuration (the RS485 card) by:

  • fixing the wiring: although it's called '2 wires', 4 pins/wires from the card need to be used, joined, 2 by tranport wire.
  • using DtrEnable to indicate sending/receiving
  • waiting before enabling receive mode after a send.

My send code now looks like this:

// Enable send mode
SerialPort.DtrEnable = false;
SerialPort.Write(data, 0, data.Length);

// Wait a little, then enable response mode.
Thread.Sleep(15);
SerialPort.DtrEnable = true;