串口碎片数据

时间:2013-05-24 13:17:37

标签: c# string serial-port

我从串口接收数据,并在多行文本框中显示这些数据。该数据具有起始标题(>),标识符(“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类之前,有没有办法正确地重新组装这些消息?

3 个答案:

答案 0 :(得分: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);
        }

答案 1 :(得分:1)

  SetText(serialPort1.ReadExisting());

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

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

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

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

答案 2 :(得分:0)

例如输入字符串是“&gt; T223&lt; \ r \ n”,您的firstchar将是'&gt;'和lastchar将是'&lt;'。 test1将通过,但test2将始终失败。 if条件

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

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

相关问题