如何在 C# 中使用 SerialPort 端口对象的 dataReceived 事件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/466474/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 04:31:24  来源:igfitidea点击:

How do I use dataReceived event of the SerialPort Port Object in C#?

c#serial-port

提问by Azim

I am attempting to create a small application to collect data received from an external sensor attached to COM10. I have successfully created a small C# console object and application that opens the port and streams data to a file for a fixed period of time using a for-loop.

我正在尝试创建一个小应用程序来收集从连接到 COM10 的外部传感器接收的数据。我已经成功创建了一个小的 C# 控制台对象和应用程序,它使用 for 循环在固定的时间内打开端口并将数据流式传输到文件。

I would like to convert this application to use the dataReceived event to stream instead. After reading the Top 5 SerialPort Tips, I still can't seem to it to work and don't know what I am missing. I rewrote the console application so that all the code is in Main and is pasted below. Can someone please help enlighten me as to why the event handler port_OnReceiveDatazz is not being called even though I know that there is data being sent to the port by the hardware?

我想将此应用程序转换为使用 dataReceived 事件进行流式传输。阅读Top 5 SerialPort Tips 后,我似乎仍然无法正常工作,也不知道我错过了什么。我重写了控制台应用程序,以便所有代码都在 Main 中并粘贴在下面。有人可以帮助我了解为什么即使我知道硬件正在将数据发送到端口,也没有调用事件处理程序 port_OnReceiveDatazz 吗?

Thanks

谢谢

Azim

阿齐姆

PS: Thanks to @Gabe, @Jason Down, and @abatishchevfor all the suggestions. I am stumped and can't seem to get the event handler to work. Perhaps it has something to do with the device. I can live with just reading the port in a thread and streaming the data straight to file.

PS:感谢@Gabe@Jason Down@abatishchev提供的所有建议。我很难过,似乎无法让事件处理程序工作。可能跟设备有关系。我可以忍受只读取线程中的端口并将数据直接流式传输到文件。



Code

代码



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));
        }
    }
}

回答by Jason Down

I think your issue is the line:**

我认为你的问题是:**

sp.DataReceived += port_OnReceiveDatazz;

sp.DataReceived += port_OnReceiveDatazz;

Shouldn't it be:

不应该是:

sp.DataReceived += new SerialDataReceivedEventHandler (port_OnReceiveDatazz);

sp.DataReceived += new SerialDataReceivedEventHandler (port_OnReceiveDatazz);

**Nevermind, the syntax is fine (didn't realize the shortcut at the time I originally answered this question).

**没关系,语法很好(我最初回答这个问题时没有意识到快捷方式)。

I've also seen suggestions that you should turn the following options on for your serial port:

我还看到建议您应该为您的串行端口打开以下选项:

sp.DtrEnable = true;    // Data-terminal-ready
sp.RtsEnable = true;    // Request-to-send

You may also have to set the handshake to RequestToSend (via the handshake enumeration).

您可能还必须将握手设置为 RequestToSend(通过握手枚举)。



UPDATE:

更新:

Found a suggestion that says you should open your port first, then assign the event handler. Maybe it's a bug?

发现一个建议,说你应该先打开你的端口,然后分配事件处理程序。也许这是一个错误?

So instead of this:

所以而不是这个:

sp.DataReceived += new SerialDataReceivedEventHandler (port_OnReceiveDatazz);
sp.Open();

Do this:

做这个:

sp.Open();
sp.DataReceived += new SerialDataReceivedEventHandler (port_OnReceiveDatazz);

Let me know how that goes.

让我知道这是怎么回事。

回答by abatishchev

By the way, you can use next code in you event handler:

顺便说一句,您可以在事件处理程序中使用下一个代码:

switch(e.EventType)
{
  case SerialData.Chars:
  {
    // means you receives something
    break;
  }
  case SerialData.Eof:
  {
    // means receiving ended
    break;
  }
}

回答by Gabe

First off I recommend you use the following constructor instead of the one you currently use:

首先,我建议您使用以下构造函数而不是您当前使用的构造函数:

new SerialPort("COM10", 115200, Parity.None, 8, StopBits.One);

Next, you really should remove this code:

接下来,您真的应该删除此代码:

// 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
}

And instead just loop until the user presses a key or something, like so:

而是循环直到用户按下某个键或其他东西,如下所示:

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();
        }
    }
}

Also, note the revisions to the data received event handler, it should actually print the buffer now.

另外,请注意对数据接收事件处理程序的修订,它现在应该实际打印缓冲区。

UPDATE 1

更新 1



I just ran the following code successfully on my machine (using a null modem cable between COM33 and COM34)

我刚刚在我的机器上成功运行了以下代码(使用 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();
        }
    }
}

UPDATE 2

更新 2



Given all of the traffic on this question recently. I'm beginning to suspect that either your serial port is not configured properly, or that the device is not responding.

