【问题标题】:.NET SerialPort DataReceived event not firing.NET SerialPort DataReceived 事件未触发
【发布时间】:2010-02-17 14:52:16
【问题描述】:

我有一个 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. 当我点击表单上的按钮发送数据时,我的超级终端窗口(连接到 COM2)显示数据正在通过。是的,当我想测试我的表单读取端口的能力时,我断开了超级终端。

  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);
    }
}

这应该消除对线程问题的任何担忧(我认为)。这也不起作用。同样,超级终端报告通过端口发送的数据,但控制台应用程序似乎没有触发 DataReceived 事件。

编辑 #2:

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

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

如果我在 WPF 应用程序中键入内容,控制台应用程序 DataReceived 事件将触发,并回显数据。

我猜问题出在我使用 VSPE 软件的某个地方,该软件被设置为将一个串行端口同时视为输入和输出。通过 SerialPort 类的一些奇怪之处,一个串行端口的实例不能同时是发送者和接收者。反正我觉得解决了。

【问题讨论】:

    标签: .net serial-port


    【解决方案1】:
    port.DtrEnable = true;
    

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

    【讨论】:

    • 这对我来说也很有效,因为我花了 5 个小时费力地弄乱了连接到平板电脑的天平。一家公司的余额 (OHaus) 在没有这条线的情况下可以正常沟通,而下一家公司的余额 (Sartorius) 则不行。
    • 原来 Adafruit SAMD51 Arduino USB 驱动程序需要设置 DtrEnable 才能工作。感谢您的提示(六年后)!
    【解决方案2】:

    我不能肯定,但可能存在线程问题。 WPF 以不同的方式处理线程,我相信虚拟端口的轮询是异步的。您是否尝试过使用 Windows 窗体或控制台应用程序来证明它完全可以工作?

    【讨论】:

    • 参见上面的控制台版本。没有运气。
    【解决方案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);
    

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

    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
        }
    }
    

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

    System.IO.Ports.SerialPort.GetPortNames()
    

    【讨论】:

    • 在您编辑后,我发现您已经解决了一些问题,但您提到“通过 SerialPort 类的一些奇怪之处,一个串行端口的实例不能同时是发送方和接收器”这不是真的。 SerialPort 类既可以是发送者,也可以是接收者。既然你说事情似乎以某种方式锻炼,我不会详细说明:)
    • 那么听起来怪异的地方并不在于 SerialPort 类,而在于它与虚拟串行端口软件的耦合。
    • +1 - 将 RTS 引脚设置为启用是我忘记的。我忘了硬件流控制。
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      我也使用 VSPE!它确实工作得很好.. 我遇到了同样的问题,我修复它的方法是在 VSPE 中使两个 com 端口成为 PAIR,而不是仅仅创建两个虚拟 com 端口

      【讨论】:

        【解决方案6】:

        我最近遇到了一个类似的奇怪问题,但只是在某些机器上。正如Dave Swersky 所指出的,这可能是一个线程问题,尤其是当您在 .NET 4.0 或更高版本下运行时。

        在 .NET 4.0 中,事件处理程序是在 ThreadPool 线程上触发的,在某些情况下,在此之前可能会有相当长的延迟。 (在我的代码中,它在 .NET 2.0 下运行良好,一旦我们升级到 .NET 4.5,就会发现问题。事件处理程序的触发时间通常比预期的要晚得多,有时它不会在全部!)

        使用更大的完成线程值调用 ThreadPool.SetMinThreads(...) 会使问题尽快消失。在我们的应用程序的上下文中,ThreadPool.SetMinThreads(2, 4) 就足够了。在观察到问题的机器上,默认值(通过调用ThreadPool.SetMinThreads 获得)都是 2。

        【讨论】:

          【解决方案7】:

          两天前我遇到了同样的问题,因为我今天需要交付应用程序,这让我很头疼。所以.. 在太多 googleashion 之后,我认为问题是另一回事,而不是我的代码。

          我的解决方案是卸载 McAfee 防病毒软件以及与此相关的所有事情。当我看到 McAfee 的日志时,它有关于停止线程的记录,我认为 SerialDataReceivedEventHandler() 在线程中运行。

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

          【讨论】:

            【解决方案8】:

            我正在使用虚拟串行端口驱动程序。这个问题花了我一整天。最后通过创建一对端口来修复。一个端口发送消息,另一个端口接收消息,而不是使用同一个端口发送和接收消息。我猜这就是 Null Modem Emulator 的工作原理。

            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
            

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

            【讨论】:

            • 你的答案能更具体吗?喜欢粘贴代码块或配置屏幕截图?
            【解决方案9】:

            我只能推测问题确实出在 Virtual Serial Port Emulator 程序上。这并不是说该软件有问题:到目前为止,VSPE 对我来说效果很好。但是我的代码与我设置 VSPE 连接器的方式之间存在一些冲突。

            【讨论】:

              猜你喜欢
              • 2011-01-18
              • 1970-01-01
              • 1970-01-01
              • 2014-03-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多