C#读取只读串口当数据到达时

8

我希望能够在串口接收到数据的时候读取数据,而非轮询方式。

以下是我的实现方式:

                Schnittstelle = new SerialPort("COM3");
                Schnittstelle.BaudRate = 115200;
                Schnittstelle.DataBits = 8;
                Schnittstelle.StopBits = StopBits.Two;
             ....

然后我启动了一个线程

             beginn = new Thread(readCom);
             beginn.Start();

在我的readCom函数中,我正在连续读取数据(有点像轮询 :()

private void readCom()
    {

        try
        {
            while (Schnittstelle.IsOpen)
            {

                Dispatcher.BeginInvoke(new Action(() =>
                {

                    ComWindow.txtbCom.Text = ComWindow.txtbCom.Text + Environment.NewLine + Schnittstelle.ReadExisting();
                    ComWindow.txtbCom.ScrollToEnd();
                }));

                beginn.Join(10);

            }
        }
        catch (ThreadAbortException) 
        {

        }

        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }

当中断到来时,我希望您可以读取它。但是我该如何做到这一点?

2个回答

37

您需要向DataReceived事件添加一个事件处理程序。

下面是来自msdn.microsoft.com的示例,经过一些编辑:请参阅注释!:

public static void Main()
{
    SerialPort mySerialPort = new SerialPort("COM1");

    mySerialPort.BaudRate = 9600;
    mySerialPort.Parity = Parity.None;
    mySerialPort.StopBits = StopBits.One;
    mySerialPort.DataBits = 8;
    mySerialPort.Handshake = Handshake.None;

    mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);

    mySerialPort.Open();

    Console.WriteLine("Press any key to continue...");
    Console.WriteLine();
    Console.ReadKey();
    mySerialPort.Close();
}

private static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
    SerialPort sp = (SerialPort)sender;
    string indata = sp.ReadExisting();
    Debug.Print("Data Received:");
    Debug.Print(indata);
}
每次有数据进来,DataReceivedHandler 就会触发并将您的数据打印到控制台。我认为您应该能够在您的代码中完成这个操作。

1
这个示例代码在 .NET 4.5 中已经不再安全使用。Console.ReadKey() 获得了一个锁,防止 Console.Write() 输出任何内容。Debug.Print() 可以正常使用。 - Hans Passant
@HansPassant,谢谢您的回复。这一定会破坏MSDN上许多线程示例 :) - kenny
他们确实这样做了。也有很多“让我们测试我的线程代码”的情况。对TDD来说有点打击。 - Hans Passant
1
@EricSmekens Debug.Print不是Console.ReadKey()的替代品,而是用于向控制台打印输出的。 - kenny
已经弄清楚了,我知道我做错了什么。 :p - Eric Smekens
@EricSmekens 我正在使用高级串口终端发送数据,这些数据需要被上面的代码接收,但是当终端打开时,C#程序无法运行,正确的使用方法是什么? - bouqbouq

5

在打开端口之前,您需要订阅DataReceived事件,然后在触发时监听该事件。

    private void OpenSerialPort()
    {
        try
        {
            m_serialPort.DataReceived += SerialPortDataReceived;
            m_serialPort.Open();
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message + ex.StackTrace);
        }
    } 

    private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        var serialPort = (SerialPort)sender;
        var data = serialPort.ReadExisting();
        ProcessData(data);
    }

串行通信,当缓冲区中有数据时,会触发数据接收事件,但这并不意味着您一次性获取了所有数据。您可能需要等待多次才能获取所有数据;这就是您需要单独处理接收到的数据的地方,也许可以将它们存储在某个缓存中,然后再进行最终处理。


我知道这已经是三年后的事了,但是为什么你的示例中没有包括 new SerialDataReceivedEventHandler(SerialPortDataReceived); 而上面的答案却有呢?这会有什么区别吗? - Xander Luciano
我的语法来自C# 2.0及以上版本。它与C# 1.0的语法完全等价,其中封装委托必须通过使用new关键字显式创建。 - Jegan

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