繁体   English   中英

串口碎片数据

[英]Serial port fragmented data

我从串口接收数据,并在多行文本框中显示这些数据。 数据具有起始标题(>),标识符(“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”之后的消息显然不正确,因为它们是以片段形式接收的。 我怎么解决这个问题? 在我将它们发送到Stripper类之前,有没有办法正确地重新组装这些消息?

当您收到数据时,将其附加到字符串。 继续检查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);
        }
  SetText(serialPort1.ReadExisting());

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

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

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

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

例如,输入字符串是“> T223 <\\ r \\ n”,你的firstchar将是'>',而lastchar将是'<'。 test1将通过,但test2将始终失败。 if条件

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM