Высокоскоростная последовательная связь через последовательный порт в C # - PullRequest
0 голосов
/ 10 июля 2019

Я работаю с Visual Studio 2019. Я отправляю данные с микроконтроллера через UART / последовательный порт на ПК, и я хочу прочитать их на стороне ПК.

Скорость передачи 9600. Я использую следующий код. Тем не менее, это очень медленно. Мне нужно иметь возможность читать код с очень высокой скоростью (сравнимой со скоростью передачи данных, которую я использую).

В настоящее время я получаю 2-3 пакета в секунду. Интервал таймера установлен на 10 мс, но даже если я изменю его на 1 мс, разницы нет. Я не могу понять, что я делаю не так. Помощь будет принята с благодарностью.

С уважением, Салман

    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 ]

1 голос
/ 12 июля 2019

Вы должны попытаться обработать все данные буфера одновременно. Поэтому вместо того, чтобы читать побайтово или построчно, подпишитесь на событие 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, см. Этот другой поток .

1 голос
/ 10 июля 2019

Мы не знаем, что делает ваш микроконтроллер, но в вашем коде на C # вы вносите огромные накладные расходы на свою обработку, считывая байты один за другим.

Решение для уменьшения этих издержек, очевидно, заключается в том, что, не читайте байты один за другим.Просто избавьтесь от цикла for, сделайте секунду sp.ReadLine() сразу после обнаружения заголовка, поработайте с полученными байтами, чтобы сохранить координаты, и отбросьте остальные.

Если этот подход не исправляетВаша проблема, а затем попробуйте решить ее: прочитайте больше команд за один раз и обработайте их.На этом этапе, возможно, будет проще изменить работу микроконтроллера.

РЕДАКТИРОВАТЬ: Теперь, когда вы включили больше деталей, и, как вы уже поняли, мои комментарии вышене очень полезны.Во-первых, известно, что ReadLine() очень медленный, см., Например, здесь .

То, что вы пытаетесь сделать, не так уж и требовательно, если вы работаете с числами.Поэтому решение может заключаться в том, чтобы использовать любой другой метод, я бы посоветовал попробовать BaseStream реализовать свой собственный способ чтения между CR (что-то похожее на то, что предлагает вопрос, указанный выше).

В противном случае вы можете попробоватьDataReceived событие .

Наконец, обратите внимание, что когда вы говорите:

Интервал таймера установлен на 10 мс, но даже если я изменю его на 1 мс, нет никакой разницы ...

относительно задержки на вашем микроконтроллере.Вы получили это с другой стороны: если вы хотите увидеть более высокую производительность чтения данных на вашем ПК, вам нужно увеличить и не уменьшать эту задержку (в противном случае вы отправляете даже больше данных, чем объем, который вы можете обработать),Но если ReadLines() слишком медленно, я сомневаюсь, что вы можете улучшить производительность, используя это, если только вы не хотите читать один образец данных каждые 3 или 4 секунды.

0 голосов
/ 11 июля 2019

Я внес некоторые изменения в код согласно обратной связи. Задержки такие же. Пожалуйста, смотрите код ниже:

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