串行端口读取
本文关键字:读取 串行端口 | 更新日期: 2023-09-27 18:32:05
我正在尝试使用 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;
}
}
等等,每个设备。这是我的串行端口数据接收事件:
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
然后再次send command device1
。问题是我有时会得到通信超时错误,我确信所有设备每次都响应非常快。由于我预设了sp.ReceivedBytesThreshold=8
我也开始收到CRC错误。我的响应应始终为 8 个字节长。
在串口数据接收事件中,但我看不出有什么问题。
附言我还尝试将计时器间隔设置为 1000 毫秒,但这并没有解决我的问题
依赖 ReceivedBytesThreshold 非常脆弱,当你一次不同步时,节目就结束了。 您的代码也很容易受到 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 秒。