Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > .NET Frameworks (точка нет фреймворки) > Общие вопросы .NET
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 03.05.2016, 14:23   #1
Krasi
Форумчанин
 
Регистрация: 12.02.2010
Сообщений: 787
По умолчанию Проблема с com-портом - как слать и обрабатывать данные

Мне нужно среди всего, что приходит с терминала, выделять только 5 чисел и отображать их в разных окошках таблицы. Я подумал, если на передатчике написать Serial.print(...), то на приемнике это обязательно примется как одна строка. Если я захочу включить в эту строку 5 чисел - то так и будет. Я сделал такой код:

Код:
string ms = data.Replace(".", ",");
            

            int ss = ms.Length;
            if (ms[ss-1] == ',') ms = ms.Substring(0, ms.Length - 1);

         
            List<string> msg = new List<string>(ms.Split());
            msg.RemoveAll(item => item == "");
            
            double[] rec = new double[5];
            double[] cor = new double[5];

            for (int i = cntw; i < msg.Count; i++)
            {
                rec[i] = Convert.ToDouble(msg[i]);
                cor[i] = rec[i] * 1000;
            }
            
            rec[0] = Convert.ToDouble(msg[0]);
            cor[0] = rec[0];

    richTextBox1.Invoke(new EventHandler(delegate
            {
                //if (data.Contains("s"))
                { richTextBox1.AppendText(Convert.ToString(cor[0]) + System.Environment.NewLine); }
                richTextBox2.AppendText(Convert.ToString(cor[1] + System.Environment.NewLine));
                richTextBox3.AppendText(Convert.ToString(cor[2] + System.Environment.NewLine));
                richTextBox4.AppendText(Convert.ToString(cor[3] + System.Environment.NewLine));
                richTextBox5.AppendText(Convert.ToString(cor[4] + System.Environment.NewLine));
            }));
Но оказалось, что эта одна строка может прийти в разбитом виде, и тогда программа зависнет на одной из колонок, куда я добавляю разделенные числа.

Я пошел дальше и посмотрел, как получается строка data. А получается она, по ходу дела, так:

Код:
  // Obtain the number of bytes waiting in the port's buffer
        int bytes = comport.BytesToRead;

        // Create a byte array buffer to hold the incoming data
        byte[] buffer = new byte[bytes];

        // Read the data from the port and store it in our buffer
        comport.Read(buffer, 0, bytes);

        // Show the user the incoming data in hex format
        Log(LogMsgType.Incoming, ByteArrayToHexString(buffer));
Код:
   comport.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
Цитата:
private string ByteArrayToHexString(byte[] data)
{
StringBuilder sb = new StringBuilder(data.Length * 3);
foreach (byte b in data)
sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' '));
return sb.ToString().ToUpper();
}
Я в ступоре. Как поступить в такой ситуации?
Krasi вне форума Ответить с цитированием
Старый 03.05.2016, 16:36   #2
kutani
Форумчанин
 
Регистрация: 23.01.2016
Сообщений: 608
По умолчанию

Цитата:
если на передатчике написать Serial.print(...)
UART работает побайтно. Когда вы видите некую строку, то байты склеивает драйвер ОС. При превышении таймаута между символами (фреймами) строка может разбиваться, со стороны терминала вы это видите как разбитие единой казалось бы строки )

Прием вы должны организовать так, чтобы предусмотреть как склейку, так и разбивку пакетов произвольно. Наилучшим выходом будет оформить свой обмен хотя-бы в виде примитивного протокола: заголовка, тела пакета, CRC. Например для данных постоянной длины достаточно в заголовке посылать всегда одинаковый байт-байты, типа FF FF или AA 55. Если данные переменной длины, то вторым байтом можно оформить длину пакета. В обработчике приема соответственно отслеживать начало пакета по заголовку, длине и производить накопление данных с переносом остатка на следующий прием в начало принимаемого пакета. Так вы не будете зависеть ни от склейки байт (фреймов), так и произвольного разбития.

Самый примитивным примером протокола - MLink, универсальнее - Modbus.
kutani вне форума Ответить с цитированием
Старый 03.05.2016, 17:45   #3
Krasi
Форумчанин
 
Регистрация: 12.02.2010
Сообщений: 787
По умолчанию

Можно обойтись и протоколом таким, чтобы в начале просто символ s был. Но я вообще не понимаю, как это сделать, я думал о накоплении, но меня на это и не хватает, а сообразить нужно побыстрее уже.

Я понимаю, что в буфер приходят байты, происходит преобразование в строку... А вот как просто взять и сделать так, чтобы за первый или 1+2 цикл работы программы было получено 5 численных значений, потом еще 5, и каждые 5 значений попадали бы строго в свою колонку в таблице данных? Я не понимаю если, например, я не получил 1 из 5 чисел, как это можно отследить вообще?
Krasi вне форума Ответить с цитированием
Старый 03.05.2016, 21:44   #4
kutani
Форумчанин
 
Регистрация: 23.01.2016
Сообщений: 608
По умолчанию

Цитата:
происходит преобразование в строку
не происходит, это пользовательская фишка обертки. Можно работать с буфером из байтов или их символьным эквивалентом.

