SerialPort.ReadLine() 比手动方法慢? [英] SerialPort.ReadLine() slow compared to manual method?

查看:79
本文介绍了SerialPort.ReadLine() 比手动方法慢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近实现了一个小程序,它读取来自传感器的数据并将其绘制为图表.

I've recently implemented a small program which reads data coming from a sensor and plotting it as diagram.

数据以 5 个字节的块形式出现,大约每 500 微秒(波特率:500000).大约 3000 个块组成了一条完整的生产线.所以总传输时间约为 1.5 s.

The data comes in as chunks of 5 bytes, roughly every 500 µs (baudrate: 500000). Around 3000 chunks make up a complete line. So the total transmission time is around 1.5 s.

当我查看实时图表时,我注意到显示的内容与当前测量的内容之间存在严重滞后.调查,归结为:

As I was looking at the live diagram I noticed a severe lag between what is shown and what is currently measured. Investigating, it all boiled down to:

SerialPort.ReadLine();

传输时间比线路多大约 0.5 秒.所以每行读取大约需要 2 秒.有趣的是没有数据丢失,它只是在每次读取新行时落后更多.这对用户来说很刺激,所以我不能就这样离开.

It takes around 0.5 s more than the line to be transmitted. So each line read takes around 2 s. Interestingly no data is lost, it just lags behind even more with each new line read. This is very irritating for the user, so I couldn't leave it like that.

我已经实现了我自己的变体,它显示了大约 1.5 秒的一致时间,并且没有出现延迟.我对我的实现并不感到自豪(或多或少轮询 BaseStream),我想知道是否有办法加快 SerialPortReadLine 功能班级.在我的实现中,我也遇到了一些损坏的线路,但还没有找到确切的问题.

I've implemented my own variant and it shows a consistent time of around 1.5 s, and no lag occurs. I'm not really proud of my implementation (more or less polling the BaseStream) and I'm wondering if there is a way to speed up the ReadLine function of the SerialPort class. With my implementation I'm also getting some corrupted lines, and haven't found the exact issue yet.

我已经尝试将 ReadTimeout 更改为 1600,但这只会产生一个 TimeoutException.虽然数据到了.

I've tried changing the ReadTimeout to 1600, but that just produced a TimeoutException. Although the data arrived.

任何解释为什么它很慢或解决它的方法表示赞赏.

Any explanation as of why it is slow or a way to fix it is appreciated.

作为旁注:我已经在只有 SerialPort.ReadLine() 的控制台应用程序上尝试过这个,结果是一样的,所以我排除了我自己的应用程序影响 SerialPort.

As a side-note: I've tried this on a Console application with only SerialPort.ReadLine() as well and the result is the same, so I'm ruling out my own application affecting the SerialPort.

我不确定这是否相关,但我的实现如下所示:

I'm not sure this is relevant, but my implementation looks like this:

LineSplitter lineSplitter = new LineSplitter();
async Task<string> SerialReadLineAsync(SerialPort serialPort)
{
    byte[] buffer = new byte[5];
    string ret = string.Empty;

    while (true)
    {
        try
        {
            int bytesRead = await serialPort.BaseStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
            byte[] line = lineSplitter.OnIncomingBinaryBlock(this, buffer, bytesRead);
            if (null != line)
            {
                return Encoding.ASCII.GetString(line).TrimEnd('\r', '\n');
            }
        }
        catch
        {
            return string.Empty;
        }
    }
}

LineSplitter 如下:

With LineSplitter being the following:

class LineSplitter
{
    // based on: http://www.sparxeng.com/blog/software/reading-lines-serial-port
    public byte Delimiter = (byte)'\n';
    byte[] leftover;


    public byte[] OnIncomingBinaryBlock(object sender, byte[] buffer, int bytesInBuffer)
    {
        leftover = ConcatArray(leftover, buffer, 0, bytesInBuffer);
        int newLineIndex = Array.IndexOf(leftover, Delimiter);
        if (newLineIndex >= 0)
        {
            byte[] result = new byte[newLineIndex+1];
            Array.Copy(leftover, result, result.Length);
            byte[] newLeftover = new byte[leftover.Length - result.Length];
            Array.Copy(leftover, newLineIndex + 1, newLeftover, 0, newLeftover.Length);
            leftover = newLeftover;

            return result;
        }
        return null;
    }

    static byte[] ConcatArray(byte[] head, byte[] tail, int tailOffset, int tailCount)
    {
        byte[] result;
        if (head == null)
        {
            result = new byte[tailCount];
            Array.Copy(tail, tailOffset, result, 0, tailCount);
        }
        else
        {
            result = new byte[head.Length + tailCount];
            head.CopyTo(result, 0);
            Array.Copy(tail, tailOffset, result, head.Length, tailCount);
        }

        return result;
    }
}

推荐答案

我在 2008 年与 GPS 模块交谈时遇到了这个问题.本质上,阻塞函数是不稳定的,解决方案是使用 APM.

I ran into this issue in 2008 talking to GPS modules. Essentially the blocking functions are flaky and the solution is to use APM.

这是另一个 Stack Overflow 答案中的血腥细节:如何使用 .NET/C# 进行强大的 SerialPort 编程?

Here are the gory details in another Stack Overflow answer: How to do robust SerialPort programming with .NET / C#?

您可能还会对此感兴趣:如何终止挂起的 APM 操作

You may also find this of interest: How to kill off a pending APM operation

这篇关于SerialPort.ReadLine() 比手动方法慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