Modbus协议定义了从机地址,也就是说我们可以在一条总线上连接多台仪器,这些仪器使用从机地址进行区分。经过多年的开发,总结出一些共用串口方面需要注意的问题。
1、接收到的数据,必须检验从机地址
特别在多线程的开发环境下,先发送不一定先接收。也就是说,向A仪器发送信息之后,可能会收到B仪器返回的信息。这时候,如果我们把不是A仪器从机地址的信息丢弃,B仪器有可能就收不到信息了。最坏的情况是这样:发给A,收到B,发给B,收到A……。这样的话,将收不到A、B设备的任何信息。我们可以把收到的信息都存起来,然后分配给相应的从机地址的设备。
byte[] recv = ComPortDict[PortName].Receive();//接收数据,保存到临时变量
if (recv != null && recv.Length != 0)//数据不为空
{
int start = 0;
while (true)//处理粘包问题
{
if (recv.Length < start + 5)
{
break;
}
byte func = recv[start + 1];
int len = 8;
if (func == 0x01 || func == 0x02 || func == 0x03 || func == 0x04)//第2位为字节数
{
len = start + recv[start + 2] + 5;
}
if (recv.Length < len)
{
break;
}
byte[] data = new byte[len];
Array.Copy(recv, start, data, 0, len);//节选内容
string key = PortName + "_" + data[0];//加上从机地址保存
if (ComDataDict.ContainsKey(key))
{
ComDataDict[key] = data;
}
else
{
ComDataDict.Add(key, data);
}
start += len;
}
}
string key2 = PortName + "_" + SlaveAddr;
if (ComDataDict.ContainsKey(key2))
{
return ComDataDict[key2];
}
2、粘包问题
即使不是多设备共用串口,粘包问题也是会出现的。只是在多设备共用串口时,粘包出现的概率会非常高。这时候,只要我们把收到的字节流按Modbus协议切好即可。
protected byte[] CutModbusPart(byte[] recv)
{
if (recv == null)
{
return null;
}
int SlaveAddr = int.Parse(mDevice.Addition1);
int start = 0;
while (true)//处理粘包问题
{
if (recv.Length < start + 5)
{
break;
}
byte func = recv[start + 1];
int len = 8;
if (func == 0x01 || func == 0x02 || func == 0x03 || func == 0x04)//第2位为字节数
{
len = start + recv[start + 2] + 5;
}
if (recv.Length < len)
{
break;
}
byte[] data = new byte[len];
Array.Copy(recv, start, data, 0, len);//节选内容
if (data[0] == SlaveAddr)
{
return data;
}
start += len;
}
return null;
}
3、不同设备轮流发送,第一次发送会出现接收不到的问题
如题。假如我向A发送指令,收到A的返回。这时我再向B发命令,有可能是收不到B的返回的。我们需要再发一次,才能收到。最坏的情况是:发A,收A,发B,收B,这种很正常的流程,我们竟然也收不到信息。我们需要这样:发A,收A,发B,发B,收B。
不是所有设备都是这样的,只是某些。