Чтение с последовательного порта в C # - PullRequest
12 голосов
/ 14 марта 2009

Я пытался использовать Readline (), и данные сбрасывались, я пытался использовать Read (), но я не уверен, как сделать метод доказательства ошибок, поскольку я могу получать несколько пакетов один за другим, и у меня способ узнать, что будет входить другой пакет. Между пакетами BytesToRead равен 0, поэтому я не могу его использовать. При чтении данных в буфер у вас есть таймер или переведите поток в спящий режим, чтобы разрешить поступление всех пакетов?

Я потерян. Не знаю, что попробовать дальше.

Я должен упомянуть, что я не получаю никаких гарантий, что строка, выходящая из последовательного порта, будет оканчиваться на \ n, \ r или \ r \ n. Мне просто нужен безошибочный способ чтения ВСЕХ пакетов, которые поступят от шкалы, когда пользователь нажмет на нее PRINT.

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

Ответы [ 3 ]

22 голосов
/ 14 марта 2009

Вы пытались прослушать событие DataRecieved класса SerialPort?

public class MySerialReader : IDisposable
{
    private SerialPort serialPort;
    private Queue<byte> recievedData = new Queue<byte>();

    public MySerialReader()
    {
        serialPort = new SerialPort();
        serialPort.Open();

        serialPort.DataReceived += serialPort_DataReceived;
    }

    void serialPort_DataReceived(object s, SerialDataReceivedEventArgs e)
    {
        byte[] data = new byte[serialPort.BytesToRead];
        serialPort.Read(data, 0, data.Length);

        data.ToList().ForEach(b => recievedData.Enqueue(b));

        processData();
    }

    void processData()
    {
        // Determine if we have a "packet" in the queue
        if (recievedData.Count > 50)
        {
            var packet = Enumerable.Range(0, 50).Select(i => recievedData.Dequeue());
        }
    }

    public void Dispose()
    {
        if (serialPort != null)
            serialPort.Dispose();
    }
10 голосов
/ 14 марта 2009

Мы недавно прошли через тот же процесс.

Единственный способ прочитать «пакеты» - это иметь некоторое представление о том, где их начало и конец находятся в потоке.

С MSDN :

Поскольку класс SerialPort буферизует данные, а поток, содержащийся в свойстве BaseStream, - нет, оба могут конфликтовать из-за того, сколько байтов доступно для чтения. Свойство BytesToRead может указывать на наличие байтов для чтения, но эти байты могут быть недоступны для потока, содержащегося в свойстве BaseStream, поскольку они буферизированы в классе SerialPort.

Мы использовали фоновый поток (вы можете использовать BackgroundWorker) для чтения данных в буфер. Если вы не можете надежно установить завершающий символ с помощью свойства SerialPort.Newline (потому что, скажем, оно варьируется!), Вам потребуется реализовать собственную систему обнаружения пакетов, поскольку вы не сможете использовать блокирующий SerialPort.Readline (). способ.

Вы можете просто прочитать в байтовый буфер, используя SerialPort.Read () (или строку, используя метод SerialPort.ReadExisting ()) и сгенерировать событие, когда вы обнаружите в данных действительный пакет. Обратите внимание, что Read () (и я предполагаю, что ReadExisting ()) очищает буфер SerialPort, поэтому вам нужно будет хранить данные в другом месте.

Если вы установите SerialPort.ReadTimeout, вы можете обрабатывать TimeoutException и иметь простой способ обработки условий, когда ваше устройство не передает. Это хороший способ сбросить обнаружение вашего пакета, если вы используете фиксированное количество байтов или какую-либо еще не завершенную схему. (используйте SerialPort.DiscardInBuffer () по таймауту, если вам не нужны частичные пакеты).

Удачи

3 голосов
/ 29 октября 2010

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

  1. буфер входящих данных
  2. просканируйте ваш буфер, чтобы найти полные данные
  3. удалить использованные данные из буфера

Мне просто интересно, если у вас все еще есть проблемы с последовательным портом. Если так, то я разработал язык программирования последовательного порта на C # и считаю, что он решает почти все проблемы, с которыми сталкиваются все.

Не могли бы вы взглянуть и попробовать? Например; Вы можете буферизовать входящие данные из последовательного порта, как показано ниже, и легко выполнять строковые операции.

state Init
  // define a global variable
  our $BUFFER = "";
  jump(Receive);
end state

state Receive
  recv();
  $len = length($DATA_PACKET);
  if("$len > 0") {
    $BUFFER += $DATA_PACKET;
    call(Parser);
  }
end state

state Parser
  // check if buffer matchs regular expression pattern
  if(match($BUFFER, "(?<WILLDELETE>.*?<STX>(?<DATA>.*?)<ETX>(?<CHECKSUM>[0-9A-F]{2}))")) {
    // Received complete data
    $lenData = length($WILLDELETE);
    $BUFFER = remove($BUFFER, 0, $lenData);

    // Do operations with the other parsed fields. $DATA and $CHECKSUM in this example.
  }
end state

Проект находится в свободном доступе на sourceforge, и если у вас есть какие-либо вопросы, пожалуйста, не стесняйтесь спрашивать.

Домашняя страница проекта

Ссылка для скачивания

...