12

我尝试使用 Readline() 并且数据被丢弃,我尝试使用 Read() 但我不确定如何使用防错方法,因为我可能会一个接一个地收到几个数据包,而我无法知道会有另一个数据包进来。在数据包之间 BytesToRead 是 0,所以我不能使用它。当向缓冲区读取数据时,您有一个计时器还是让线程进入睡眠状态以允许所有数据包到达?

我搞不清楚了。不知道下一步该尝试什么。

我应该提一下,我不能保证从串行端口出来的字符串将以 \n 或 \r 或 \r\n 结尾。当用户按下 PRINT 时,我只需要一种简单的方法来读取来自秤的所有数据包。

有人在这里回答了我喜欢的想法 - 为所有数据包等待一定的时间,但他们删除了他们的答案。你有机会重新发布吗?

4

3 回答 3

22

你试过听课堂上的DataRecieved活动SerialPort吗?

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();
    }
于 2009-03-13T23:28:38.143 回答
10

我们不久前经历了同样的过程。

读取“数据包”的唯一方法是了解它们在流中的开始和结束位置。

来自msdn

因为 SerialPort 类缓冲数据,而 BaseStream 属性中包含的流不缓冲,所以两者可能会在有多少字节可供读取方面发生冲突。BytesToRead 属性可以指示有要读取的字节,但 BaseStream 属性中包含的流可能无法访问这些字节,因为它们已缓冲到 SerialPort 类。

我们使用后台线程(您可以使用 BackgroundWorker)将数据读入缓冲区。如果您无法使用 SerialPort.Newline 属性可靠地设置终止字符(因为它会有所不同!)那么您将需要实现自己的数据包检测系统,因为您将无法使用阻塞 SerialPort.Readline()方法。

您可以使用 SerialPort.Read() (或使用 SerialPort.ReadExisting() 方法的字符串)读取字节缓冲区,并在检测到数据中的有效数据包时生成事件。请注意, Read() (我假设 ReadExisting() )清空 SerialPort 的缓冲区,因此您需要将数据保存在其他地方。

如果您设置 SerialPort.ReadTimeout,您可以处理 TimeoutException 并有一种简单的方法来处理您的设备不传输的情况。如果您使用固定数量的字节或其他一些非终止方案,这是重置数据包检测的好方法。(如果您不需要部分数据包,请在超时时使用 SerialPort.DiscardInBuffer())。

祝你好运

于 2009-03-14T00:00:55.583 回答
4

由于字节可能随时进入,缓冲传入数据至关重要。所以你应该

  1. 缓冲传入的数据
  2. 扫描缓冲区以查找完整数据
  3. 从缓冲区中删除使用的数据

我只是想知道您是否仍然遇到串行端口问题。如果是这样,我用 C# 开发了一种串行端口编程语言,我相信它几乎可以解决每个人遇到的所有问题。

请您看一下并尝试一下好吗?例如; 您可以像下面这样缓冲来自串行端口的传入数据并轻松执行字符串操作。

state Init
  // define a global variable
  our $BUFFER = "";
  jump(Receive);
end state

state Receive
  recv();
  $len = length($DATA_PACKET);
  if("$len > 0") {
    $BUFFER += $DATA_PACKET;
    call(Parser);
  }
end state

state Parser
  // check if buffer matchs regular expression pattern
  if(match($BUFFER, "(?<WILLDELETE>.*?<STX>(?<DATA>.*?)<ETX>(?<CHECKSUM>[0-9A-F]{2}))")) {
    // Received complete data
    $lenData = length($WILLDELETE);
    $BUFFER = remove($BUFFER, 0, $lenData);

    // Do operations with the other parsed fields. $DATA and $CHECKSUM in this example.
  }
end state

该项目在 sourceforge 上免费提供,如果您有任何问题,请随时提问。

项目主页

下载链接

于 2010-10-29T11:37:14.503 回答