.NET SerialPort DataReceived事件未触发

时间:2010-02-17 14:52:16

标签: .net serial-port

我有一个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上连接)显示数据正在通过。是的,当我想测试我的表格读取端口的能力时,我断开Hyperterminal。

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

  4. 我在这里阅读了另一篇文章,其中有人遇到类似的问题。在这种情况下,这些信息都没有帮助我。

    修改

    这是控制台版本(从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 个答案:

答案 0 :(得分:13)

port.DtrEnable = true;

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

答案 1 :(得分:3)

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

答案 2 :(得分:2)

我使用完全相同的设置,它现在可以很好地工作但是必须解决很多问题才能到达那里。

这就是为什么我的初始声明如下:

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()

答案 3 :(得分:0)

我只能猜测问题确实存在于虚拟串行端口仿真器程序中。这并不是说该软件存在问题:到目前为止,VSPE对我来说效果很好。但是我的代码和我如何设置VSPE连接器之间存在一些冲突。

答案 4 :(得分:0)

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

答案 5 :(得分:0)

我也使用VSPE!它运行得非常好..我遇到了同样的问题,我修复它的方法是在VSPE中使两个COM端口成为PAIR而不是仅创建两个虚拟COM端口

答案 6 :(得分: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。

答案 7 :(得分:0)

两天前,我遇到了同样的问题,这是一个非常令人头痛的问题,因为我今天需要提供应用程序。所以......经过太多googleashion之后,我认为问题是另一回事而不是我的代码。

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

我希望这个解决方案适合你。问候。

答案 8 :(得分:0)

我正在使用虚拟串行端口驱动程序。这个问题整日困扰着我。最后通过创建一对端口进行修复。一个端口发送消息,另一个端口接收消息,而不是使用同一端口发送和接收消息。我猜这就是Nul​​l 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

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