串口读取 [英] Serial port reading

查看:60
本文介绍了串口读取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 WinForms 和 Modbus 485 协议读取 3 个温度设备.基本上我必须定期向每个设备写入一个命令,等待响应,当我收到响应时,处理它.每个设备都有一个唯一的通信地址.为了定期发送命令,我使用了一个计时器.Timer1.interval=100;这就是我发送命令的方式以及处理响应的位置:

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           
        }

所以我的交流应该是:

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

然后再次发送命令device1.问题是我有时会收到通信超时错误,而且我确信所有设备每次都响应非常快.因为我已经预设了 sp.ReceivedBytesThreshold=8 我也开始收到 CRC 错误.我的回复应该总是 8 字节长.

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.

附言我也尝试将计时器间隔设置为 1000 毫秒,但这并没有解决我的问题

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

推荐答案

依赖 ReceivedBytesThreshold 是很脆弱的,一旦失去同步,表演就结束了.您的代码也很容易受到 DataReceived 可能触发的其他原因的影响,您没有检查 e.EventType 属性.对于二进制协议,当然可以是 SerialData.Eof.

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.

只需编写不依赖于 EventType 或可用字节数的健壮代码.像这样:

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

并在超时时将 rcveLen 重置为零.并确保超时不会太低,如果您的程序被换出,您可能会损失很多秒,使用 10 秒是安全的.

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.

这篇关于串口读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