Задержка связи через последовательный порт с использованием C #

Я пытаюсь написать приложение C #, которое считывает данные UART со скоростью 115200 бит / с. Данные в формате:

ID: XXX Data: XX XX XX XX XX XX XX XX
ID: XXX Data: XX XX XX XX XX XX XX XX
ID: XXX Data: XX XX XX XX XX XX XX XX

где X представляют шестнадцатеричные значения.

Каждая передача заканчивается символом новой строки ('\ n'). Ниже приведен код моего приложения C #. Он просто считывает данные построчно, разбирает ID и поля данных в переменные, а затем вставляет данные в объект dataGridView. Если запись идентификатора не существует в таблице, она и ее данные добавляются. Если запись идентификатора уже существует (повторяется), то существующие данные для повторяющейся записи идентификатора обновляются новыми данными. Это позволяет мне видеть, как меняются данные в перечисленных идентификаторах.

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            serialPort.PortName = "COM11";
            serialPort.BaudRate = 115200;
            serialPort.Open();
            serialPort.DiscardOutBuffer();
            serialPort.DiscardInBuffer();

        }

        private delegate void SetTextDeleg(string text);
        private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            string CAN_tx = serialPort.ReadLine();
            this.BeginInvoke(new SetTextDeleg(processCAN), new object[] { CAN_tx });
        }

        void processCAN(string CAN_tx)
        {
            CANout_txtbox.Text = CAN_tx;
            Match match = Regex.Match(CAN_tx, @"^ID:\s([A-F0-9]+)\s+Data:\s([^\r]+)", RegexOptions.IgnoreCase);
            if (!match.Success) return;
            string pid = match.Groups[1].Value.Trim();
            string data = match.Groups[2].Value.Trim();
            string raw = pid + " " + data;

            string[] row = raw.Split(' ');

            int rowIndex = -1;

            try
            {
                DataGridViewRow matchRow = dataTable.Rows
                    .Cast<DataGridViewRow>()
                    .Where(r => r.Cells["PID"].Value.ToString().Equals(match.Groups[1].Value))
                    .First();

                rowIndex = matchRow.Index;
            }
            catch { }

            if (rowIndex != -1)
            {
                dataTable.Rows[rowIndex].SetValues(row);
            }
            else
            {
                dataTable.Rows.Add(row);
            }
        }
    } 
}

Программа работает, однако, похоже, есть проблемы с производительностью последовательной связи. Когда я просматриваю поток данных в консоли, я вижу, что в секунду отправляется несколько сотен идентификаторов. (Идентификатор повторяется каждые 10, 20, 50, 100, 110 мс, в зависимости от идентификатора) Когда я просматриваю данные в приложении C #, я вижу, может быть, 50 идентификаторов в секунду. Это приводит к огромной задержке между отправкой данных в приложение C # и обновлением данных в приложении C #.

Есть ли способ установить приоритет для COM-порта, который я использую? Или здесь есть более глубокие проблемы? Я попытался уменьшить размер последовательного буфера, изменить таймауты и количество байтов, необходимых для запуска события приема данных, но ничего не изменилось.

Я уже начал новый подход в Python, поскольку я мог отображать данные почти в реальном времени, однако я хотел бы понять, что происходит в моем приложении C #, что снижает производительность, которая мне нужна.

Спасибо!


person radensb    schedule 12.05.2014    source источник
comment
существует проблема с производительностью последовательной связи. - Зачем винить последовательный порт в разнице в простом просмотре потока данных в консоли (т.е. минимальная обработка ) по сравнению с обработкой данных с помощью вашей программы? Создайте тесты или тесты на работоспособность. (1) Разделите вашу программу на две части. Вырежьте код чтения последовательного порта и просто отправьте данные в stdout. Посмотрите, как быстро этот вывод может отображаться на консоли. Перезапустите программу и перенаправьте stdout в файл. (2) Вырежьте обрабатывающую часть, но прочтите из stdin (например, из файла).   -  person sawdust    schedule 13.05.2014
comment
Если запись идентификатора не существует в таблице - это похоже на поиск, который может легко объяснить накладные расходы на обработку в вашей программе.   -  person sawdust    schedule 13.05.2014
comment
В качестве теста я уже поместил оператор return после первой строки в функции processCAN, так что все, что ему нужно было сделать, это установить для свойства Text текстового поля CANout_txtbox строку из потока UART. Без изменений. Я по-прежнему получаю медленные обновления. Не знаю, насколько я могу это сделать проще.   -  person radensb    schedule 13.05.2014
comment
С учетом того, насколько медленной является связь UART, я не понимаю, как любая выполняемая мной обработка может вызвать такое замедление. И поиск, который проводится, минимален. Уникальных ключей всего около 35. Я думал, что, возможно, пользовательский интерфейс не обновляется достаточно быстро, но когда я изменил свои тестовые данные на увеличивающиеся значения, я понял, что это тоже не так ... хмммммм ....   -  person radensb    schedule 13.05.2014


