C#正在等待串行端口上的数据

本文关键字:数据 串行端口 在等待 | 更新日期: 2023-09-27 18:24:44

我正试图通过c#应用程序从指纹扫描仪获取数据,但在指纹发送之前,我的整个代码都会执行。

我尝试使用延迟函数和System.Threading.Thread.Sleep(1000),这样它就可以在下一步执行之前获得数据,但这一切似乎都是徒劳的。

谁能提供其他选择吗?

我正在使用"SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)"来获取数据。

C#正在等待串行端口上的数据

这段代码非常适合我:

port = new SerialPort(port, 9600, Parity.None, 8, StopBits.One);
port.Open();
port.DiscardOutBuffer();
port.DiscardInBuffer();
port.DataReceived += OnScan;
void OnScan(object sender, SerialDataReceivedEventArgs args)
{
    SerialPort port = sender as SerialPort;
    string line = port.ReadExisting();
// etc
}

不幸的是,在C#中等待串行端口数据很棘手,没有什么比poll()更好的了。

有一个SerialPort.DataReceived,它接受对传入数据调用的函数。所以你在那里指定了一个函数来触发一个任意事件。您的另一个函数——实际等待的函数——应该等待此事件。

下面是一个简单的例子,注释如下,但简而言之:TestFunc初始化并打开串行端口(特别是分配DataReceivedProxy()是一个函数,每次数据到达时都会调用它,它会触发一个事件。WaitForAData()确实在等待数据出现时Proxy()将触发的事件。注意lock(){},如果没有它们围绕Monitor的函数,它将无法正常工作。

这只是一个例子,您可能想要重新生成WaitForAData()函数,以便在超时的情况下触发异常。如果Proxy()在您开始等待之前被触发,那么串行端口已经有数据,则添加一个布尔变量。但我测试了它(因为我现在需要这样的函数☺),并且它起作用。

namespace MyNamespace
{
class MySerial
{
    ///A condition variable that signals when serial has a data
    private System.Object SerialIncoming;
    public MySerial()
    {
        SerialIncoming = new Object();
    }
    /**
     * A proxy function that will be called every time a data arrived
     */
    private void Proxy(Object unused1, SerialDataReceivedEventArgs unused2)
    {
        Console.WriteLine("Data arrived!");
        lock (SerialIncoming)
        {
            Monitor.Pulse(SerialIncoming);
        }
    }
    /**
     * Waits for a data for the time interval Timeout
     * 'param Timeout a timeout in milliseconds to wait for a data
     * 'returns true in if a data did arrived, and false else
     */
    public bool WaitForAData(int Timeout)
    {
        lock (SerialIncoming)//waits N seconds for a condition variable
        {
            if (!Monitor.Wait(SerialIncoming, Timeout))
                {//if timeout
                    Console.WriteLine("Time out");
                    return false;
                }
            return true;
        }
    }
    /* Just a test function: opens a serial with speed, and waits
     * for a data for the «Timeout» milliseconds.
     */
    public void TestFunc(string serial, int speed, int Timeout)
    {
        SerialPort ser = new SerialPort(serial);
        ser.BaudRate = speed;
        ser.DataReceived += Proxy;
        ser.Open();
        if (WaitForAData(Timeout))
            Console.WriteLine("Okay in TestFunc");
        else
            Console.WriteLine("Time out in TestFunc");
    }
}
}

更新:这个问题浪费了我半天的时间,所以我希望我能节省一些人的时间:上面的代码在mono中不起作用(但在MS实现中起作用),因为在编写这些单词时不支持串行端口事件。

如果这是一个控制台应用程序,那么在调用COM端口组件的适当函数开始异步侦听后,可以使用Console.ReadLine()等。如果这是一个WinForms应用程序。消息循环当然会继续显示您当前的表单。在这种情况下,您可以在Form_Load事件中或单击按钮后调用异步侦听函数。

这里的关键点是,您应该调用侦听器函数的异步版本。在这种情况下,不需要使用延迟或定时器。

为什么不制作一个全局标记(bool),标记您是否收到了任何东西,并制作一个while(!marker){}循环,然后更改SerialPort_datareceived子例程中的标记?

thread.sleep可能会使您错过SerialPort数据发送?

串行端口在一个单独的线程中工作。因此,serialPort_DataReceived事件是从该线程中激发的。

因此,如果您的程序只启动串行端口,然后main退出,则永远不会收到该事件。如果你有一个控制台应用程序,这是真的。

当使用表单应用程序时,它会保持表单和主线程处于活动状态,直到用户关闭它。