串口通信通常会需要判断帧头.

byte[] headbyte = new byte[]{0x5F,0x5F,0xF5,0xF5};
/// <summary>
/// 查找帧头, if版
/// </summary>
/// <param name="serialPort"></param>
/// <returns></returns>
public void ReadToPackHead(SerialPort serialPort)
{
while (true)
{
if (serialPort.ReadByte() == headbyte[0])
{
if (serialPort.ReadByte() == headbyte[1])
{
if (serialPort.ReadByte() == headbyte[2])
{
if (serialPort.ReadByte() == headbyte[3])
{
break;
}
}
}
}
}
}

不得不说, 这个版本看上去有点傻, 但是从容易理解的角度来讲, 比起while 循环要好的太多了. 一般我们在设计帧头方面, 一般不会太过长的.

如果你更加喜好 循环版, 那么代码如下.

// 查找帧头 , 循环版, 这个看起来就不是那么容易理解了
public int ReadToPackHead(SerialPort serialPort)
{
int h = 1;
while (h < serialPort.BytesToRead)
{
if (serialPort.ReadByte() == headbyte[0])
{
bool ishead = true;

while (h < headbyte.Length)
{
if (serialPort.ReadByte() == headbyte[h])
{
h++;
}
else
{
ishead = false;
break;
}
}
if (ishead)
{
break;
}
}
}
return h;
}

串口读取数据的主代码

if(serialPort.IsOpen ==false)
{
serialPort.Open();
Thread.Sleep(200);
}

// 现在发送的命令返回的数据, 下次才能读取到.
serialPort.Write(cmdGetData, 0, cmdGetData.Length);
Thread.Sleep(500);


//找到起始帧
ReadToPackHead(serialPort);
//然后开始读取数据长度帧
byte[] lenbytes = new byte[2];
serialPort.Read(lenbytes, 0, 2);
int onePackLength = BitConverter.ToUInt16(lenbytes, 0);// 16位的数据, 按照8位发的所以需要*2
//pindex = pindex + 2;

Console.WriteLine("本包数据长度" + onePackLength);
//然后循环读取数据, 直到全部读取完整. 如果是小包的数据, 例如20个以下的, 会比较简单.
//但是如果数据量比较大, 则一次无法完全读取完毕所以应该要写入到buffer中然后进行合并.
byte[] onePackBuffer = new byte[onePackLength];
int newDataIndex = 0;

//这里使用循环的原因是, 串口的速度比较慢, 需要等串口把指定长度的数据都传过来之后再进行后续的处理.
while (newDataIndex < onePackLength)
{
if (serialPort.BytesToRead == 0)
{
continue;
}
serialPort.Read(onePackBuffer, newDataIndex, onePackLength);
newDataIndex = newDataIndex + serialPort.BytesToRead;
Thread.Sleep(1);
}