简体   繁体   English

显然,这不是使用SerialPort读取的正确方法

[英]Obviously this is not the correct way to read with SerialPort

Let's say I want to have a function which reads data from the SerialPort and returns a byte[]. 假设我想拥有一个从SerialPort读取数据并返回byte []的函数。

public byte[] RequestData(byte[] data)
{
    //See code below
}

Something as simple as this really doesn't work/perform well and isn't very reliable: 像这样简单的事情实际上不能很好地工作/执行,也不是很可靠:

byte[] response = new byte[port.ReadBufferSize];

port.Open();    
port.Write(data, 0, data.Length);

Thread.Sleep(300); //Without this it doesn't even work at all

Console.WriteLine("Bytes to read: {0}", port.BytesToRead);

int count = port.Read(response, 0, port.ReadBufferSize);

Console.WriteLine("Read {0} bytes", count);

port.Close();
port.Dispose();       

return response.GetSubByteArray(0, count);

I also tried replacing the Thread.Sleep with something like: 我也尝试用以下方式替换Thread.Sleep:

while (port.BytesToRead < 14)
{
    //Maybe Thread.Sleep(10) here?
}

But that causes problems to. 但这导致了问题。 (PS: I know I need at least 14 bytes) (PS:我知道我至少需要14个字节)

Of course a better way (I think) would be to have something like: 当然,更好的方法(我认为)是:

port.ReceivedBytesThreshold = 14;
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
port.Open();

port.Write(data, 0, data.Length);

And then having a handler of course: 然后当然有一个处理程序:

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var port = (SerialPort)sender;

    while (port.BytesToRead > 0)
    {
        //Read the data here
    }
}

But then I can't return the data as the result of the function I wanted to define? 但是,由于我想定义的函数的结果,我不能返回数据吗? The client code using this would have to subscribe to an event raised by this code, but then how would it know the response is really the response to the request it just made. 使用此代码的客户端代码将必须预订此代码引发的事件,但是随后它将如何知道响应实际上是对刚刚发出的请求的响应。

(Multiple messages might be sent, and I can imagine one message taking longer to process on the other side than the other, or something). (可能会发送多条消息,我可以想象一条消息在另一侧处理所需的时间比另一条或其他消息要长)。

Any advise would be welcome 任何建议都将受到欢迎

UPDATE UPDATE

The following code works a lot better, but if I remove the Thread.Sleep() statements it once again stops working properly. 以下代码效果更好,但是如果删除Thread.Sleep()语句,它将再次停止正常工作。 For example, the serial port monitoring tool clearly indicates 17 bytes have been written on the serial line. 例如,串行端口监视工具清楚地指示在串行线上已写入17个字节。 The first time BytesToRead = 10 and the next time BytesToRead = 4 , but then BytesToRead remains 0 so where did the last 3 bytes go to ? 第一次BytesToRead = 10,下一次BytesToRead = 4,但是BytesToRead仍然为0,那么最后3个字节去了哪里?

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    Thread.Sleep(100);
    while (port.BytesToRead > 0)
    {
        Console.WriteLine("Bytes to read: {0}", port.BytesToRead);
        var count = port.BytesToRead;

        byte[] buffer = new byte[count];

        var read = port.Read(buffer, 0, count);

        if (count != read)
            Console.WriteLine("Count <> Read : {0} {1}", count, read);

        var collectAction = new Action(() =>
        {
            var response = dataCollector.Collect(buffer);

            if (response != null)
            {
                this.OnDataReceived(response);
            }
        });

        collectAction.BeginInvoke(null, null);
        Thread.Sleep(100);
    }    
}

Here's how I've done it: 这是我的操作方法:

I have a wrapper for the class that accepts the vital data for the connection in the constructor and does the basic setup in that constructor. 我为该类提供了一个包装器,该包装器在构造函数中接受连接的重要数据,并在该构造函数中进行基本设置。 The consumer of the class calls a Connect method, which fires off another thread to perform the connection (non-blocking). 该类的使用者调用Connect方法,该方法会激发另一个线程来执行连接(非阻塞)。

When the connection is complete, a StateEvent is fired indicating the connection is completed. 连接完成后,将触发StateEvent指示连接已完成。 At this time a Send queue is setup, a thread to work that queue is fired off and a read thread is also setup. 这时设置了一个发送队列,触发了该队列的工作线程,并且还设置了一个读取线程。 The read thread reads 128 characters of data from the SerialPort, converts that to a string and then fires an event to pass along the received data. 读取线程从SerialPort读取128个字符的数据,将其转换为字符串,然后触发事件以传递接收到的数据。 This is wrapped in a while thread that loops as long as the connection is maintained. 这被包装在一个while线程中,只要保持连接,该线程就会循环。 When the consumer wants to send something, a Send method simply enqueues the data to be sent. 当消费者想要发送东西时,Send方法只是使要发送的数据入队。

As far as knowing that the response is in response to something that was sent really isn't the job of a connection class. 就知道响应是对已发送内容的响应而言,实际上并不是连接类的工作。 By abstracting away the connection into something as easy to handle as that, the consumer of the class can cleanly maintain the logic to determine if the response is what it expected. 通过将连接抽象为一个易于处理的类,该类的使用者可以清晰地维护逻辑以确定响应是否是期望的。

Aren't serial ports fun. 串行端口不是很有趣。 My only thought is that your fifo, assuming your device has one and its enabled, is being overrun. 我唯一的想法是,假设您的设备已启用并启用了设备,则它的FIFO已超载。

Problem solved: 问题解决了:

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    var count = port.BytesToRead;
    byte[] buffer = new byte[count];
    var read = port.Read(buffer, 0, count);

    var response = dataCollector.Collect(buffer);

    if (response != null)
    {
        this.OnDataReceived(response);
    }            
}

It seems the problem wasn't actually this code but the code in the dataCollector.Collect() method. 似乎问题实际上不是此代码,而是dataCollector.Collect()方法中的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM