代码之家  ›  专栏  ›  技术社区  ›  TimothyP

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

  •  1
  • TimothyP  · 技术社区  · 16 年前

    假设我想要一个函数从serialport中读取数据 并返回字节[]。

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

    我也试着换了线。睡觉的时候要像:

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

    但这也带来了问题。(我知道我至少需要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 回复  |  直到 9 年前
        1
  •  3
  •   jasonh    16 年前

    我是这样做的:

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

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

    只要知道响应是对发送的东西的响应,就不是连接类的工作。通过将连接抽象成这样容易处理的东西,类的使用者可以清晰地维护逻辑,以确定响应是否是预期的。

        2
  •  0
  •   kenny    15 年前

    串行端口不好玩吗?我唯一的想法是你的FIFO,假设你的设备有一个和它的启用,正在被超越。

        3
  •  0
  •   Mateen Ulhaq    9 年前

    问题解决:

    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() 方法。