鉴于最近有关此问题的所有流量。我开始怀疑您的串行端口配置不正确,或者设备没有响应。

I highly recommend you attempt to communicate with the device using some other means (I use hyperterminal frequently). You can then play around with all of these settings (bitrate, parity, data bits, stop bits, flow control) until you find the set that works. The documentation for the device should also specify these settings. Once I figured those out, I would make sure my .NET SerialPort is configured properly to use those settings.

我强烈建议您尝试使用其他方式与设备通信(我经常使用超级终端)。然后,您可以使用所有这些设置(比特率、奇偶校验、数据位、停止位、流量控制),直到找到有效的设置。设备的文档还应指定这些设置。一旦我弄清楚了这些,我将确保我的 .NET SerialPort 配置正确以使用这些设置。

Some tips on configuring the serial port:

配置串口的一些技巧:

Note that when I said you should use the following constructor, I meant that use that function, not necessarily those parameters! You should fill in the parameters for your device, the settings below are common, but may be different for your device.

请注意,当我说您应该使用以下构造函数时,我的意思是使用该函数,而不一定是那些参数!您应该为您的设备填写参数,以下设置是通用的,但您的设备可能会有所不同。

new SerialPort("COM10", 115200, Parity.None, 8, StopBits.One);

It is also important that you setup the .NET SerialPort to use the same flow control as your device (as other people have stated earlier). You can find more info here:

将 .NET SerialPort 设置为使用与设备相同的流控制也很重要(正如其他人之前所述)。您可以在此处找到更多信息:

http://www.lammertbies.nl/comm/info/RS-232_flow_control.html

http://www.lammertbies.nl/comm/info/RS-232_flow_control.html

回答by Justin Wignall

I was having the very same problem with a modem that had previously worked and then one day just stopped raising the DataReceived event.

我在使用以前工作过的调制解调器时遇到了同样的问题,然后有一天刚刚停止引发 DataReceived 事件。

The solution in my case, very randomly, was to enable RTS e.g.

在我的情况下,非常随机的解决方案是启用 RTS,例如

sp.RtsEnable = true;

No idea why that worked on this particular bit of kit (not a comms man at all really), nor why it had worked and then stopped but it may help somebody else one day so just posting it just in case...

不知道为什么这对这个特定的工具包起作用(根本不是一个通讯员),也不知道为什么它起作用然后停止了,但有一天它可能会帮助其他人,所以只是张贴它以防万一......

回答by Matt

I believe this won't work because you are using a console application and there is no Event Loop running. An Event Loop / Message Pump used for event handling is setup automatically when a Winforms application is created, but not for a console app.

我相信这不会起作用,因为您使用的是控制台应用程序并且没有运行事件循环。创建 Winforms 应用程序时会自动设置用于事件处理的事件循环/消息泵,但不会为控制台应用程序设置。

回答by Bart de Boer

Might very well be the Console.ReadLineblocking your callback's Console.Writeline, in fact. The sample on MSDN looks ALMOST identical, except they use ReadKey (which doesn't lock the console).

事实上,很可能会Console.ReadLine阻塞您的回调Console.Writeline。MSDN 上的示例看起来几乎相同,除了它们使用 ReadKey(不锁定控制台)。

回答by MikeZ

Be aware that there are problems using .NET/C# and any COM port higher than COM9.

请注意,使用 .NET/C# 和任何高于 COM9 的 COM 端口存在问题。

See: HOWTO: Specify Serial Ports Larger than COM9

请参阅:如何:指定大于 COM9 的串行端口

There is a workaround in the format: "\\.\COM10" that is supported in the underlying CreateFile method, but .NET prevents using that workaround format; neither the SerialPort constructor nor the PortName property will allow a port name that begins with "\"

格式中有一种变通方法:“\\.\COM10”在基础 CreateFile 方法中受支持,但 .NET 阻止使用该变通方法格式;SerialPort 构造函数和 PortName 属性都不允许以“\”开头的端口名称

I've been struggling to get reliable communications to COM10 in C#/.NET. As an example, if I have a device on COM9 and COM10, traffic intended for COM10 goes to the device on COM9! If I remove the device on COM9, COM10 traffic goes to the device on COM10.

我一直在努力在 C#/.NET 中获得与 COM10 的可靠通信。例如,如果我在 COM9 和 COM10 上有一个设备,则发往 COM10 的流量会转到 COM9 上的设备!如果我移除 COM9 上的设备,COM10 流量会流向 COM10 上的设备。

I still haven't figured how to use the handle returned by CreateFile to create a C#/.NET style SerialPort object, if I knew how to do that, then I think I could use COM10+ just fine from C#.

我仍然没有想出如何使用 CreateFile 返回的句柄来创建 C#/.NET 样式的 SerialPort 对象,如果我知道如何做到这一点,那么我想我可以从 C# 中很好地使用 COM10+。