22

我正在尝试创建一个小型应用程序来收集从连接到 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));
        }
    }
}
4

8 回答 8

15

我认为您的问题是: **

sp.DataReceived += port_OnReceiveDatazz;

不应该是:

sp.DataReceived += 新的 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);

让我知道情况如何。

于 2009-01-21T18:54:04.087 回答
8

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

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

于 2009-01-21T19:11:57.703 回答
4

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

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

sp.RtsEnable = true;

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

于 2009-06-08T12:36:26.960 回答
3

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

switch(e.EventType)
{
  case SerialData.Chars:
  {
    // means you receives something
    break;
  }
  case SerialData.Eof:
  {
    // means receiving ended
    break;
  }
}
于 2009-01-21T18:57:17.293 回答
1

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

于 2011-03-14T17:53:42.310 回答
1

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

于 2014-03-12T13:28:50.247 回答
0

请注意,使用 .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+。

于 2016-10-02T04:45:19.967 回答
0
switch(e.EventType)
{
  case SerilData.Chrs:
  {
    // means you receives something
    break;
  }
  case SerialData.Eo:
  {
    // means reciving ended
    break;
  }
}
于 2022-01-19T09:59:16.513 回答