Ответы (2)


Я вижу, может быть, 50 идентификаторов в секунду.

Это невозможно физически, ваши глаза недостаточно хороши, чтобы видеть изменения с такой скоростью. Вы обманули себя программой режима консоли, вы сделали сотни изменений в секунду из скорости, с которой строки прокручивались в окне консоли. Конечно, никогда не читал ни одного из них.

Этот физиологический эффект перестает работать, когда вы обновляете строки в сетке. Теперь вы делаете то же самое, что и кинопроектор в кинотеатре. Он обновляет кадры со скоростью 24 в секунду. Или телевизор, по которому вы смотрели шоу, обновляет кадры со скоростью 25 или 30 в секунду. Вы не можете видеть отдельные кадры, они меняются слишком быстро, чтобы ваш глаз мог их заметить. Хотя 24 кадра в секунду - это нижний предел, исходная скорость до того, как цифровое проецирование стало обычным явлением, мерцание, как правило, было заметным.

Человеческие глаза выскакивают со скоростью около 20 обновлений в секунду, работают быстрее и просто превращаются в размытое пятно. Что в остальном - хорошо, это помогает вещателям и операторам театра не тратить много денег на дорогостоящее оборудование, такое, которое съедает рулон пленки за считанные минуты.

Короче говоря, вы пишете непригодную для использования программу. Ваш пользователь будет смотреть на дико мигающие числа и быстро потеряет интерес. Вам придется подумать о том, как превратить данные в полезную информацию, здесь нет ничего очевидного.

person Hans Passant    schedule 12.05.2014
comment
Позвольте мне уточнить. Я ничего не основываю строго на наблюдениях. Я осознаю ограничения человеческого зрения. :) 50 идентификаторов в секунду против 200+ идентификаторов в секунду были основаны на моих тестовых данных, которые увеличивались после каждой передачи. Я наблюдал обновление в приложении каждые 500 мс или около того, при этом идентификатор теста увеличивался примерно на 40-60 за каждое обновление, но мог видеть историю как все полученные данные. В консоли обновления прокручивались и проходили по идентификатору теста намного быстрее (200+ в секунду). Данные, которые меня интересуют, меняются в зависимости от взаимодействия с людьми, поэтому это было бы очевидно. - person radensb; 13.05.2014
comment
Мне совершенно непонятно, как ваша установка снижает пропускную способность. Полевая шина, такая как CAN, конечно же, не обращает внимания на событие SerialPort.DataReceived. Я не верю вашему исключению из предвзятости наблюдения. Сосредоточьтесь на отображении полезных данных, которые генерируются человеческим взаимодействием. Нет смысла вызывать BeginInvoke (), если данные не изменились. - person Hans Passant; 13.05.2014

Эту проблему можно решить, используя фоновые рабочие процессы для обработки data и main только для обновления datagrid [GUI]? Это мог быть только я, но в наши дни большая часть моей обработки данных живет в автомобилях ...

Изменить: еще одна мысль, в зависимости от того, сколько «строк» ​​данных вы ожидаете, идея может заключаться в том, чтобы сохранить информацию в хеш-таблице (очень быстро для поиска) или с датами? Усиливается ли «задержка» при добавлении дополнительных элементов, накапливается ли она?

Edit2: Хорошее руководство по правильному использованию фоновых рабочих [Если вы решите их использовать!]

person Inspired    schedule 12.05.2014
comment
И попробуйте FirstOrDefault и нулевую проверку вместо использования исключений для потока управления. - person CodeCaster; 13.05.2014