.NET串口DataReceived事件未触发

6
我有一个WPF测试应用程序,用于评估基于事件的串口通信(与轮询串口相比)。问题是DataReceived事件似乎根本没有触发。

我有一个非常基本的WPF表单,其中包含用于用户输入的TextBox、用于输出的TextBlock和一个将输入写入串口的按钮。

下面是代码:

public partial class Window1 : Window
{
    SerialPort port;

    public Window1()
    {
        InitializeComponent();

        port = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One);
        port.DataReceived +=
            new SerialDataReceivedEventHandler(port_DataReceived);  
        port.Open();
    }

    void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        Debug.Print("receiving!");
        string data = port.ReadExisting();
        Debug.Print(data);
        outputText.Text = data;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Debug.Print("sending: " + inputText.Text);
        port.WriteLine(inputText.Text);
    }
}

现在,以下是复杂因素:
  1. 我使用一个名为Virtual Serial Port Emulator的软件在没有串口的笔记本上设置COM2端口。VSPE以前一直表现良好,不清楚为什么它只会在.NET的SerialPort类中发生故障,但我还是提到了这一点。

  2. 当我按下表单上的按钮发送数据时,我的Hyperterminal窗口(连接在COM2上)显示数据正在传输。是的,我想测试表单读取端口的能力时会断开Hyperterminal。

  3. 我尝试在连接事件之前打开端口。没有变化。

我已经阅读过另一篇帖子,其中其他人遇到了类似的问题。但那些信息都没有对我有所帮助。

编辑:

这是控制台版本(修改自http://mark.michaelis.net/Blog/TheBasicsOfSystemIOPortsSerialPort.aspx):

class Program
{
    static SerialPort port;

    static void Main(string[] args)
    {
        port = new SerialPort("COM2", 9600, Parity.None, 8, StopBits.One);
        port.DataReceived +=
            new SerialDataReceivedEventHandler(port_DataReceived);
        port.Open();

        string text;
        do
        {
            text = Console.ReadLine();
            port.Write(text + "\r\n");
        }
        while (text.ToLower() != "q");
    }

    public static void port_DataReceived(object sender,
        SerialDataReceivedEventArgs args)
    {
        string text = port.ReadExisting();
        Console.WriteLine("received: " + text);
    }
}

这应该消除了任何关于线程问题的担忧(我想)。但这也不起作用。Hyperterminal再次报告通过端口发送的数据,但控制台应用程序似乎没有触发DataReceived事件。

编辑#2:

我意识到我有两个单独的应用程序都应该从串行端口发送和接收数据,所以我决定尝试同时运行它们...

如果我在控制台应用程序中输入,WPF应用程序的DataReceived事件会触发,并出现预期的线程错误(我知道如何处理)。

如果我在WPF应用程序中输入,控制台应用程序的DataReceived事件会触发,并回显数据。

我猜问题出在我的VSPE软件使用上,它被设置为将一个串行端口同时视为输入和输出。由于SerialPort类的某些奇怪特性,一个串行端口实例不能同时充当发送方和接收方。无论如何,我认为问题已解决。

9个回答

24
port.DtrEnable = true;

这对我解决了问题,DataTransmitReady标志未启用,因此没有接收到数据。


1
在我折腾了五个小时的平板电脑连接天平后,这个方法对我也起作用了。一家公司的天平(OHaus)没有这行代码也能正常通信,而另一家公司的天平(Sartorius)则不行。 - jaredbaszler
3
原来Adafruit SAMD51 Arduino USB驱动程序需要设置DtrEnable才能正常工作。感谢这个提示(六年后)! - Brad Oestreicher

3

我使用完全相同的设置,现在它可以完美地工作,但是为了达到这个目标,我解决了许多问题。

以下是我的初始声明原因:

comControl = new SerialPort();

//This is important - determine your min nb of bytes at which you will fire your event, mine is 9
comControl.ReceivedBytesThreshold = 9; 

//register the event handlers
comControl.DataReceived += new SerialDataReceivedEventHandler(OnReceive);
comControl.PinChanged += new SerialPinChangedEventHandler(OnPinChanged);

我将打开端口和关闭端口的方法分开,因为我经常检查串口是否已关闭。

public bool OpenPort()
{
    try
    {
        //must keep it open to maintain connection (CTS)
        if (!comControl.IsOpen)
        {
             comControl.Open();
             comControl.RtsEnable = true;
        }
    }
    catch (Exception e)
    {
        //error handling here
    }
}

最后,请确认您的虚拟串口驱动程序已正确安装并且正在使用正确的端口,插入适配器时即插即用可能不够。如果您想创建一种控件,允许您在运行时选择可用的端口,则以下命令将提供可用的端口:

System.IO.Ports.SerialPort.GetPortNames()

1
在你的编辑之后,我看到你已经解决了一些问题,但是你提到“通过SerialPort类的某些奇怪行为,一个串口实例不能同时作为发送方和接收方”,这是不正确的。SerialPort类可以同时作为发送方和接收方。既然你说事情似乎已经解决了,我就不再赘述了 :) - Roast
那么,这肯定听起来不像是SerialPort类的问题,而是与虚拟串口软件耦合的问题。 - Klay
+1 - 将 RTS 引脚设置为启用是我忘记的事情。我忘记了硬件流控制。 - J. Polfer

