上文提到了如何简单发送和接收串口数据。
在实际操作中,对于半双工通信(一问一答),如果需要一次发送多个指令,用DataReceived事件判断是否接收完毕,再发送下一条数据,不是很好的选择。
个人采用如下的方式,总的来说就是发送指令之后,用循环判断是否完成接收,未完成就延时一段时间再去判断,直到接收完成后再执行下一条指令:
先写好单条一问一答的函数:
有关接收事件GetCallbackData()代码如下:
private byte[] DataBuffer = new byte[1000];
private int bufferReadLength = 0;
private bool isAccept = false;
public object GetCallbackData()
{
if (!serialPort.IsOpen) return null;
bool isEnd = false;
while (!isEnd)//如果数据未接收完,则等待一会继续接收,直到接收完成跳出循环
{
Thread.Sleep(400);//延时等待接收完数据
isEnd = ComReceiveData();
}
var data = Analyse(DataBuffer.Clone() as byte[]);//将接收的byte[]数据按要求解析出来
DataBuffer = new byte[1000];
isAccept = false;
return data;
}
/// <summary>
/// 判断接收到的数据是否完整,并将接收的正确数据放入缓存变量中
/// </summary>
/// <param name="data">接受的数据</param>
public bool ComReceiveData()
{
try
{
byte[] buffle = new byte[serialPort.BytesToRead];
serialPort.Read(buffle, 0, buffle.Length);//查看返回的数据buffle
if (buffle.Length <= 0)
{
//MessageBox.Show("读取失败,请检查是否打开设备");
return true;
}
if (serialPort == null)
{
return true;
}
if (!serialPort.IsOpen)//串口在关闭时不接收数据 为了防止关闭串口时卡死的问题
{
serialPort.DiscardInBuffer();//丢弃接收缓冲区数据
return true;
}
bool isAll = false;
if (!isAccept)
{
isAccept = true;
}
if (DataBuffer[0] == 0x77 && DataBuffer[1] == 0xCC)//上次未接收完
{
var Length = DataBuffer.Length;
DataBuffer = RS485Helper.AddBytes(DataBuffer, buffle);//追加新数据
isAll = (Length == buffle.Length + bufferReadLength);
}
else//开始接收
{
if (buffle[0] == 0x77 && buffle[1] == 0xCC)
{
bufferReadLength = buffle.Length;
var length = (ushort)(buffle[3] << 8) + (ushort)buffle[4] + 6;//包长加包头包尾才是总长度
DataBuffer = new byte[length];
DataBuffer = RS485Helper.AddBytes(DataBuffer, buffle, false);//原缓存数据上追加新数据
isAll = (length == buffle.Length);
}
}
return isAll;
}
catch(Exception ex)
{
throw ex;
}
}
最后,在发送多条命令的地方使用函数
: