简体   繁体   English

通过C#中的串行端口进行高速串行通信

[英]High speed serial communication over serial port in C#

I am working with visual studio 2019. I am sending data from microcontroller over uart/serial port to the PC and I want to read it on the PC side. 我正在使用Visual Studio2019。我正在通过uart /串行端口将数据从微控制器发送到PC,我想在PC端读取数据。

The baud rate is 9600. I am using the following code. 波特率为9600。我正在使用以下代码。 However, its very slow. 但是,它非常慢。 I need to be able to read the code with very high speed (comparable to the baud rate I use). 我需要能够以非常高的速度读取代码(与我使用的波特率相比)。

At present, I am getting 2-3 packets per second. 目前,我每秒收到2-3个数据包。 The timer interval is set at 10ms but even if I change it to 1ms, there is no difference. 计时器间隔设置为10毫秒,但是即使将其更改为1毫秒,也没有任何区别。 I cant figure out what am I doing wrong. 我不知道我在做什么错。 Help will be greatly appreciated. 帮助将不胜感激。

Regards, Salman 问候,萨尔曼

    public void  readCapsule(SerialPort sp)
    {
        timer1.Enabled = false;

        string headerStart = "";
        string headerEnd = "";
        List<Int32> newCoordinates = new List<Int32>();

        headerStart = sp.ReadLine();

        if (headerStart == "START")
        {               
            for (int i = 0; i < 3; i++)
            {
                Int32 coords = sp.ReadByte();
                newCoordinates.Add(coords);
            }

            tbRead.AppendText("X: " + newCoordinates[0].ToString() + " ");
            tbRead.AppendText("Y: " + newCoordinates[1].ToString() + " ");
            tbRead.AppendText("Z: " + newCoordinates[2].ToString() + Environment.NewLine);

            headerEnd = sp.ReadLine();
            newCoordinates.Clear();                
        }
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        readCapsule(spCapsule);            
        Application.DoEvents();
        spCapsule.DiscardInBuffer();
        timer1.Enabled = true;
    }

My Microcontroller code is basically incrementing 3 variables and sending them in between the START and END header. 我的微控制器代码基本上是递增3个变量并将其发送到START和END标头之间。 I know that there are other lines being executed so the throughput wont be 9600 but the delay I experience is WAY too long to be contributed from the microcontroller side I think. 我知道还有其他行正在执行,因此吞吐量不会是9600,但是我遇到的延迟太长了,无法从我认为的微控制器方面做出贡献。 The microcontroller code is below. 微控制器代码如下。 I am using Atmega328p. 我正在使用Atmega328p。 I have verified on hyper terminal that the incoming data is way faster than the rate at which I read with my C# code: 我已经在超级终端上验证了传入数据比使用C#代码读取数据的速度快得多:

while (1) {

    counter++; val1 = val1 + 3; val2 = val2 + 3; val3 = val3 + 3; 

    if(counter >= 100) {

        counter = 0;
        val1 = 1; val2 = 2; val3 = 3;

        }

    transmitUart0('S'); transmitUart0('T'); transmitUart0('A'); transmitUart0('R'); transmitUart0('T');transmitUart0(0x0A);
    transmitUart0(val1);
    transmitUart0(val2);
    transmitUart0(val3);
    transmitUart0('E'); transmitUart0('N'); transmitUart0('D'); transmitUart0(0x0A);

    _delay_ms(10);

}

We don't know what your microcontroller is doing but on your C# code you're introducing a huge overhead on your processing by reading bytes one by one. 我们不知道您的微控制器在做什么,但是在您的C#代码上,您通过逐字节读取字节在处理中引入了巨大的开销。

The solution to reducing this overhead is, obviously, do not read bytes one by one. 减少这种开销的解决方案显然是不要一一读取字节。 Just get rid of the for loop, do a second sp.ReadLine() right after you detect the header, work with the bytes you get to store the coordinates and discard the rest. 只需摆脱for循环,在检测到标头之后sp.ReadLine()执行第二个sp.ReadLine() ,使用获得的字节存储坐标并丢弃其余部分。

If this approach is not fixing your problem, then try to square it: read more commands in one go and process them. 如果这种方法不能解决您的问题,请尝试解决它:一口气阅读更多命令并进行处理。 At this point, it might be easier to change the way the microcontroller works I guess. 在这一点上,我想可能更容易改变微控制器的工作方式。

EDIT: Now that you have included more details, and as you have already realized, my comments above are not really helpful. 编辑:现在您已经包含了更多详细信息,并且您已经意识到,我上面的评论并没有真正的帮助。 ) First off, ReadLine() is known to be very slow, see for instance here . )首先,已知ReadLine()非常慢,例如,请参见此处

What you're trying to do is not really that demanding if you work out the numbers. 如果您计算出数字,那么您尝试做的并不是那么苛刻。 So the solution might be to use any other method, I would advise trying the BaseStream to implement your own way of reading between CRs (something similar to what the question linked above proposes). 所以解决方案可能是使用任何其他方法,我建议尝试使用BaseStream在CR之间实现您自己的读取方式(类似于上面链接的问题所建议的方式)。

Otherwise you can try the DataReceived event . 否则,您可以尝试DataReceived事件

Finally, note that when you say: 最后,请注意,当您说:

The timer interval is set at 10ms but even if I change it to 1ms, there is no difference... 计时器间隔设置为10毫秒,但是即使我将其更改为1毫秒,也没有任何区别...

referring to the delay on your microcontroller. 指的是您的微控制器上的延迟。 You got that the other way around: if you want to see better performance reading data on your PC you need to increase and not reduce this delay (otherwise you are sending even more data than the amount you can handle). 反过来看,如果您希望在PC上读取数据时看到更好的性能,则需要增加而不是减少此延迟(否则,您发送的数据甚至超过了您可以处理的数量)。 But if ReadLines() is that slow, I doubt you can improve the performance exploiting this, unless you're willing to read one data sample every 3 or 4 seconds. 但是,如果ReadLines()这么慢,我怀疑您可以利用它来提高性能,除非您愿意每3或4秒读取一次数据样本。

You should try to handle all the buffer data at once. 您应该尝试一次处理所有缓冲区数据。 So rather than reading byte by byte or line by line, subscribe to the event SerialPort.DataReceived and process the whole chunk at once. 因此,订阅事件SerialPort.DataReceived并立即处理整个块,而不是逐字节或逐行读取。

See this example: https://docs.microsoft.com/en-us/dotnet/api/system.io.ports.serialport.datareceived?view=netframework-4.8 请参见以下示例: https : //docs.microsoft.com/zh-cn/dotnet/api/system.io.ports.serialport.datareceived?view=netframework-4.8

private static void DataReceivedHandler(
                    object sender,
                    SerialDataReceivedEventArgs e)
{
    SerialPort sp = (SerialPort)sender;
    string indata = sp.ReadExisting();
    Console.WriteLine("Data Received:");
    Console.Write(indata);
    // Use BeginInvoke for synchonization!
}

For using BeginInvoke, see this other thread . 有关使用BeginInvoke的信息, 请参见此其他线程

I have made some changes to the code as per the feedback. 根据反馈,我对代码进行了一些更改。 The delays are the same. 延迟是相同的。 Please see the code below: 请参见下面的代码:

public void readCapsule(SerialPort sp)
{
        timer1.Enabled = false;

        string headerStart = "";
        string headerEnd = "";
        List<Int32> newCoordinates = new List<Int32>();

        headerStart = sp.ReadLine();
        tbRead.AppendText(headerStart + Environment.NewLine);

}


private void timer1_Tick(object sender, EventArgs e)
{
        readCapsule(spCapsule);
        timer1.Enabled = true;
    }

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

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