2013-06-24 3 views
0

Я пытаюсь написать программу, которая обновляет форму окна каждый раз, когда новые данные поступают на последовательный порт, но я борюсь с пониманием того, как работает последовательный порт, и как я может использовать его так, как я этого хочу.Последовательный порт Trigger DataReceived при получении определенных количеств байтов

У меня есть внешнее устройство, отправляющее 8 байтов на 1 Гц на мой последовательный порт и желающее использовать событие DataReceived из класса SerialPort. Когда я отлаживаю свой код, событие более или менее запускается случайным образом на основе того, что программа делает в определенное время. Код как ниже:

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) 
    { 
     //byte[] rxbyte = new byte[1]; 
     byte[] rxbyte = new byte[8]; 
     byte currentbyte; 
     port.Read(rxbyte, 0, port.BytesToRead); 

     currentbyte = rxbyte[0]; 

     int channel = (currentbyte >> 6) & 3; //3 = binary 11, ANDS the last 2 bits 
     int msb_2bit = (currentbyte >> 0) & 255; //AND compare all bits in a byte 
     currentbyte = rxbyte[1]; 
     int val = ((msb_2bit << 8) | (currentbyte << 0)); 

     //Extra stuff 

     SetText_tmp1(val.ToString()); 
    } 

Я хочу быть в состоянии иметь ровно 8 байт в приемном буфере перед тем, как вызвать функцию чтения, но я не знаю, как это сделать (не используется класс SerialPort перед тем), и хотите делать все манипуляции с данными только тогда, когда у меня есть все 8 байтов. Есть ли встроенный способ переключения события только тогда, когда определенное количество байтов находится в буфере? Или есть другой способ получить только 8 байтов, но не более, и оставить оставшиеся байты в следующем экземпляре?

+0

Видимо, у вас есть проблема XY. У вас есть ответ на проблему Y, но IMO вам все равно нужно решить X. Если это просто домашнее задание, то надежное решение, вероятно, не обязательно (но должно быть стоит A или дополнительный кредит). Если это для реального продукта, то вы не закончили. – sawdust

ответ

2

Да, вы не правильно это кодируете. Вы не можете предсказать, сколько байтов вы собираетесь получать. Поэтому просто не обрабатывайте полученные байты, пока не получите их все. Как это:

private byte[] rxbyte = new byte[8]; 
private int rxcount = 0; 

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) 
{ 
    rxcount += port.Read(rxbyte, rxcount, 8 - rxcount); 
    if (rxcount < 8) return; 
    rxcount = 0; 
    // Process rxbyte content 
    //... 
} 
+0

Ваш код работает и прост для понимания. Благодарю. – fysloc

+0

Я подозреваю, что этот код будет «работать» большую часть времени, но он недостаточно устойчив, чтобы работать все время. Логики синхронизации сообщений нет. – sawdust

+0

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

0

Установите свойство ReceivedBytesThreshold до 8. Как и в port.ReceivedBytesThreshold = 8;

+0

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

+0

Если вы следуете ответам Ганса, это не нужно. – dbasnett

+0

@sawdust - да, это упрощенно и, возможно, неверно, основываясь на остальной части предоставленного кода. Тем не менее, сообщение только указывает: «Я хочу иметь ровно 8 байтов в буфере приема, прежде чем я вызову функцию« Чтение ». Ничего о синхронизации не включено, хотя почти наверняка необходимо. –

0

Эффективный способ справиться с этим, чтобы добавить таймер к классу, который клещами вместе в возможно 9 раз в секунду. Полностью исключить обработчик событий последовательного порта.

При каждом тике отметьте код для последовательного порта для байтов, полученных от последовательного порта. Если они есть, вытащите их из последовательного порта и добавьте их в конец буфера, поддерживаемого в классе, как элемент данных.

Если в буфере имеется восемь или более символов, тогда логика таймера по типу занимает первые 8 байтов из буфера и использует их для обновления окна пользовательского интерфейса. Любые оставшиеся байты в буфере могут быть перемещены в начало буфера.

Процедура таймера может также поддерживать значение счетчика, которое увеличивается каждый раз при включении галочки и нет данных, готовых к серийному порту при этом тике. Когда этот счетчик достигнет значения, скажем, 3 или 4, код сбросит буфер данных до нуля и сбросит счетчик обратно до нуля. Когда данные фактически видны из последовательного порта, этот счетчик сбрасывается на ноль. Целью этого механизма счетчика является синхронизация буфера приема данных с потоком данных 1 Гц, поступающим так, что процесс приема не выходит из синхронизации с тем, какие данные представляют собой начало 8-байтового сообщения.

Обратите внимание, что этот метод превосходит событие приема данных последовательного порта, поскольку он позволяет вашей программе оставаться в состоянии контроля над вещами. Я уже описал возможность синхронизации с пакетами потока данных - что невозможно сделать с попыткой установить порог полученных данных последовательного порта на счет, например 8. Еще одно преимущество заключается в том, что код тикового таймера может включать в себя дополнительные функции обработки например, сигнализация таймаута, если данные не поступают из последовательного порта через 2 или 3 секунды.

+0

@sawdust - сам таймер управляется событиями. В результате повторных событий измеряется время ожидания. Я могу сказать, что из нескольких приложений, использующих последовательный порт, построена эта схема очень хорошо. Возможно, цитируемый комментарий слишком силен для всех, но он хорошо зарекомендовал себя для моих приложений, которые используются в десятках промышленных производственных сред. –

+0

* «Обратите внимание, что этот метод превосходит ...» * - Не совсем, вы предполагаете, что опрос «лучше», чем событие. Если латентность допустима, то это возможное решение. Я вообще не знаю C#, но в C я считаю, что неканонические чтения с использованием соответствующих настроек VMIN и VTIME будут самым простым решением. – sawdust

+0

@MichaelKaras - зачем вы запускаете таймер 9 раз в секунду для данных, которые поступают через @ 1 байт/сек? Мне нравится ответ Ганса. Проблема с тем, чтобы избежать обработчика, заключается в том, что таймер должен выполнять чтение И обрабатывать данные, которые работают для низких скоростей передачи, но не настолько хороши для более высоких ставок. – dbasnett

Смежные вопросы