繁体   English   中英

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

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

假设我想拥有一个从SerialPort读取数据并返回byte []的函数。

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

像这样简单的事情实际上不能很好地工作/执行,也不是很可靠:

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

我也尝试用以下方式替换Thread.Sleep:

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

但这导致了问题。 (PS:我知道我至少需要14个字节)

当然,更好的方法(我认为)是:

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

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

然后当然有一个处理程序:

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

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

但是,由于我想定义的函数的结果,我不能返回数据吗? 使用此代码的客户端代码将必须预订此代码引发的事件,但是随后它将如何知道响应实际上是对刚刚发出的请求的响应。

(可能会发送多条消息,我可以想象一条消息在另一侧处理所需的时间比另一条或其他消息要长)。

任何建议都将受到欢迎

UPDATE

以下代码效果更好,但是如果删除Thread.Sleep()语句,它将再次停止正常工作。 例如,串行端口监视工具清楚地指示在串行线上已写入17个字节。 第一次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);
    }    
}

这是我的操作方法:

我为该类提供了一个包装器,该包装器在构造函数中接受连接的重要数据,并在该构造函数中进行基本设置。 该类的使用者调用Connect方法,该方法会激发另一个线程来执行连接(非阻塞)。

连接完成后,将触发StateEvent指示连接已完成。 这时设置了一个发送队列,触发了该队列的工作线程,并且还设置了一个读取线程。 读取线程从SerialPort读取128个字符的数据,将其转换为字符串,然后触发事件以传递接收到的数据。 这被包装在一个while线程中,只要保持连接,该线程就会循环。 当消费者想要发送东西时,Send方法只是使要发送的数据入队。

就知道响应是对已发送内容的响应而言,实际上并不是连接类的工作。 通过将连接抽象为一个易于处理的类,该类的使用者可以清晰地维护逻辑以确定响应是否是期望的。

串行端口不是很有趣。 我唯一的想法是,假设您的设备已启用并启用了设备,则它的FIFO已超载。

问题解决了:

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

似乎问题实际上不是此代码,而是dataCollector.Collect()方法中的代码。

暂无
暂无

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

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