[英]How do I use dataReceived event of the SerialPort Port Object in C#?
我正在尝试创建一个小型应用程序来收集从连接到 COM10 的外部传感器接收到的数据。 我已经成功创建了一个小型 C# 控制台对象和应用程序,它使用 for 循环打开端口并在固定时间段内将数据流式传输到文件。
我想将此应用程序转换为使用 dataReceived 事件进行流式传输。 在阅读了Top 5 SerialPort Tips之后,我似乎仍然无法让它工作并且不知道我错过了什么。 我重写了控制台应用程序,以便所有代码都在 Main 中并粘贴在下面。 有人能帮我解释一下为什么即使我知道硬件正在向端口发送数据,事件处理程序 port_OnReceiveDatazz 也没有被调用吗?
谢谢
感谢@Gabe、 @ Jason Down和@abatishchev提供的所有建议。 我很难过,似乎无法让事件处理程序工作。 也许它与设备有关。 我可以忍受只在线程中读取端口并将数据直接流式传输到文件。
代码
namespace serialPortCollection
{ class Program
{
static void Main(string[] args)
{
const int bufSize = 2048;
Byte[] buf = new Byte[bufSize]; //To store the received data.
SerialPort sp = new SerialPort("COM10", 115200);
sp.DataReceived += port_OnReceiveDatazz; // Add DataReceived Event Handler
sp.Open();
sp.WriteLine("$"); //Command to start Data Stream
// Wait for data or user input to continue.
Console.ReadLine();
sp.WriteLine("!"); //Stop Data Stream Command
sp.Close();
}
// My Event Handler Method
private static void port_OnReceiveDatazz(object sender,
SerialDataReceivedEventArgs e)
{
SerialPort spL = (SerialPort) sender;
const int bufSize = 12;
Byte[] buf = new Byte[bufSize];
Console.WriteLine("DATA RECEIVED!");
Console.WriteLine(spL.Read(buf, 0, bufSize));
}
}
}
我认为你的问题是: **
sp.DataReceived += port_OnReceiveDatazz;
不应该是:
sp.DataReceived += new SerialDataReceivedEventHandler (port_OnReceiveDatazz);
**没关系,语法很好(我最初回答这个问题时没有意识到快捷方式)。
我还看到建议您应该为您的串行端口打开以下选项:
sp.DtrEnable = true; // Data-terminal-ready
sp.RtsEnable = true; // Request-to-send
您可能还必须将握手设置为 RequestToSend(通过握手枚举)。
更新:
发现一个建议,说你应该先打开你的端口,然后分配事件处理程序。 也许这是一个错误?
所以而不是这个:
sp.DataReceived += new SerialDataReceivedEventHandler (port_OnReceiveDatazz);
sp.Open();
这样做:
sp.Open();
sp.DataReceived += new SerialDataReceivedEventHandler (port_OnReceiveDatazz);
让我知道这是怎么回事。
首先,我建议您使用以下构造函数而不是您当前使用的构造函数:
new SerialPort("COM10", 115200, Parity.None, 8, StopBits.One);
接下来,您真的应该删除此代码:
// Wait 10 Seconds for data...
for (int i = 0; i < 1000; i++)
{
Thread.Sleep(10);
Console.WriteLine(sp.Read(buf,0,bufSize)); //prints data directly to the Console
}
而是循环直到用户按下某个键或其他东西,如下所示:
namespace serialPortCollection
{ class Program
{
static void Main(string[] args)
{
SerialPort sp = new SerialPort("COM10", 115200);
sp.DataReceived += port_OnReceiveDatazz; // Add DataReceived Event Handler
sp.Open();
sp.WriteLine("$"); //Command to start Data Stream
Console.ReadLine();
sp.WriteLine("!"); //Stop Data Stream Command
sp.Close();
}
// My Event Handler Method
private static void port_OnReceiveDatazz(object sender,
SerialDataReceivedEventArgs e)
{
SerialPort spL = (SerialPort) sender;
byte[] buf = new byte[spL.BytesToRead];
Console.WriteLine("DATA RECEIVED!");
spL.Read(buf, 0, buf.Length);
foreach (Byte b in buf)
{
Console.Write(b.ToString());
}
Console.WriteLine();
}
}
}
另外,请注意对数据接收事件处理程序的修订,它现在应该实际打印缓冲区。
更新 1
我刚刚在我的机器上成功运行了以下代码(使用 COM33 和 COM34 之间的空调制解调器电缆)
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
Thread writeThread = new Thread(new ThreadStart(WriteThread));
SerialPort sp = new SerialPort("COM33", 115200, Parity.None, 8, StopBits.One);
sp.DataReceived += port_OnReceiveDatazz; // Add DataReceived Event Handler
sp.Open();
sp.WriteLine("$"); //Command to start Data Stream
writeThread.Start();
Console.ReadLine();
sp.WriteLine("!"); //Stop Data Stream Command
sp.Close();
}
private static void port_OnReceiveDatazz(object sender,
SerialDataReceivedEventArgs e)
{
SerialPort spL = (SerialPort) sender;
byte[] buf = new byte[spL.BytesToRead];
Console.WriteLine("DATA RECEIVED!");
spL.Read(buf, 0, buf.Length);
foreach (Byte b in buf)
{
Console.Write(b.ToString() + " ");
}
Console.WriteLine();
}
private static void WriteThread()
{
SerialPort sp2 = new SerialPort("COM34", 115200, Parity.None, 8, StopBits.One);
sp2.Open();
byte[] buf = new byte[100];
for (byte i = 0; i < 100; i++)
{
buf[i] = i;
}
sp2.Write(buf, 0, buf.Length);
sp2.Close();
}
}
}
更新 2
鉴于最近有关此问题的所有流量。 我开始怀疑您的串行端口配置不正确,或者设备没有响应。
我强烈建议您尝试使用其他方式与设备通信(我经常使用超级终端)。 然后,您可以使用所有这些设置(比特率、奇偶校验、数据位、停止位、流量控制),直到找到有效的设置。 设备的文档还应指定这些设置。 一旦我弄清楚了这些,我将确保我的 .NET SerialPort 配置正确以使用这些设置。
配置串口的一些技巧:
请注意,当我说您应该使用以下构造函数时,我的意思是使用该函数,而不一定是那些参数! 您应该为您的设备填写参数,以下设置是通用的,但可能因您的设备而异。
new SerialPort("COM10", 115200, Parity.None, 8, StopBits.One);
将 .NET SerialPort 设置为使用与设备相同的流控制也很重要(正如其他人之前所述)。 您可以在此处找到更多信息:
http://www.lammertbies.nl/comm/info/RS-232_flow_control.html
我在使用以前工作过的调制解调器时遇到了同样的问题,然后有一天刚刚停止引发 DataReceived 事件。
在我的情况下,非常随机的解决方案是启用 RTS,例如
sp.RtsEnable = true;
不知道为什么这对这个特定的工具包起作用(根本不是一个通讯员),也不知道为什么它起作用然后停止了,但有一天它可能会帮助其他人,所以只是张贴它以防万一......
顺便说一句,您可以在事件处理程序中使用下一个代码:
switch(e.EventType)
{
case SerialData.Chars:
{
// means you receives something
break;
}
case SerialData.Eof:
{
// means receiving ended
break;
}
}
实际上,很可能是Console.ReadLine
阻塞了回调的Console.Writeline
。 MSDN 上的示例看起来几乎相同,除了它们使用 ReadKey(不锁定控制台)。
我相信这不会起作用,因为您使用的是控制台应用程序并且没有运行事件循环。 创建 Winforms 应用程序时会自动设置用于事件处理的事件循环/消息泵,但不会为控制台应用程序设置。
请注意,使用 .NET/C# 和任何高于 COM9 的 COM 端口存在问题。
格式中有一种变通方法:“\\\\.\\COM10”在基础 CreateFile 方法中受支持,但 .NET 阻止使用该变通方法格式; SerialPort 构造函数和 PortName 属性都不允许以“\\”开头的端口名称
我一直在努力在 C#/.NET 中获得与 COM10 的可靠通信。 例如,如果我在 COM9 和 COM10 上有一个设备,则发往 COM10 的流量会转到 COM9 上的设备! 如果我移除 COM9 上的设备,COM10 流量会流向 COM10 上的设备。
我仍然没有想出如何使用 CreateFile 返回的句柄来创建 C#/.NET 样式的 SerialPort 对象,如果我知道如何做到这一点,那么我想我可以从 C# 中很好地使用 COM10+。
switch(e.EventType)
{
case SerialData.Chars:
{
// means you receives something
break;
}
case SerialData.Eof:
{
// means receiving ended
break;
}
}
首先将您的行更改为:
sp.DataReceived += new SerialDataReceivedEventHandler(OnDataReceived);
其次,请注意每次到达一个字节时都会触发 DataReceived - 因此您每次读取的数据可能都是单个字符,如果每次处理事件时都覆盖它,“缓冲区”将永远不会保存整个消息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.