C# 串口读取

C# 串口读取,c#,serial-port,C#,Serial Port,我正在尝试使用WinForms和Modbus 485协议读取3个温度设备。 基本上,我必须周期性地向每个设备写入命令,等待响应,当我得到响应时,处理它。每个设备都有一个唯一的通信地址。为了定期发送命令,我正在使用计时器。Timer1.interval=100 以下是我发送命令的方式和处理响应的位置: private void ProcessTimer_Tick(object sender, EventArgs e) { switch (tempState

我正在尝试使用WinForms和Modbus 485协议读取3个温度设备。 基本上,我必须周期性地向每个设备写入命令,等待响应,当我得到响应时,处理它。每个设备都有一个唯一的通信地址。为了定期发送命令,我正在使用计时器。
Timer1.interval=100
以下是我发送命令的方式和处理响应的位置:

private void ProcessTimer_Tick(object sender, EventArgs e)
    {

                switch (tempState)
                {
                    case TempTimerState.sendCommDevice1:
                        if (!tempSerial.IsOpen)
                        {
                            tempSerial.Open();
                        }
                        tempSerial.DiscardInBuffer();
                        communication.tempCommand[0] = 0x01;  //device adress
                        communication.tempCommand[6] = 0xA5;  //CRC
                        communication.tempCommand[7] = 0xC2;  //CRC
                        tempSerial.Write(communication.tempCommand, 0, 8);
                        tempState = TempTimerState.recievedDevice1;
                        communication.waitTime = 0;  //time to wait before throw a timeout exception
                        communication.dataRecievedTemp = false;  //flag for response recieved
                        break;
                    case TempTimerState.recievedDevice1:
                        communication.waitTime++;
                        if (communication.dataRecievedTemp)
                        {
                            communication.waitTime = 0;
                            if(CheckCRC(communication.tempResponse))  //CRC checking
                            {
                                //process response
                            }
                            else
                            {
                                //handle CRC Failure error
                            }
                        }
                        if(commcommunication.waitTime>=maxWaitTime)
                        {
                               //handle Timeout exception
                        }
                        tempState=TempTimerState.sendCommDevice2;
                        break;
                 }
        }
对于每个设备,等等。这是我的serialport数据接收事件:

    private void tempSerial_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            SerialPort sp = (SerialPort)sender;
            sp.Read(communication.tempResponse, 0, sp.BytesToRead);
            communication.dataRecievedTemp = true;  //flag for data recieved           
        }
因此,我的沟通应该是:

send command device1
recieve response device1
send command device2
recieve command device2
send command device3
recieve command device3
然后再次
发送命令设备1
。问题是,我有时会收到通信超时错误,而且我确信所有设备每次都会快速响应。由于我预先设置了sp.ReceivedBytesThreshold=8
,我也开始出现CRC错误。我的响应应该总是8字节长

我认为问题出在串行端口数据接收事件中,但我看不出问题出在哪里


另外,我还尝试将计时器间隔设置为1000毫秒,但这并没有解决我的问题

依赖ReceivedBytestThreshold非常脆弱,一旦失去同步,节目就结束了。您的代码也很容易受到DataReceived可能引发的其他原因的攻击,因为您没有检查e.EventType属性。对于二进制协议,它当然可以是SerialData.Eof

只需编写不依赖于EventType或可用字节数的健壮代码。像这样:

    private byte[] rcveBuf = new byte[8];
    private int rcveLen;

    private void tempSerial_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        SerialPort sp = (SerialPort)sender;
        rcveLen += sp.Read(rcvebuf, rcveLen, rcveBuf.Length - rcveLen);
        if (rcveLen == rcveBuf.Length) {
           Array.Copy(rcveBuf, communication.tempResponse, rcveBuf.Length);
           communication.dataRecievedTemp = true;
           rcveLen = 0;
        }        
    }

并在超时时将rcveLen重置回零。并且要确保超时时间不要太低,如果你的程序被调出,你可能会损失很多秒,使用10秒是安全的。

依赖ReceivedBytestThreshold是非常脆弱的,一旦你失去同步,节目就结束了。您的代码也很容易受到DataReceived可能引发的其他原因的攻击,因为您没有检查e.EventType属性。对于二进制协议,它当然可以是SerialData.Eof

只需编写不依赖于EventType或可用字节数的健壮代码。像这样:

    private byte[] rcveBuf = new byte[8];
    private int rcveLen;

    private void tempSerial_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        SerialPort sp = (SerialPort)sender;
        rcveLen += sp.Read(rcvebuf, rcveLen, rcveBuf.Length - rcveLen);
        if (rcveLen == rcveBuf.Length) {
           Array.Copy(rcveBuf, communication.tempResponse, rcveBuf.Length);
           communication.dataRecievedTemp = true;
           rcveLen = 0;
        }        
    }

并在超时时将rcveLen重置回零。并确保超时时间不太低,如果程序被调出,您可能会损失很多秒,请使用10秒来确保安全。

您的解决方案解决了我的CRC故障问题,但在连接超时时不起作用您的解决方案解决了我的CRC故障问题,但在连接超时时不起作用