C#分裂帧中的串行端口通信

C#分裂帧中的串行端口通信,c#,serial-port,modbus,C#,Serial Port,Modbus,我需要写一个程序,它将通过RS485监听ModBus网络中的通信。 我用RS485 USB加密狗连接到网络 我可以使用SerialPort.DataReceived事件读取一些数据,但它会给出奇怪的结果。 当数据应该是一个整体时,数据常常被分割。(Modbus主机每100ms传输一次) class串行 { 专用串行端口; 队列缓冲区; 公共序列号() { buffer=新队列(); 端口=新的串行端口(“COM3”,19200,奇偶校验,8,停止位,1); port.DataReceived+=

我需要写一个程序,它将通过RS485监听ModBus网络中的通信。 我用RS485 USB加密狗连接到网络

我可以使用SerialPort.DataReceived事件读取一些数据,但它会给出奇怪的结果。 当数据应该是一个整体时,数据常常被分割。(Modbus主机每100ms传输一次)

class串行
{
专用串行端口;
队列缓冲区;
公共序列号()
{
buffer=新队列();
端口=新的串行端口(“COM3”,19200,奇偶校验,8,停止位,1);
port.DataReceived+=端口_DataReceived;
}
公开作废
{
if(端口等参线)
{
port.Close();
}
port.Open();
}
无效端口\u DataReceived(对象发送方,SerialDataReceivedEventArgs e)
{
byte[]buff=新字节[port.BytesToRead];
读取端口(buff,0,port.BytesToRead);
buffer.Enqueue(buff);
}
}
我在传输中没有任何启动标志。
帧之间的延迟最小为3.5个字符,字符之间的最大延迟为1.5个字符。

这是完全正常的,串行端口是非常慢的设备。DataReceived事件在收到一个字节后立即触发。您需要调用Read(),并注意它返回的值,以及它能够从输入缓冲区检索的字节数。这可能不止一个,但很少等于“数据包”中的字节数,只有在机器由于某种原因变得非常慢的情况下才会发生

请注意,调试器是使其变慢的一种方法,断点或事件处理程序代码单步执行会给驱动程序足够的时间来接收数据包中的所有字节。因此,Read()调用将返回所有值。但一旦你停止调试代码,它就会停止工作


您可以使用ReceivedBytestThreshold属性来延迟事件,但这只能在数据包具有固定大小时起作用。只需使用Read()调用的第二个参数将得到的字节追加到byte[]中。在您拥有所有数据包之前不要处理数据包。

但我不知道一帧中有多少字节。DataReceived几乎可以正常工作,但它并不总是返回完整帧,有时它会一分为二。ModBus有点原始。希望您已经有了TCP帧,并且可以使用帧中的长度字段。如果没有,那么您必须从函数代码中计算出帧的长度。也许你应该去购买其他人的解决方案,从参考资料中联系你的经销商。嗯,事实上,这是RTU,而不是TCP。我买不到解决方案,因为这是我(我的团队)的学术项目。要推断你应该收到多少字节并不难。大多数MODBUS帧提供诸如功能代码和请求/传输数据的数量等线索。您可以(必须?)检查CRC的一致性,它限定了帧的结尾。示例:如果收到“读取多个寄存器”请求,则帧具有固定大小。如果收到“写入多个寄存器”请求,帧的长度(以字节为单位)将嵌入帧本身。串行端口没有任何数据包概念。它们完全是面向字节的,所以您期望“它们应该是一个整体”是错误的。您的读取代码必须处理读取任意数量的字节和查找数据包边界。
class Serial
{
    private SerialPort port;
    Queue<byte[]> buffer;

    public Serial()
    {
        buffer = new Queue<byte[]>();
        port = new SerialPort("COM3", 19200, Parity.Even, 8, StopBits.One);
        port.DataReceived += port_DataReceived;
    }

    public void Open()
    {
        if (port.IsOpen)
        {
            port.Close();
        }

        port.Open();
    }

    void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        byte[] buff = new byte[port.BytesToRead];
        port.Read(buff, 0, port.BytesToRead);
        buffer.Enqueue(buff);
    }
}