我有一个运行nanopb的微控制器(Arduino Uno)正在通过线路发送protobuf消息。我发现在一个特定情况下,我没有收到我的完整信息。我想了一会儿它是微控制器,但它似乎是在C#端读取它。
问题仅发生在大于16或16以下的uint32值且工作正常。
我在微控制器上设置了一个非常简单的程序,以确保它不是我的其他代码导致它在那里。基本上它通过线路发送一个结构,其中包含一个uint32_t值:
//Protobuf message:
message Test { required uint32 testInt = 1 }
//Resulting struct:
typedef struct Test {
uint32_t testInt;
}
//Serial code:
Serial.begin(115200);
pb_ostream_t ostream;
//Removed ostream setup code as it's not relevant here...
Test message;
Test.testInt = 17;
pb_encode_delimited(&ostream, Test_fields, &message);
如果我插入设备并使用Termite查看数据输出,我会看到以下数据(这是正确的):
[02] [08] [11] (note Termite displays it in hex)
(那说消息是2个字节长,然后是msg起始字节,然后是十六进制的Test.testInt值17 - 0x11)
现在,如果我在C#中提到它,我应该在阅读消息时看到3个字节,但我只看到2.当testInt中的值为16或更小时,它会出现三个字节,17或更大而且我只有得到两个:
var port = new SerialPort("COM7", 115200, Parity.None, 8, StopBits.One);
port.Handshake = Handshake.RequestToSendXOnXOff;
port.Open();
while (port.IsOpen)
{
Console.WriteLine(port.ReadByte());
Thread.Sleep(10);
}
port.Close();
Console.ReadLine();
Output with 16: 2 8 16
Output with 17: 2 8 17
非常感谢任何帮助,我对这一点感到茫然=(
答案 0 :(得分:1)
看起来像一个简单的竞争条件 - 没有什么可以确保C#代码获得3个字节。它可以得到一个,两个,三个或更多。比方说,当两个字节在UART缓冲区中时,它会启动循环,然后它将获得两个字节并输出它们。我怀疑16/17问题只是巧合。
此外,当缓冲区中没有任何内容时,您的循环会消耗100%的CPU。那不好。
最好使用阻塞SerialPort.ReadByte()
调用,获取长度字节然后循环以从串行端口读取更多字节。
此外,作为一种协议,单独使用protobuf消息而没有标题标记并不是很好。如果你不同步,可能需要很长时间才能获得幸运并恢复同步。你可能想要添加某种魔术字节'或每个消息开头的一系列魔术字节,以便读者重新获得同步。
答案 1 :(得分:1)
您将串行端口设置为使用Xon / Xoff。为什么呢?
XON的代码是17。
如果您要发送二进制数据,请不要使用Xon / Xoff。