Serial port reading

只愿长相守 提交于 2019-12-24 12:20:07

问题


I am trying to read 3 temperature devices using WinForms and the Modbus 485 protocol. Basically I have to periodically write a command to each device, wait for response and when I get the response, process it. Each device has a unique communication adress. In order to periodically send the command I am using a timer.Timer1.interval=100; This is how I am sending the command and where I am processing the response:

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;
                 }
        }

and so on for each device. This is my serialport data recieved event:

    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           
        }

So my communication should be :

send command device1
recieve response device1
send command device2
recieve command device2
send command device3
recieve command device3

and then send command device1 again. The problem is that I get sometimes get communication timeout error and I know for sure that all the devices are responding very quick and every time. Since I had preset the sp.ReceivedBytesThreshold=8I started to get CRC errors too. My response should always be 8 bytes long.

I think the problem is in the serial port data recieved event, but I can't see what's the problem.

P.S. I have also tried to set the timer interval to 1000 miliseconds, but that didn't solve my problem


回答1:


Relying on ReceivedBytesThreshold is very brittle, the show is over when you get out of sync once. Your code is also very vulnerable to other reasons that DataReceived may fire, you are not checking the e.EventType property. Which certainly can be SerialData.Eof for a binary protocol.

Just write robust code that doesn't depend on the EventType nor the number of available bytes. Like this:

    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;
        }        
    }

And reset rcveLen back to zero on a timeout. And make sure that the timeout isn't too low, you can lose many seconds if your program got swapped out, use 10 seconds to be safe.



来源:https://stackoverflow.com/questions/18899357/serial-port-reading

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!