同一台 Windows 机器上的串行端口通信无法正常工作

Serial Port Communication on the same Windows machine not working

打扰一下,快速提问:

我有这个硬件设置:

Same machine: "Com3" -> USB -> To Serial -> To USB -> "Com4"

然后我按照 MSDN SerialPort Class and MSDN SerialPort.ReadLine() 构建了这个例程:

SerialPort SendSerialPort = new SerialPort("Com3", 9600);
SerialPort ReceiveSerialPort = new SerialPort("Com4", 9600);

SendSerialPort.Open();
ReceiveSerialPort.Open();

SendSerialPort.WriteLine("Test");
var message = ReceiveSerialPort.ReadLine(); // control stops here

SendSerialPort.Close();
ReceiveSerialPort.Close();

Console.WriteLine(message);

然而,当我倾向于 ReadLine() 时,我的控制会停止并等待。我没想到的是。

我期待收到字符串 Test 并将其分配给我的 var message。你能告诉我我做错了什么吗?

编辑:

我使用 Serial Port Utility Application and it worked just fine.

测试了我的硬件

我修改了from the example you linked:

要真正让两个端口 运行 来回读写,您实际上需要为两者实现读写线程。

使用计时器是个好主意。

public static void Main()
{
    SerialPort SendSerialPort = new SerialPort("Com3", 9600);
    SerialPort ReceiveSerialPort = new SerialPort("Com4", 9600);

    StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;
    Thread readThread = new Thread(Read);

    // Set the read/write timeouts
    _serialPort.ReadTimeout = 500;
    _serialPort.WriteTimeout = 500;

    SendSerialPort.Open();
    ReceiveSerialPort.Open();
    bool _continue = true;
    readThread.Start();

    Console.Write("Name: ");
    name = Console.ReadLine();

    Console.WriteLine("Type QUIT to exit");

    while (_continue)
    {
        message = Console.ReadLine();

        if (stringComparer.Equals("quit", message))
            _continue = false;
        else
            SendSerialPort.WriteLine(String.Format("<{0}>: {1}", name, message));
    }
    readThread.Join();
    SendSerialPort.Close();
}

public static void Read()
{
    while (_continue)
    {
        try
        {
            string message = ReceiveSerialPort.ReadLine();
            Console.WriteLine(message);
        }
        catch (TimeoutException) { }
    }
}

通常在写入的数据中会有一个开始和结束值,以告诉另一个端口消息已完成,并让端口验证它们正在读取它们应该是的数据,通常带有命令处理这些数据。 (超出此问题的范围)。

还缺少但重要的是你的端口的初始化。

我更喜欢使用默认构造函数(仅偏好)

SerialPort Constructor ()

然后像这样设置任何值:

_serialPort.BaudRate = SetPortBaudRate(_serialPort.BaudRate);
_serialPort.Parity = SetPortParity(_serialPort.Parity);
_serialPort.DataBits = SetPortDataBits(_serialPort.DataBits);
_serialPort.StopBits = SetPortStopBits(_serialPort.StopBits);
_serialPort.Handshake = SetPortHandshake(_serialPort.Handshake);

所有构造函数都会给出这些值:

This constructor uses default property values when none are specified. For example, the DataBits property defaults to 8, the Parity property defaults to the None enumeration value, the StopBits property defaults to 1, and a default port name of COM1.

连握手都有默认值。如果你look at the source code.

private const Handshake defaultHandshake = Handshake.None;

有可用数据时不能阻塞。您发送的内容要么卡在传输缓冲区中,要么由于接线错误而丢失,触发错误或被忽略。如果它与另一个程序一起工作,那么接线错误就不是问题。

请记住,仅设置波特率是不够的,您还必须设置 DataBits、Parity 和 Stopbits 属性以匹配设备设置。不匹配会触发错误,这种错误只有在为 ErrorReceived 事件编写事件处理程序时才能看到。永远不要跳过那个事件,如果你从不检查,可能会出现混淆问题。

最重要的是握手 属性 必须正确设置。正确的值取决于端口如何连接在一起,不连接它们太常见了。首先将其设置为 Handshake.None,这样 DSR 和 CTS 信号的错误状态就不会阻止接收,DTR 和 RTS 信号的错误状态也不会阻止传输。请注意,另一个程序启用硬件握手是很常见的,不匹配肯定会导致通信停止。

如果您使用同步读取而不是 DataReceived 事件,那么您通常应该处理设备没有响应的可能性。可能是因为它已关闭电源,根本未连接或发生故障。为此使用 ReadTimeout 属性,这样您的程序就不会挂起。志存高远,10000毫秒是一个合理的选择。

注意这个问题的随机性,换个程序可以很容易地正确配置端口,现在它会突然工作。请注意,启动一个线程不会完成任何事情,现在是该线程被卡住并且 Join() 调用将死锁。

你的代码问题出在这一行

var message = ReceiveSerialPort.ReadLine();

您阻止您的代码等待线路,如果该线路永远不会到达,它将永远留在这里或将值设置为 ReadTimeout

那为什么一直没有排队呢?

问题可能是 WriteLine("Test"); 中的一个错误,您应该处理错误,或者可能是您的 in 在 WriteLine("Test") 设法通过之前阻塞了您的代码 ReadLine() ,您可以在两者之间插入一个 Thread.Sleep(100) ,但这并没有真正改进代码。

注意:您的代码有时也会正常工作,具体取决于这些竞争条件。

这种从串口同步/阻塞读取的代码看起来很简单,只有一行;但它会在您的通信协议中产生很多负面影响。

更好的解决方案(考虑到您喜欢从微控制器读取/写入数据)是使用线程作为 or use asynchronously reading Stream.BeginRead (Byte[], Int32, Int32, AsyncCallback, Object) 我更喜欢。

异步读取将在串行端口上传入某些内容时抛出一个事件。这种编程策略的基本思想是不进行单步编程,而是期待任何结果,然后正确处理它。

在异步读取通信协议中 AutoResetEvent 非常有用,因此你发送一些东西,然后启动 AutoResetEvent,如果异步到达预期结果,你将设置此事件和你的代码可以继续,如果它没有到达 AutoResetEvent 将超时,你可以处理这个。