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

时间:2019-07-10 15:08:43

标签: c# .net serial-port uart serial-communication

我正在使用Visual Studio2019。我正在通过uart /串行端口将数据从微控制器发送到PC,我想在PC端读取数据。

波特率是9600。我正在使用以下代码。但是,它非常慢。我需要能够以非常高的速度读取代码(与我使用的波特率相当)。

目前,我每秒收到2-3个数据包。计时器间隔设置为10毫秒,但是即使将其更改为1毫秒,也没有任何区别。我不知道我在做什么错。帮助将不胜感激。

关于, 萨尔曼(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;
    }

我的单片机代码基本上是递增3个变量并将其发送到START和END标头之间。我知道还有其他行正在执行,因此吞吐量不会是9600,但是我遇到的延迟太长了,无法从我认为的微控制器方面做出贡献。微控制器代码如下。我正在使用Atmega328p。我已经在超级终端上验证了传入数据比使用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);

}

3 个答案:

答案 0 :(得分:1)

我们不知道您的微控制器在做什么,但是在您的C#代码上,通过逐个读取字节来给处理过程带来巨大的负担。

显然,减少这种开销的解决方案是不要一一读取字节。只需摆脱for循环,在检测到标头之后立即执行第二次sp.ReadLine(),使用获得的字节存储坐标,然后丢弃其余的字节。

如果这种方法不能解决您的问题,请尝试解决它:一口气阅读更多命令并进行处理。在这一点上,我猜想改变微控制器的工作方式可能会更容易。

编辑:既然您已经包含了更多详细信息,并且您已经意识到,我上面的评论并没有真正的帮助。 ) 首先,已知ReadLine()的运行速度很慢,例如参见here

如果要计算出数字,您要尝试做的并不是那么苛刻。因此解决方案可能是使用任何其他方法,我建议尝试使用BaseStream在CR之间实现您自己的阅读方式(类似于上面链接的问题所建议的方式)。

否则,您可以尝试DataReceived event

最后,请注意,当您说:

  

计时器间隔设置为10毫秒,但是即使我将其更改为1毫秒,也没有区别...

是指微控制器上的延迟。反过来看,如果您想在PC上读取数据获得更好的性能,则需要增加而不是减少此延迟(否则,您发送的数据量甚至超出了您的处理能力) )。但是,如果ReadLines()这么慢,我怀疑您可以利用它来提高性能,除非您愿意每3或4秒读取一个数据样本。

答案 1 :(得分:1)

您应该尝试一次处理所有缓冲区数据。因此,订阅事件SerialPort.DataReceived并立即处理整个块,而不是逐字节或逐行读取。

请参见以下示例:https://docs.microsoft.com/en-us/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!
}

要使用BeginInvoke,see this other thread

答案 2 :(得分:0)

根据反馈,我对代码进行了一些更改。延迟是相同的。请参见下面的代码:

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