如何在C#中使用SerialPort端口对象的dataReceived事件?
我正在尝试创建一个小应用程序来收集从连接到COM10的外部传感器接收的数据。 我已成功创建了一个小型C#控制台对象和应用程序,它使用for循环打开端口并将数据流传输到文件一段固定的时间。
我想转换此应用程序以使用dataReceived事件来代替流。 阅读前5个SerialPort提示后 ,我似乎仍然无法工作,也不知道我错过了什么。 我重写了控制台应用程序,以便所有代码都在Main中并粘贴在下面。 有人可以帮助启发我,为什么事件处理程序port_OnReceiveDatazz没有被调用,即使我知道硬件有数据被发送到端口?
谢谢
阿齐姆
PS:感谢@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; } }
我相信这不会起作用,因为您正在使用控制台应用程序并且没有运行Event Loop。 用于事件处理的事件循环/消息泵在创建Winforms应用程序时自动设置,但不适用于控制台应用程序。
事实上,很可能是Console.ReadLine
阻止你的回调的Console.Writeline
。 MSDN上的示例看起来几乎相同,除了它们使用ReadKey(它不锁定控制台)。
请注意,使用.NET / C#和任何高于COM9的COM端口都存在问题。
请参阅: HOWTO:指定大于COM9的串行端口
格式有一种解决方法:底层的CreateFile方法支持“\\。\ COM10”,但.NET阻止使用该解决方法格式; SerialPort构造函数和PortName属性都不允许以“\”开头的端口名称
我一直在努力在C#/ .NET中与COM10进行可靠的通信。 例如,如果我在COM9和COM10上有一个设备,那么用于COM10的流量将转到COM9上的设备! 如果我在COM9上删除设备,COM10流量将转到COM10上的设备。
我还没有想过如何使用CreateFile返回的句柄来创建一个C#/ .NET样式的SerialPort对象,如果我知道怎么做,那么我想我可以在C#中使用COM10 +。
- 可以调用Assembly.Load(byte )来引发AppDomain.AssemblyResolve事件吗?
- 是否有可能将unicode hex \ u0092显示(转换?)到.NET中的unicode html实体?
- 如何在文本文件中添加标头
- 使用Console.Writeline()或Console.Write()时,multithreadingC#控制台应用程序中偶尔会挂起
- 在IIS中重新启动应用程序池时立即运行Application_Start
- 使用字符串常量更改通知属性
- “公共”构造函数在抽象类中的相关性
- 如何从exe服务运行exe并在exe进程退出时停止服务?
- C#Keys Enumeration Confused:Keys.Alt或Keys.RButton | Keys.ShiftKey | Keys.Alt