问题 Serial Port ReadLine vs ReadExisting或如何正确读取串口数据


我正在从串口读取数据。数据来自规模。我现在正在使用 Readline() 删除后,即使数据丢失也是如此 DiscardInBuffer()。 从串口读取数据的正确方法是什么?网上的例子很少,我觉得这就像是一些没有人想到的圣杯。

有什么帮助吗?

好像串口是一个反复无常的孩子。

C#,WinCE 5.0,HP瘦客户端,Compact framework 2.0

 private void WeighSample()
    {
        this._processingDone = false;
        this._workerThread = new Thread(CaptureWeight);
        this._workerThread.IsBackground = true;
        this._workerThread.Start();
    } //end of WeighSample()


    private void CaptureWeight()
    {
         globalCounter++;
         string value = "";


          while (!this._processingDone)
          {
              try
              {

                 value = this._sp.ReadLine();

                  if (value != "")
                  {
                      if (value == "ES")
                      {
                          _sp.DiscardInBuffer();
                          value = "";
                      }
                      else
                      {
                          this.Invoke(this.OnDataAcquiredEvent, new object[] { value });
                      }
                  }
              }
              catch (TimeoutException)
              {
                  //catch it but do nothing
              }
              catch
              {
                  //reset the port here?
                  MessageBox.Show("some other than timeout exception thrown while reading serial port");
              }
          }


    } //end of CaptureWeight()

关于我的应用程序需要注意的一点是,当光标跳到文本框时,我启动线程(weighSample)。这样做的原因是重量也可以手动输入(部分需求)。所以我事先并不知道用户是否要在天平上按PRINT或输入重量。在获取数据之后的任何一种情况下,我退出工作线程。另外,请注意我没有使用串行端口事件DataReceived,因为我被告知它不可靠。

任何意见/想法欢迎。这是我第一次使用串口。


9887
2018-03-11 23:25


起源

什么语言,操作系统,硬件平台等? - MarkusQ
你在读什么样的数据?二进制?文本? - Eddie
我正在阅读文本数据 - sarsnake


答案:


我有 决不 祝ReadLine工作顺利。只要在数据可用时读取本地缓冲区,然后使用单独的线程扫描数据并自行查找换行符。


5
2018-03-12 12:58



快速问题 - 我已经轮询了已经在现有线程中运行的规模。我还需要一个单独的线程来扫描数据吗?我上班的时候会发布代码。 - sarsnake
通常我会启动一个工作线程来执行端口读取并将它们放入app缓冲区。当它将数据放入缓冲区时,它会设置一个事件,指示解析器线程查找数据行,然后将另一个事件引发到使用应用程序。您可能已经拥有其中一个。 - ctacke
总共有两个主题:一个主线程和一个工作线程?阻塞和非阻塞行为之间有什么区别? Read()阻塞吗? - sarsnake
是的,我通常有2个主题。也许3取决于确切的用例,但工人通常使用非常少的处理器处于等待状态。我认为Read是阻塞的,返回是基于驱动程序CommTimeouts(这就是我在OpenNETCF串行库中实现它的方式)。 - ctacke
我已经读过Read是非阻塞的 - 我很困惑,似乎没有人真正解释它是如何工作的。这样做是否安全:_sp.Read(buffer,0,_sp.BytesToRead);和缓冲区是char []谢谢!由于缺乏有关串口的信息,我感到不知所措。 - sarsnake


取决于输入数据的行尾(EOL)字符。如果您的数据是面向行的,则ReadLine是一个有效的函数,但您可能需要查看NewLine属性并确保为输入数据设置了相应的属性。

例如,如果您的比例输出EOL的换行然后设置 port.NewLine = "\n";

http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.newline.aspx


10
2018-03-11 23:52



这取决于设备配置吗? - sarsnake
我正在从秤中读取数据。在这种情况下,此值(换行符)是否必须与比例格式相对应?我现在将它设置为\ r \ n这是标准。 - sarsnake
非常感谢。我使用.NewLine设置为“\ r \ n”,因为扫描仪正在发送给我最后一个和.ReadLine()我得到的正是我所期待的。优秀的解决方 - JD - DC TECH
在读到这个答案之前,我在使用ReadLine时遇到了麻烦。我只是将port.NewLine设置为我的打印机作为EOL发送的内容(巧合的是“\ n”)并且它有效!谢谢! - João Victor Oliveira


我想对Elias Santos发表评论,但我没有足够的声誉。使用ReadExisting方法有一些问题:

https://msdn.microsoft.com/en-us/library/system.io.ports.serialport.readexisting(v=vs.110).aspx

请注意,此方法可能会留下尾随的前导字节   内部缓冲区,使BytesToRead值大于零。

我之前遇到过ReadExisting的一些问题,这是因为不需要的字节。使用Readline解决了这些问题。


1
2018-06-28 09:00



请注意,只要您提出另一个建议并将其格式化为答案,就可以添加另一个对另一个答案进行争议的答案。 - cybermonkey


if (serialPort1->IsOpen){
    if (serialPort1->BytesToRead>0){
        this->textBox1->Text += serialPort1->ReadExisting();
    }
}

0
2017-07-17 11:58



请详细说明为什么您认为此代码专用答案有助于解决问题。 - PMF