Цитата:
еще 5, и каждые 5 значений попадали бы строго в свою колонку в таблице данных?
забудьте о таблице, не забивайте голову оформительскими плюшками без понимания алгоритма.

Представьте себе вы забили в качестве начала (а значит и конца) пакета данных - некий неиспользуемый символ-байт FFh и вам надо передать последовательность байт-символов неизвестной длины:

1 3 6 8 9 0 1 2 3 10 145

Пакет данных будет:

255 1 3 6 8 9 0 1 2 3 10 145
или в HEX:
FF 01 03 06 08 09 00 01 02 03 0A 91

Следующий пакет данных, скажем 0B 0C 06 08 09, вы снова обрамляете FF:

FF 0B 0C 06 08 09

В итоге шлются данные: FF 01 03 06 08 09 00 01 02 03 0A 91 FF 0B 0C 06 08 09 ...
Причем могут как так: FF 01 03 06 08 09 00 01 02 03 0A 91 FF 0B 0C 06 08 09 ...
Так и:
FF 01
03 06 08 09
00 01 02 03 0A 91 FF 0B 0C 06 08 09 ...
Или:
FF 01 03 06 08 09 00 01 02 03 0A 91
FF
0B 0C
06 08 09 ...

И неважно как они разбиты и сколько их пришло за раз, ибо FF однозначно позиционирует начало текущего пакета, а следующая FF конец текущего или начало следущего. Следовательно данные в приемном буфере нужно парсить на наличие признаков начала пакета. Либо усложнить состав пакета и ввести конец или фиксированную длину или длину в заголовке с CRC. Если в пакете не будет найдено начало или в остатке его нет, переносим на следующее чтение.
kutani вне форума Ответить с цитированием
Старый 04.05.2016, 21:05   #5
Krasi
Форумчанин
 
Регистрация: 12.02.2010
Сообщений: 787
По умолчанию

Я понял, что в буфер данные идут бесконечно, бинарные данные, которые будут в виде FF в hex представлении, например. Ок, с этим чисто. Хотя не совсем понял, когда моя программа решает, когда буфер необходимо обновить?

Не забивать голову с разделением на столбцы... Вот тут самая главная проблема, я никак не могу понять. У меня есть главное окошко. Там я реально вижу

FF 00 02 03 05 20 FF 00 02 03 05 20 FF 00 02 03 05 20 В текстовом виде, конечно.

Но Вы сказали, что содержаться в буфере это может следующим образом:

FF 00 02 03 05 2
0 FF 00 02 03 05
20 FF 00 02 03 05 20 В текстовом виде все, конечно, после ASCII.

Это содержимое буфера в разные моменты времени. Тогда я просто не могу понять. Мне же нужно получить, в итоге, такую таблицу, где у меня будет четко

00 02 03 05 20
00 02 03 05 20
00 02 03 05 20

Первый столбец - момент времени. Эта программа для показания значений 4 датчиков в определенные моменты времени. Временной интервал между измерениями может определяться в мс, но его можно задать в 10 ках с. А результат должен быть разделен, а желательно, еще и построен в виде 4 графиков в зависимости от времени.

Дело в том, что я вообще не понимаю, как это возможно.
Krasi вне форума Ответить с цитированием
Старый 05.05.2016, 12:40   #6
kutani
Форумчанин
 
Регистрация: 23.01.2016
Сообщений: 608
По умолчанию

Вы когда-нибудь парсили данные, любые?
kutani вне форума Ответить с цитированием
Старый 06.05.2016, 13:08   #7
Krasi
Форумчанин
 
Регистрация: 12.02.2010
Сообщений: 787
По умолчанию

Вообще не в курсе. То есть данные идут, их как-то нужно парсить.... Я делал до этого Ethernet, но там длина буфера строго определена, сколько передаю, столько и принимаю. Поэтому сейчас я как-то вообще в шоке, честно. Прошу поддержки в этом вопросе
Krasi вне форума Ответить с цитированием
Старый 09.05.2016, 23:51   #8
Krasi
Форумчанин
 
Регистрация: 12.02.2010
Сообщений: 787
По умолчанию

Ну разве это такая сложная задача? Я просто реально не могу сообразить, я-то не программист, и задача простая, если немного подсказать, но сейчас я просто понять не могу, как входной буфер может быть не фиксированной длины, как я могу начинать обработку в программе, когда у меня еще не пришло ровно столько данных, сколько я ожидаю, четкое число бит, которое я заведомо знаю?
Krasi вне форума Ответить с цитированием
Старый 10.05.2016, 00:04   #9
Alar
Александр
Администратор
 
Аватар для Alar
 
Регистрация: 28.10.2006
Сообщений: 17,758
По умолчанию

раздел для вопроса не тот
Alar вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Проблема с портом. Артём_2 Работа с сетью в Delphi 2 30.09.2013 11:06
проблема с COM-портом SYSSI Общие вопросы C/C++ 9 29.03.2012 10:13
проблема с COM-портом axalay Компьютерное железо 1 23.07.2010 22:30
Как обрабатывать данную ситуацию? Arkuz БД в Delphi 2 08.12.2008 02:51
как обрабатывать события с клавы? proglamer Паскаль, Turbo Pascal, PascalABC.NET 13 25.10.2007 11:41