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

时间:2009-06-12 03:45:36

标签: c# .net asynchronous serial-port

假设我想要一个从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
    }
}

但是我不能将数据作为我想要定义的函数的结果返回? 使用它的客户端代码必须订阅此代码引发的事件, 但那么它怎么知道响应真的是对它刚刚提出的请求的响应。

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

欢迎任何建议

更新

以下代码工作得更好,但如果我删除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);
    }    
}

3 个答案:

答案 0 :(得分:3)

以下是我的表现:

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

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

只要知道响应是对发送的内容的响应,就不是连接类的工作。通过将连接抽象为易于处理的东西,类的使用者可以干净地维护逻辑,以确定响应是否符合预期。

答案 1 :(得分:0)

串口不是很有趣。我唯一的想法是你的fifo,假设你的设备有一个并启用它,正在被超限。

答案 2 :(得分:0)

问题解决了:

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()方法中的代码。