【问题标题】:C# waiting for the data on serial portC#等待串口上的数据
【发布时间】:2017-08-25 04:45:55
【问题描述】:

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

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

谁能提供任何其他选项?

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

【问题讨论】:

  • 邮政编码,所以有人可以帮助你。

标签: c# serial-port delay


【解决方案1】:

这段代码非常适合我:

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
}

【讨论】:

  • 它不等待数据,它只是读取现有数据。
  • @Hi-Angel 我认为代码应该按预期工作。 DataReceived 将仅在收到数据时(而不是立即)调用委托 OnScan
  • @Offler 是的。但是提问者期望的是在 SerialPort 上等待的代码。我的情况也是这样:假设我有某种串行连接,我想在几秒钟内等待数据,如果没有数据,则返回假设连接断开。这不是 Servè 编写的代码。顺便说一句,here was my answer 关于这个问题
  • @Hi-Angel 但是,如果您真的只想这样做,那么忘记事件中的所有内容可能会更容易。我已完成以下操作来访问 arduino “serial = new SerialPort(port, baudRate) { ReadTimeout = 2000 };”然后“try { int returnValue = serial.ReadByte(); return returnValue;} catch (TimeoutException) //将在 2 秒后发生 -> 损坏”。之后你就不需要一堆监视器等等。 (好吧,与 arduino 的通信是一个爱好项目中的一个自己的线程 - 该线程中的所有内容都按顺序运行......)
  • @Offler 不,这是一种悲哀。我是认真的。
【解决方案2】:

不幸的是,在 C# 中等待一个串口数据很棘手,没有像 poll() 这样的东西。

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

下面是一个简单的例子,有注释,但简而言之:TestFunc初始化并打开一个串口(特别是分配DataReceivedProxy() 是一个函数,每次数据到达时都会调用它,它会触发一个事件。而WaitForAData() 确实在等待数据出现时Proxy() 将触发的事件。请注意lock(){}s,如果没有它们围绕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 实现中工作) 因为 serial port events are not supported 在写这些话时。

【讨论】:

  • 你能帮我解决这个问题吗:stackoverflow.com/questions/55026042/…
  • @PrashantPimpale 抱歉,我已经有几年没有使用 C#了,希望以后也不会 :) 此外,我也没有方便的串口,我也不知道 Mono 是否(即非 Windows 系统上的唯一实现,因为我手边没有 Windows) 修复了串行端口事件。基本上,提款机,我根本没有办法帮你解决你的问题。
  • 好的,没问题!感谢您的回复顺便说一句!
【解决方案3】:

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

这里的关键点是你应该调用监听函数的异步版本。在这种情况下,无需使用延迟或计时器。

【讨论】:

  • 感谢您的意见。我是 C# 新手。您能否解释一下如何定义异步监听功能。它是一个 Windows 窗体应用程序。
  • 我相信您正在使用SerialPort 类。默认情况下,此类仅在同步模式下工作,因此您需要将其与BackgroundWorker 组件一起使用(或使用您自己的后台线程机制)。查看 MSDN 关于BackgroundWorker 组件的使用情况。它非常简单易用。你花在学习这个组件上的时间会在接下来的日子里给你带来很多回报。
【解决方案4】:

为什么不做一个全局标记 (bool),它会标记你是否收到任何东西,然后做一个 while(!marker) {} 循环,然后在 SerialPort_datareceived 子程序中更改标记?

thread.sleep 可能会让你错过 SerialPort 数据发送?

【讨论】:

  • 那是因为你必须进行线程间的值更改,所以找到如何将一个线程中的值挂到另一个线程。
【解决方案5】:

串行端口在单独的线程中工作。因此,serialPort_DataReceived 事件会从此线程中触发。

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

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

【讨论】:

  • 如果接收到一些数据并且 thread.sleep() 正在运行,那么它将丢弃该数据??
  • Thread.Sleep 用于当前线程。 DataReceived 事件是从不同的线程调用的,因此您将收到数据。
猜你喜欢
  • 2015-10-08
  • 1970-01-01
  • 2012-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多