RA.HALLEEN Ответов: 1

У меня есть проблема с последовательным портом связи с использованием C# и visual studio.


У меня есть система на основе микроконтроллера Pic, которая периодически отправляет строку данных.
Обычно я проверяю его с помощью HyperTerminal, но теперь я хочу использовать свое собственное маленькое приложение для правильного отображения данных.
Приложение работает нормально, пока я не попытаюсь проанализировать данные с помощью операторов if() и так далее. Прилагается фрагмент кода, который дает мне проблемы (он бросает систему.Исключение IndexOutOfRange и другие неприятные вещи).
Я уже несколько недель пытаюсь понять,что же это за решение, но мне уже 70 с лишним лет, и мой стареющий мозг с трудом воспринимает страдания Microsoft. Не мог бы какой-нибудь умный хакер просветить меня на этот счет?

частная Port_DataReceived_1 недействительным(объект отправителя, SerialDataReceivedEventArgs е)
{
SetText (это. ComPort.ReadExisting());

}//datareceived
//---------------------------------------------------
частный недействительными помощью setText(string текст)
{

если (это.rtbIncoming.Свойство invokerequired)
{
SetTextCallback d = новый SetTextCallback(SetText);
этот.Invoke(d, new object[] { text });
}
еще
{
//RecDataString = "SensMon:ABCDE" (это то, что я получаю от системы Pic)

if (text[8]== ('A')) {flagsA = ("A");}
else {flagsA = ("?");}
if (text[9] == ('B')) {flagsB = ("B");}
else {flagsB = ("?");}
if (text[10] == ('C')){flagsC = ("C");}
else {flagsC = ("?");}

//Ниже не работает:
myData = (строка.Формат("{0}: {1}: {2}:", flagsA, flagsB, flagsC));
это.rtbIncoming.Текст += myData;

//Ниже действительно работает:
//это.rtbIncoming.Текст += текст;

}

Что я уже пробовал:

if (text[8]== ('A')) {flagsA = ("A");}
else {flagsA = ("?");}
//Вышеизложенное создает исключение.

0x01AA

Одно дело, когда Port_DataReceived_1 срабатывает и Вы читаете доступные байты с помощью ComPort.ReadExisting() велика вероятность, что не все байты, которые вы ожидаете, уже получены. Итак, IndexOutOfRange Скорее всего, это происходит из-за этого. SetText вы пытаетесь обратиться text[8] что еще не все готово. Одно из решений состоит в том, чтобы проверить, сколько байтов доступно, и вызвать SetText только в том случае, если в нем достаточно байтов.

Gerry Schmitz

SetText (это. ComPort.ReadExisting());

Вам всегда нужно подтвердить, что вы получили "что-то", и это правильная длина, прежде чем продолжить. "SetText" может принимать что угодно (или ничего).

RA.HALLEEN

Ты не поверишь, (я не поверил)... Я изменил ComPort.ReadExisting на ComPort.ReadLine (), и теперь он работает отлично!

1 Ответов

Рейтинг:
7

OriginalGriff

Последовательные данные, как следует из названия: каждый байт данных поступает независимо от других, в последовательной последовательности. И когда каждый байт прибывает, Windows вызывает событие DataReceived, чтобы сообщить об этом вашему коду. Вы не получаете определенный "пакет" данных, потому что последовательный порт не является внутренне ориентированным на пакет.
Это означает, что если поступающие данные составляют (например) 10 байт, вы получите от 1 до 10 событий, происходящих в зависимости от скорости вашего компьютера, скорости передачи данных коммуникационного порта и общей нагрузки на систему.
Если вы хотите обработать больше байта, то вы должны "буферизировать" данные до тех пор, пока не будет собран узнаваемый "пакет", и представление этого. Способ, которым я бы это сделал, состоит в том, чтобы буферизировать его в коллекцию (например, список<T>) внутри события DataReceived, а затем передать его через вызов вашему основному потоку - потому что событие DataReceived никогда выполняемый в основном потоке, он всегда требует вызова для доступа к компонентам пользовательского интерфейса, и ни одна из стандартных коллекций не является потокобезопасной. Выполнение этого способа позволяет вам "закончить" с коллекцией, прежде чем передать ее неповрежденной в другой поток и больше не иметь с ней ничего общего.