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

时间:2009-01-21 18:44:34

标签: c# serial-port

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

我想转换此应用程序以使用dataReceived事件来代替流。阅读Top 5 SerialPort Tips之后,我似乎无法工作,也不知道我错过了什么。我重写了控制台应用程序,以便所有代码都在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));
        }
    }
}

7 个答案:

答案 0 :(得分:12)

我认为你的问题就在于: **

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

让我知道这是怎么回事。

答案 1 :(得分:9)

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

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

答案 2 :(得分:4)

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

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

sp.RtsEnable = true;

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

答案 3 :(得分:3)

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

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

答案 4 :(得分:1)

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

答案 5 :(得分:1)

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

答案 6 :(得分:0)

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

请参阅:HOWTO: Specify Serial Ports Larger than COM9

格式有一种解决方法:底层的CreateFile方法支持“\\。\ COM10”,但.NET阻止使用该解决方法格式; SerialPort构造函数和PortName属性都不允许以“\”

开头的端口名称

我一直在努力在C#/ .NET中与COM10进行可靠的通信。例如,如果我在COM9和COM10上有一个设备,那么用于COM10的流量将转到COM9上的设备!如果我在COM9上移除设备,COM10流量将转到COM10上的设备。

我还没有想过如何使用CreateFile返回的句柄创建一个C#/ .NET样式的SerialPort对象,如果我知道怎么做,那么我想我可以在C#中使用COM10 +。