Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   с# - не могу понять принцип чтения com-порта (http://forum.oszone.net/showthread.php?t=273232)

Carmageddon 02-12-2013 16:33 2265496

с# - не могу понять принцип чтения com-порта
 
Здравствуйте. Имеется устройство, оно принимает от меня пакет данных (6 байт), и отправляет ответ - 28 байт.
Не могу понять как организовать чтение?
на данный момент на форму брошены 2 кнопки - нажимаю на первую, происходит :
Код:

byte[] a = { 0x02, 0x4B, 0x00, 0x12, 0x04, 0x01 };
port.Open();
port.Write(a, 0, a.Length);

Соответственно вторая кнопка - чтение :
Код:

byte[] b = new byte[28];
port.Read(b, 0, b.Length);

Клацаю на первую, после на вторую - все читается и обрабатывается.
Но(!) - если запихать это в одну процедуру - то ничего не получается, т.к. устройству нужно 600 мс для посылки ответа, т.е. в буфер для чтения попадают нули, 28 байт 0x00 - пустой буфер, т.к. устройство попросту не успевает прислать ответ.
Как правильно поступить в этом случае?
Могу предположить установить паузу, но это - костыль.
Как правильно выходить из данной ситуации?

pva 02-12-2013 18:06 2265543

Варианты:
1. (самый простой) синхронное чтение (либо просто увеличь таймаут), читай сразу 28 байт.
2. если железяка поддерживает аппаратную синхронизацию - включи (и в настройках порта тоже)
3. если железяка поддерживает программную синхронизацию (xon/xoff) - включи в настройках порта
4. если железяка в любом случае шлёт 1-й байт определённый (например 27), укажи его в настройках как event char

Первый вариант подходит в 99.9% случаев

С таймаутом тоже неплохо. Особенно если совместить с поллингом

Carmageddon 02-12-2013 18:22 2265557

Цитата:

Цитата pva
Варианты:
1. (самый простой) синхронное чтение (либо просто увеличь таймаут), читай сразу 28 байт. »

А как читать сразу 28 байт? Я вроде так и делаю :
Код:

byte[] b = new byte[28];
port.Read(b, 0, b.Length);

Поднимаю таймаут до 1000мс - в массиве байтов все 0x00 :(

Да, я заранее знаю, какие байты будут идти первыми, и кол-во байт.
Поищу завтра event char

pva 03-12-2013 10:42 2265988

покажи как настройки порта выставляешь

Carmageddon 03-12-2013 11:43 2266020

Код:

SerialPort MyPort = new SerialPort("COM2", 9600, Parity.Even, 8, StopBits.One);
MyPort.ReadBufferSize = 1024;
MyPort.WriteBufferSize = 1024;
MyPort.WriteTimeout = 1000;
MyPort.ReadTimeout = 1000;


pva 03-12-2013 14:01 2266118

Основываюсь на http://msdn.microsoft.com/ru-ru/libr...vs.110%29.aspx
глупый хелп, конечно. Совсем обленился микрософт.
Если не забываешь сделать Open(), то попробуй:
1. поотключать аппаратное управление портом
2. вызови 28 раз сподряд ReadByte(). Про неё точно написано что она синхронная. Если заработает - значит используй её либо ищи как работать асинхронно

вот такая штука может быть полезной:

ReceivedBytesThreshold Получает или задает число байтов, содержащихся во внутреннем входном буфере перед наступлением события DataReceived.

Carmageddon 03-12-2013 15:11 2266156

Цитата:

Цитата pva
2. вызови 28 раз сподряд ReadByte(). »

Вроде сработало - данные пришли как нужно, но в полном масштабе не тестировал
Дополню таким фактом - при чтении Read() - в портмоне данные приходят (видны) как одна строка. В текущем случае, они видны как один байт на строку (что вполне понятно, т.к. читаю 28 байт в цикле). Но визуально в портмоне данные читаются блоками по 14 байт, между блоками некая задержка.
P.s. - когда читает родная утилита железяки, данные в портмоне видны "одной строкой"
Что ж за странность - читает 14 байт, ложит в массив и небольшая задержка, и дальше читает по 14 байт. Цикл то крутиться на 28
Вот, взгляните (картинка в хайде) :




Цитата:

Цитата pva
вот такая штука может быть полезной:
ReceivedBytesThreshold »

Да, кстати, очень хороший вариант.
Однако, стоит заметить о многочисленных отзывах, и официальной информации с msdn - что сие событие не обязано срабатывать на каждый полученный байт. Вдруг мой 28й байт как раз станет тем самым. А после него данные не приходят, соответственно событие уже не сработает :(.
буду тестировать вариант с циклом.

P.s.s. уважаемый pva, а подскажите пожалуйста, где мне просвятиться, о том, что есть "синхронный" и "асинхронный режимы" в доступной форме?

Спасибо за Ваши ответы, очень помогли

pva 03-12-2013 18:50 2266316

Скажу честно, я не знаю. Отвечал на основе опыта работы с портом в C/C++. Принцип примерно такой:
к порту прицеплен драйвер, который держит очередь ввода-вывода и запуливает в порт данные с его скоростью (и читает обратно)
Всё это работает в соседнем процессе, значит можно помещать данные в очередь (пишем в порт) или снимать их оттуда (читаем порт) с небольшими задержками (чтобы не переполнить очередь), и заниматься своими делами. Видимо в этом и вся асинхронность.
здесь написано про настройки драйвера:
http://msdn.microsoft.com/en-us/library/bb202767.aspx
http://msdn.microsoft.com/en-us/library/aa909018.aspx

Это всё как-то намаплено на классы C# - ищи похожие названия

Carmageddon 03-12-2013 19:39 2266360

Прочел ряд статей - насколько я понял, все для ПК по rs232 работает в асинхронном режиме - режиме, где единицей передачи информации является байт, т.е. каждый байт имеет старт и стоп биты, и как правило бит четности.
В противоположность ему, есть более быстрый - синхронный режим, когда поток бит идет непрерывно, но rs232 его не поддерживает.
буду пробовать

pva 03-12-2013 20:39 2266393

Carmageddon, не в этом смысле! Имеется в виду дожидается ли функция результата (синхронный режим) или возвращается сразу, а результат получается полингом, ожиданием события или обратным вызовом (асинхронный режим). Синхронность в межпотоковом смысле.


Время: 20:22.

Время: 20:22.
© OSzone.net 2001-