3

我不能确定,但可能存在线程问题。WPF处理线程的方式不同,并且虚拟端口的轮询是异步的。你是否尝试过在Windows Forms或控制台应用程序中进行测试以证明它可以正常工作?


请参考上面的控制台版本。没有运气。 - Klay

0

两天前我也遇到了同样的问题,这让我非常头疼,因为我需要在今天交付应用程序。所以...经过了太多的谷歌搜索,我认为问题不是我的代码,而是其他的原因。

我的解决方案是卸载McAfee杀毒软件和所有相关的东西。当我看到McAfee的日志时,它记录了停止线程的信息,我假设SerialDataReceivedEventHandler()在一个线程中运行。

我希望这个解决方案对你有用。问候。


0

我正在使用虚拟串口驱动程序。这个问题让我整整一天都在解决。最终通过创建一对端口来解决了问题。一个端口发送消息,另一个端口接收消息,而不是使用同一个端口来发送和接收消息。我猜这就是空模拟器的工作原理。

Dim mySerialPort As SerialPort = New SerialPort("COM1")
Dim mySerialPort2 As SerialPort = New SerialPort("COM2")

Sub Main()
    SerialPortCommunicate()
End Sub

Public Sub SerialPortCommunicate()
    mySerialPort.BaudRate = 9600
    mySerialPort.Parity = Parity.None
    mySerialPort.StopBits = StopBits.One
    mySerialPort.DataBits = 8
    mySerialPort.Handshake = Handshake.None
    mySerialPort.DtrEnable = True
    mySerialPort.RtsEnable = True

    mySerialPort2.BaudRate = 9600
    mySerialPort2.Parity = Parity.None
    mySerialPort2.StopBits = StopBits.One
    mySerialPort2.DataBits = 8
    mySerialPort2.Handshake = Handshake.None
    mySerialPort2.DtrEnable = True
    mySerialPort2.RtsEnable = True

    AddHandler mySerialPort2.DataReceived, AddressOf DataReceivedHandler

    mySerialPort.Open()
    mySerialPort2.Open()

    mySerialPort.Write("Hello World")

    Console.WriteLine("Press any key to continue...")
    Console.WriteLine()
    Console.ReadKey()
    mySerialPort.Close()
    mySerialPort2.Close()
End Sub

Private Sub DataReceivedHandler(sender As Object, e As SerialDataReceivedEventArgs)
    Dim sp As SerialPort = CType(sender, SerialPort)
    Dim indata As String = sp.ReadExisting()
    Console.WriteLine("Data Received:")
    Console.Write(indata)
End Sub

结果: 收到的数据: 你好,世界 按任意键继续...


你能否更加具体地回答?例如贴出代码片段或配置截图? - Olympiloutre

0
我在从表单中运行这样的驱动程序时也遇到了类似的问题,尽管没有使用VSPE,只是一个简单的SP。 我相信这是一个STA模型的问题,将其包含在控制台应用程序中解决了足够的问题。

0

我最近遇到了一个类似的奇怪问题,但只在一些机器上出现。正如Dave Swersky所指出的那样,这可能是一个线程问题,特别是如果你正在运行.NET 4.0或更高版本。

在.NET 4.0中,事件处理程序在ThreadPool线程上触发,在某些情况下可能会有相当长的延迟才会发生。(在我的代码中,它在.NET 2.0下完美地工作,但一旦升级到.NET 4.5就出现了问题。事件处理程序通常会比预期触发得晚得多,有时甚至根本不会触发!)

调用 ThreadPool.SetMinThreads(...) 并将完成线程的值设置得更大,问题就像它出现一样迅速消失了。在我们的应用程序上下文中,ThreadPool.SetMinThreads(2, 4) 就足够了。在出现问题的机器上,通过调用 ThreadPool.SetMinThreads 获得的默认值都是 2。


0

我也使用VSPE!它确实非常好用。我曾经遇到过同样的问题,解决方法是在VSPE中将这两个串口配对,而不仅仅是创建两个虚拟串口。


-1
我只能猜测问题确实出在虚拟串口仿真器程序上。这并不是说该软件有问题:到目前为止,VSPE一直很好用。但我的代码与我设置的VSPE连接器之间存在某些冲突。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接