串行端口 - 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 的请求。如果我将软件设置为不响应,则每个请求看起来都很好。我做错了什么?

串行端口 - C# 写入后从串行端口接收的数据错误

好的,所以一切都很好。我的 COM 接口坏了:(两种方式都很好 - DataReceived 事件处理程序和 read() 紧跟在 write() 之后(无论哪种解决方案在编程方式上更好)。无论如何,谢谢大家尝试帮助我的案件!