串行端口 - C# 写入后从串行端口接收的数据错误
本文关键字:串行端口 数据 错误 | 更新日期: 2023-09-27 17:57:02
我有一个通信设备,它通过COM每两秒发送一次请求。 在请求之间,设备等待响应。我正在使用 C# 构建软件 SerialPort
.我调用一个事件处理程序进行数据接收,并使用循环在新线程中运行一个方法while
该方法检查请求是否符合预期并调用负责响应的方法。问题是,响应后下一个接收到的数据是错误的。这是代码:SerialPortManager
:
class SerialPortManager : IDisposable
{
...
public void connect()
{
if (mSerialPort.IsOpen)
return;
mSerialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
try
{
mSerialPort.Open();
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
mStatus = Status.DISCONNECTED;
return;
}
if (mSerialPort.IsOpen)
{
mStatus = Status.CONNECTED;
Thread tryToResponseThread = new Thread(tryToResponse);
tryToResponseThread.Start();
}
}
private void tryToResponse()
{
while (mStatus == Status.CONNECTED)
{
if (mRequest.Length >= 56)
{
string checksum = "555555555555555580808080";
if (mRequest.Length > 56)
{
mRequest.Remove(55, mRequest.Length - 56);
Debug.Print("cutting");
}
if (mRequest.ToString().StartsWith(checksum))
{
StringBuilder strToCMD = new StringBuilder();
for (int i = 0; i < mRequest.Length; i += 2)
{
strToCMD.Append(mRequest[i]);
strToCMD.Append(mRequest[i + 1]);
strToCMD.Append(" ");
}
StringBuilder address = new StringBuilder();
StringBuilder group = new StringBuilder();
address.Append(mRequest.ToString(24, 8));
group.Append(mRequest.ToString(24 + 8, 2));
mMainForm.appendCMDTextboxText(Environment.NewLine);
mMainForm.appendCMDTextboxText(DateTime.Now.ToLongTimeString() + " [RX] " + address.ToString() + " " + group.ToString() + "'t");
mMainForm.appendCMDTextboxText(strToCMD.ToString());
byte[] request = ByteArrayConverter.fromString16(mRequest.ToString());
mRequest.Clear();
response(request);
Array.Clear(request, 0, request.Length);
Debug.Print("starts with checksum");
}
else if (mRequest.ToString().Contains(checksum))
{
int indexOfChecksum = mRequest.ToString().IndexOf(checksum);
mRequest.Remove(0, indexOfChecksum);
Debug.Print("contains");
}
else
{
int index = 0;
bool found = false;
for (int i = 0; i < checksum.Length; i++)
{
StringBuilder s = new StringBuilder();
int sub = mRequest.Length - checksum.Length + i + 2;
if (sub == mRequest.Length)
break;
s.Append(mRequest.ToString().Substring((Math.Max(0, mRequest.Length - checksum.Length + i + 2))));
s.Append(mRequest.ToString(0, i + 2));
if (s.ToString().Equals(checksum))
{
index = sub;
found = true;
break;
}
}
if (found)
{
mRequest.Remove(0, index);
}
else
{
mRequest.Clear();
}
Debug.Print("on start and end");
}
}
}
}
private void response(byte[] request)
{
Luminaire lumToResponse = mLuminaireManager.getLuminaire(request);
if (lumToResponse == null)
{
return;
}
else
{
if (lumToResponse.isNotResponding())
return;
}
byte[] responseMsg = lumToResponse.getWholeFrame(request);
mMainForm.setCommandLabelForResponsingLuminaire(lumToResponse);
mMainForm.appendCMDTextboxText(Environment.NewLine + DateTime.Now.ToLongTimeString() + " [TX]'t");
string responseMsgAsString = ByteArrayConverter.toString(responseMsg).Replace("-", " ");
mMainForm.appendCMDTextboxText(responseMsgAsString);
write(responseMsg, 0, responseMsg.Length);
mSerialDataEventArgs.clearData();
}
public void write(byte[] buffer, int offset, int count)
{
if (mStatus == Status.DISCONNECTED || mSerialPort.IsOpen == false)
{
mStatus = Status.DISCONNECTED;
return;
}
mSerialPort.Write(buffer, offset, count);
}
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (mStatus == Status.DISCONNECTED)
return;
int dataLength = mSerialPort.BytesToRead;
if (dataLength == 0)
return;
byte[] data = new byte[dataLength];
mSerialPort.Read(data, 0, dataLength);
mSerialDataEventArgs.setData(data);
mDataReceived?.Invoke(this, mSerialDataEventArgs);
}
...
}
用于传递接收到的数据的帮助器类:
public class SerialDataEventArgs : EventArgs
{
public SerialDataEventArgs()
{
}
public void setData(byte[] data)
{
clearData();
mData = data;
}
public SerialDataEventArgs(byte[] dataInByteArray)
{
mData = dataInByteArray;
}
public void clearData()
{
if (mData == null)
return;
Array.Clear(mData, 0, mData.Length);
}
public byte[] mData;
}
和主要类:
public partial class MainForm : Form
{
...
private void MainForm_Load(object sender, EventArgs e)
{
mSerialPortManager = new SerialPortManager();
mSerialPortManager.setPortBoudRate((int)numUpDown_SerialPortSpeed.Value);
mLuminaireManager = new LuminaireManager();
mSerialPortManager.mMainForm = this;
mSerialPortManager.mLuminaireManager = mLuminaireManager;
fixTableLayoutColumnSize(ref tl_SingleLuminaire);
fillTheRestOfSingleLuminaireGroupBoxes();
fillSerialPortComboBoxWithNamesOfAvailablePorts();
mSerialPortManager.mDataReceived += new EventHandler<SerialDataEventArgs>(serialPortManager_DataReceived);
mIsPaused = false;
}
private void serialPortManager_DataReceived(object sender, SerialDataEventArgs e)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new EventHandler<SerialDataEventArgs>(serialPortManager_DataReceived), new object[] { sender, e });
return;
}
if (mIsPaused)
return;
mSerialPortManager.mRequest.Append(ByteArrayConverter.toString(e.mData).Replace("-", ""));
}
...
}
通信应如下所示:
request: 5555555555555555808080800100000001001A0006070001060031B1
response: 55555555555555558080808001000000010000808076
request: 5555555555555555808080800200000001001A0006070001060034B2
response: 555555555555555580808080020000000100008041BA
request: 5555555555555555808080800300000001001A000607000106003473
response: 55555555555555558080808003000000010000804049
等等。这只是一个例子,请求框架应该是什么样子。如您所见,该设备要求 1、2、3、4 等。它总是按这个顺序询问。最后四个值只是校验和。回复后我收到的是这样的:
request: 5555555555555555808080800200000001001A0006070001060034B2
response: 555555555555555580808080020000000100008041BA
request: 55555555555555558080808002000000000A0100000000000000BCAE
在回答 2 之后,应该有一个 3 的请求。如果我将软件设置为不响应,则每个请求看起来都很好。我做错了什么?
好的,所以一切都很好。我的 COM 接口坏了:(两种方式都很好 - DataReceived 事件处理程序和 read() 紧跟在 write() 之后(无论哪种解决方案在编程方式上更好)。无论如何,谢谢大家尝试帮助我的案件!