我从串口接收数据,并在多行文本框中显示这些数据。该数据具有起始标题(>),标识符(“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类之前,有没有办法正确地重新组装这些消息?
答案 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)
永远不会实现。替换或删除字符串中不需要的字符。