【问题标题】:What is the correct way to read a serial port using .NET framework?使用 .NET 框架读取串行端口的正确方法是什么?
【发布时间】:2012-12-06 23:45:44
【问题描述】:

我在这里阅读了很多关于如何使用 .NET SerialPort 类从串行端口读取数据的问题,但没有一种推荐的方法对我来说完全有效。

这是我现在使用的代码:

SerialPort port = new SerialPort("COM1");
port.DataReceived += new SerialDataReceivedEventHandler(MyDataReceivedHandler);

以及事件处理程序:

void MyDataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
    int count = port.BytesToRead;
    byte[] ByteArray = new byte[count];
    port.Read(ByteArray, 0, count);
}

但有时我仍然会丢失一些数据。我尝试了不同的方式来读取事件处理程序中的数据,但没有成功。

由于 .NET 4.5 为执行一些异步任务带来了新的可能性,例如似乎可以在 SerialPort 流上使用的 ReadAsync 方法,我很想知道处理这些情况的推荐方法是什么.

【问题讨论】:

  • 你的问题真的很模糊。 “我有时仍然丢失一些数据”就像告诉你的机械师“我的车有时会发出有趣的声音”并询问修理需要多少钱。也许this answer 对相关问题可能会有所帮助。但是,如果您需要帮助,我认为您需要更加具体;事实上,通过查看有关该主题的其他问题,没有什么是无法回答的。
  • 你说得对,我将一个真实的例子放在一起,以更好地说明正在发生的事情......
  • 通过 RS232 或 485 实现串行通信协议是一项非常非常艰巨的任务。这需要很多经验。自从良好的旧 DOS 时代以来,我一直在实施这一点,但仍然陷入一些常见的陷阱。您为什么不尝试寻找可靠的第三方产品来处理串行通信?他们可能已经解决了你自己会遇到的所有许多、许多、许多错误:-) 如果这是一个练习,那就继续吧,最终掌握串行通信会让你非常满意! :-)

标签: c# serial-port .net-4.5


【解决方案1】:

您可以尝试这样的事情吗?例如,我认为您想要使用的是 port.ReadExisting() 方法

 using System;
 using System.IO.Ports;

 class SerialPortProgram 
 { 
  // Create the serial port with basic settings 
    private SerialPort port = new   SerialPort("COM1",
      9600, Parity.None, 8, StopBits.One); 
    [STAThread] 
    static void Main(string[] args) 
    { 
      // Instatiate this 
      SerialPortProgram(); 
    } 

    private static void SerialPortProgram() 
    { 
        Console.WriteLine("Incoming Data:");
         // Attach a method to be called when there
         // is data waiting in the port's buffer 
        port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived); 
        // Begin communications 
        port.Open(); 
        // Enter an application loop to keep this thread alive 
        Console.ReadLine();
     } 

    private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) 
    { 
       // Show all the incoming data in the port's buffer
       Console.WriteLine(port.ReadExisting()); 
    } 
}

或者你想根据你想做的事情来做,你可以试试这个

public class MySerialReader : IDisposable
{
  private SerialPort serialPort;
  private Queue<byte> recievedData = new Queue<byte>();

  public MySerialReader()
  {
    serialPort = new SerialPort();
    serialPort.Open();
    serialPort.DataReceived += serialPort_DataReceived;
  }

  void serialPort_DataReceived(object s, SerialDataReceivedEventArgs e)
  {
    byte[] data = new byte[serialPort.BytesToRead];
    serialPort.Read(data, 0, data.Length);
    data.ToList().ForEach(b => recievedData.Enqueue(b));
    processData();
  }

  void processData()
  {
    // Determine if we have a "packet" in the queue
    if (recievedData.Count > 50)
    {
        var packet = Enumerable.Range(0, 50).Select(i => recievedData.Dequeue());
    }
  }

  public void Dispose()
  {
        if (serialPort != null)
        {
            serialPort.Dispose();
        }
  }

【讨论】:

  • 感谢您的帮助,我终于选择了 ReadExisting 与阻塞集合一起使用。我仍然打算尝试新的ReadAsync 功能...
  • processData() 方法不需要互斥体吗?我的意思是,当 processData() 仍在运行时,datareceived 事件可能会再次触发?不是吗?所以我们最终可能会在 processData() 方法中运行两个(甚至更多?)线程......
  • 我还没有尝试到那种程度,根据 Yannick 在上面评论中提到的内容,我认为如果他继续异步阅读不会有什么不同
  • 你错过了一些 static 修饰符
【解决方案2】:

我使用了与@MethodMan 类似的代码,但我必须跟踪串行端口正在发送的数据并查找终止字符以了解串行端口何时完成发送数据。

private string buffer { get; set; }
private SerialPort _port { get; set; }

public Port() 
{
    _port = new SerialPort();
    _port.DataReceived += new SerialDataReceivedEventHandler(dataReceived);
    buffer = string.Empty;
}

private void dataReceived(object sender, SerialDataReceivedEventArgs e)
{    
    buffer += _port.ReadExisting();

    //test for termination character in buffer
    if (buffer.Contains("\r\n"))
    {
        //run code on data received from serial port
    }
}

【讨论】:

  • ReadLine() 已经为您完成了这项工作。你不需要检查\n\r
  • 如果您使用ReadLine() 并且已发送多个回复,您可能不会阅读所有回复。 ReadExisting() 将读取多行,如果它们位于缓冲区中。
【解决方案3】:
    using System;
    using System.IO.Ports;
    using System.Threading;

    namespace SerialReadTest
    {
        class SerialRead
        {
            static void Main(string[] args)
            {
        Console.WriteLine("Serial read init");
        SerialPort port = new SerialPort("COM6", 115200, Parity.None, 8, StopBits.One);
        port.Open();
        while(true){
          Console.WriteLine(port.ReadLine());
        }

    }
}
}

【讨论】:

  • 如何不做的好例子
猜你喜欢
  • 2014-11-03
  • 1970-01-01
  • 2013-01-22
  • 1970-01-01
  • 1970-01-01
  • 2015-11-10
  • 1970-01-01
  • 1970-01-01
  • 2016-10-11
相关资源
最近更新 更多