【问题标题】:Serial port reading串口读取
【发布时间】:2013-09-24 19:32:09
【问题描述】:

我正在尝试使用 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 毫秒,但这并没有解决我的问题

【问题讨论】:

    标签: c# serial-port


    【解决方案1】:

    依赖 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 秒。

    【讨论】:

    • 您的解决方案解决了我的 CRC Failure 问题,但它不适用于连接超时
    猜你喜欢
    • 1970-01-01
    • 2017-07-23
    • 2018-11-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-18
    • 2011-12-24
    • 1970-01-01
    相关资源
    最近更新 更多