0

我正在尝试以非常快的速度连续从串行端口获取数据。波特率为230400。当我打印出数据、时间戳并BytesToRead写入文件时,我注意到每当BytesToRead下降到一个数字并且readLine()在这 200 毫秒内没有读取任何内容时,都会发生 200 毫秒的延迟。延迟后,BytesToRead回到 3000 左右,这个过程一次又一次地发生。本质上,我没有连续获取数据。

我想也许我的阅读速度比缓冲区中数据累积的速度要快,所以我尝试更改 readBuffer 大小并让该线程休眠 1 毫秒,以便让缓冲区跟上我正在阅读的速度。他们都没有工作。仍有一些延误。

欢迎任何想法。

 private void dostuff()//The thread I created after the port is opened
    {
        var startTime = DateTime.Now;
        var stopwatch = Stopwatch.StartNew();
        while (serialPortEncoder.IsOpen)
        {
            if (serialPortEncoder.BytesToRead > 210)
            {
                try
                {
                    var line = serialPortEncoder.ReadLine();
                    var timestamp = (startTime + stopwatch.Elapsed);
                    var lineString = string.Format("{0}  ----{1}",
                                    line,
                                    timestamp.ToString("HH:mm:ss:fff") + " "+serialPortEncoder.BytesToRead+"\r\n");

                    richTextBoxEncoderData.BeginInvoke(new MethodInvoker(delegate()
                    {
                        richTextBoxEncoderData.Text = line;//update UI                           
                    }));                                     
                }
                catch (Exception ex) { MessageBox.Show(ex.ToString()); }


            }}
4

3 回答 3

3

除非每 210 个字节换行一次,否则您的 ReadLine() 函数可能会超时并且什么也不返回。ReadLine() 将读取输入缓冲区,直到遇到换行值,然后返回之前的任何数据。http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.readline.aspx

什么样的信息正在通过港口?如果要读取特定大小的缓冲区,只需使用该Read方法即可。如果您需要阅读直到有换行符,请使用 ReadLine() 并经常检查它是否返回一个字符串。

于 2013-01-14T17:38:46.750 回答
2

您的代码存在根本性缺陷,它存在“热等待循环”错误。当串行端口没有足够的数据时,您的循环正在燃烧 100% 的核心。这将使 Windows 在您烧毁量子后将您的线程放在狗屋中一段时间​​,让其他线程有机会运行。在那个狗屋里呆 200 毫秒有点长,但肯定不是不寻常的。

您应该以不同的方式执行此操作,当串行端口实际有可用数据时,您应该让 Windows 有机会唤醒您。当它寻找下一个要调度的线程时,它有利于具有 I/O 完成的线程。这很容易做到,只需删除 BytesToRead 测试。ReadLine() 调用是一个阻塞调用,在收到 NewLine 之前不会返回。您的线程现在将消耗接近 0% 的 cpu 周期。

当机器负载过重或垃圾收集器运行时,您仍然会损失任意数量的时间。不,这还不足以可靠地读取编码器并关闭反馈回路。可靠地做到这一点需要一个具有可预测实时行为的微控制器。可从工业电子供应商处获得。

于 2013-01-14T17:46:17.767 回答
0

在网上进行了一番无休止的研究后,我找到了延迟的原因。设备管理器--->端口---->高级---->将延迟更改为1毫秒即可解决问题。现在,每次缓冲区降至零时,最多只需要 2ms 即可恢复正常。我现在正在使用单独的线程轮询数据。它工作得很好。

但就像 Hans Passant 所说,我正在尝试找出一种更好的设计方法。

于 2013-01-15T02:09:05.307 回答