0

我从串行端口接收数据,并在多行文本框中显示这些数据。数据有一个起始标题(>)、一个标识符(“T”或“I”或“N”)和一个结束标题(<)。因此,完整的消息类似于 >T123< 或 >N456< 或 >I086<。txtOutput 中显示的数据以正确的形状出现 >T123< 每行即使在串行输出窗口中它们以这种方式出现:

>T22
0<\r\n
>T22
2<\r\n
>T22
2<\r\n
>T223<\r\n
>
T225<\r\n
>
T228<\r\n
....

我需要过滤这些数据以在 PID 中进行一些计算,并且我创建了一个类来去除标题和标识符。该类返回已经在不同变量(a、b、c)中排序的数据,准备用于其他计算。这是从串口接收数据并将数据附加到txtOutput中的方法,这很好。然后该方法将数据发送到类“ strp.Distri(invia , out a, out b, out c)”。

 private void SetText(string text)
        {
            if (this.txtOutput.InvokeRequired)
            {
             SetTextCallback d = new SetTextCallback(SetText);
             this.BeginInvoke(d, new object[] { text });
            }
            else
            {
               txtOutput.AppendText(text);
               string a = "", b = "", c = "";
               string invia = text.ToString();
               Stripper strp = new Stripper();
               strp.Distri(invia, out a, out b, out c);

               textBox7.Text = a; //current
               textBox2.Text = b; //temperature
               textBox6.Text = c; //giri

这是我用来过滤和去除不必要字符的类。

 class Stripper
{

 public  void  Distri (string inComing, out string param1, out string param2, out string param3)

    {
        string current="";
        string temperature="";
        string numRPM="";
        string f = inComing;
        char firstChar = f[0];
        char lastChar =f [f.Length - 1];
        bool test1 =(firstChar.Equals('>'));
        bool test2 =(lastChar.Equals('<'));
        int messLenght = f.Length;

     if (test1 == true && test2 == true && messLenght <=6)
     {
        f = f.Replace("<", "");
        f = f.Replace(">", "");

             if (f[0] == 'I')
             {
              string _current = f;
             _current = _current.Replace("I", "");
              current = _current;
              }
            else if (f[0] == 'T')
            {
            string _temperature = f;
             _temperature = _temperature.Replace("T", "");
              temperature = _temperature;
            }
            else if (f[0] == 'N')
            {
            string _numRPM = f;
            _numRPM = _numRPM.Replace("N", "");
            numRPM = _numRPM;
            }

            else
            {}
     }

     else
     {}
        param1 = current;
        param2 = temperature;
        param3 = numRPM;

    }
}

这是我的串行端口和关联的委托:

delegate void SetTextCallback(string text);
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {

            try
            {
                SetText(serialPort1.ReadExisting());

            }

            catch (Exception ex)
            {
                SetText(ex.ToString());
            }

        }

我的问题是 a、b 和 c 没有返回任何内容,因为“test1”和“test2”之后的消息显然不是真的,因为它们是分片接收的。我怎么解决这个问题?有没有办法在我将它们发送到剥离器类之前正确地重新组合这些消息?

4

3 回答 3

1

当您收到数据时,将其附加到字符串中。继续检查 CRLF (\r\n),如果找到,则可以处理该行。但是请记住,由于从串口接收到的碎片,遇到结束后可能会有字符。

很久以前的某个时候,我需要类似的功能。因此,代码类似于下面。接收处理程序可以是这样(receivedText 是全局字符串,receivedData 是当前接收到的数据)

        receivedText = String.Concat(receivedText, receivedData);

        /* do nothing - already copied to buffer */
        if ((receivedText.Contains("\r\n") == false))
        {
            return;
        }

        /* get the lines from the received text */
        string[] lines = receivedText.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);

        /* process your lines here */

        /* keep the remaining portion of the fragment after the end of new line */
        if(receivedText.EndsWith("\r\n"))
        {
            receivedText = "";
        }
        else
        {
            receivedText = receivedText.Substring(receivedText.LastIndexOf('\n') + 1);
        }
于 2013-05-24T14:07:34.640 回答
1
  SetText(serialPort1.ReadExisting());

这就是它出错的地方。串行端口与其他设备之间的通信方式(如 TCP)没有什么不同。它只是实现了一个简单的流,它不会尝试为数据分配任何含义。它不偏向于数据的开始和结束位置。

因此,当您调用 ReadExisting() 时,您只会得到端口接收到的任何内容。它可以是任意数量的字符,通常是几个,因为串行端口不是很快。你的程序运行得越慢,你得到的字符就越多。

因此,就像 TCP 一样,如果您需要了解数据流的开始和结束,那么您需要一个协议。就像 TCP 具有 http、ftp 等协议一样。额外的字节添加到流数据中,可以帮助您弄清楚数据包的样子。串口领域使用的通用协议不多,大部分人都是自己做的。除了一个,常用于调制解调器。表示数据结束的特殊字符或字符串。很多时候是换行符。SerialPort.NewLine 属性允许您设置它,您可以通过使用 ReadLine() 而不是 ReadExisting() 来利用它。发射器必须合作,但它实际上需要传输这些字符。

它似乎已经这样做了,您的代码段正在显示 \r\n。Windows 中用于指示行尾的标准字符。所以只需将 NewLine 属性设置为 "\r\n" 并使用 ReadLine() 而不是 ReadExisting() 就可以了。但是,避免调用端口的 Close() 方法,如果您在设备发送时关闭程序,这可能会死锁。

于 2013-05-24T14:22:43.227 回答
0

例如输入字符串是“>T223<\r\n”,你的第一个字符是'>',最后一个字符是'<'。test1 会通过,但 test2 总是会失败。if 条件

if (test1 == true && test2 == true && messLenght <=6)

永远不会实现。从字符串中替换或删除不需要的字符。

于 2013-05-24T13:36:51.523 回答