C#正在等待串行端口上的数据
本文关键字:数据 串行端口 在等待 | 更新日期: 2023-09-27 18:24:44
我正试图通过c#应用程序从指纹扫描仪获取数据,但在指纹发送之前,我的整个代码都会执行。
我尝试使用延迟函数和System.Threading.Thread.Sleep(1000)
,这样它就可以在下一步执行之前获得数据,但这一切似乎都是徒劳的。
谁能提供其他选择吗?
我正在使用"SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
"来获取数据。
这段代码非常适合我:
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
初始化并打开串行端口(特别是分配DataReceived
)。Proxy()
是一个函数,每次数据到达时都会调用它,它会触发一个事件。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
退出,则永远不会收到该事件。如果你有一个控制台应用程序,这是真的。
当使用表单应用程序时,它会保持表单和主线程处于活动状态,直到用户关闭它。