串口通讯
Unity 中的串口通讯和C#的处理方式基本一致,
- Serial.Read(); 可以读取缓存区中的十六进制数
- Serial.ReadLine();可以以字符串的方式读取
Read()函数的处理
但是Read()函数有一个大坑,就是他不是一次性全读取,而是将缓存区中的数据分多次(一般是两次)读取,这个情况的产生不是因为对方以两次发送过来,而是一次发送过来会放在缓存区,通过Read()函数将缓存区的数据读多次,也就是这个函数会执行多次。 这样就导致了我们要是直接在Read()下面直接进行数据处理,会将第一次的未完成数据进行处理,这样处理结果显然是错误的。、
解决问题的过程
我在遇到问题后查找的资料基本倾向于规定一个指定的接收长度,在未完成长度时继续读,直到读满长度后开始对数据进行处理。 但是我这边需要实现的功能是对三种不同长度的报文进行分类处理,这样的情况显然不对。所以只能是规定三种长度
对Read()函数的应用
所以我对串口接收数据的入口进行了一点点更改,Serial.BytesToRead函数是去直接获取缓存区的数据位数,可以通过检查缓存区的数据,进行下一步操作来确保将缓存区的数据读完。
// sp为串口
int index = 0; //用于记录此时的数据次序
int ReadToBytes = 0; //记录长度
byte[] readBuffer = new byte[20]; //接收数组初始化
while (true)
{
if (sp != null && sp.IsOpen)
{
try
{
int n = sp.BytesToRead;
if (n > 0)
{
readBuffer = new byte[sp.BytesToRead + 1];
ReadToBytes = sp.Read(readBuffer, 0, n);
if ((n == 7) || (n == 9) || (n == 13)) //是否符合接收长度
{
index = 0;
for (int i = 0; i < n; i++)
{
if (index >= n) index = n - 1; //理论上不应该会进入此判断,但是由于传输的误码,导致数据的丢失,使得标志位与数据个数出错
data[index] = readBuffer[i]; //将数据存入数据处理数组data中
index++;
}
}
}
DataProcessingFunction(index, data); //数据处理
}
catch (Exception ex)
{
if (ex.GetType() != typeof(ThreadAbortException))
{
}
}
}
Thread.Sleep(100);
}
这段代码实际上只是对入口进行了略微处理,在开始时新建一个接收线程,在每次接收完让这个线程休眠一段时间可以确保数据不会冲突。
弊端
这样的弊端也是有的,
- 干扰数据也是符合这几位的话也是会键入循环,不过可以加个校验,就可以不被处理直接忽略。
- 对偶然情况,比如发送端是分两次发送的正确数据无法处理,这样的情况这段代码无法排除。
结束
|