Terrence13 Ответов: 2

Как получить массив байтов через последовательный порт


Привет Всем.

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

Что касается проблемы. Код, который я сделал, отправляет массив байтов и должен получить массив байтов обратно в качестве ответа. Я считаю, что моя проблема возникает, когда я пытаюсь сохранить полученное сообщение.

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

//this part is in my main code.
 myport.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);

 private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
   {
      if (!myport.IsOpen) return;  //If port is closed exit
      int bytes = myport.BytesToRead;  //find the size of the array needed
      byte[] buffer = new byte[bytes];  //create the array
      myport.Read(buffer, 0, bytes);  //read the message and save it into the buffer
      byte[] ReceivedMessage = new byte[bytes];  //create an array of the same size
      Array.Copy(buffer, ReceivedMessage, bytes);  //copy it across
   }


После выполнения этой части кода в "ReceivedMessage" сохраняется только первый байт, а все остальное-ноль. Предполагается, что полученное сообщение имеет длину 25 байт.

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

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

Richard MacCutchan

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

Terrence13

Спасибо за ответ, Ричард.
Да, в этом есть большой смысл. Есть ли способ заставить мой код подождать, пока он не получит все 25 байт и не заполнит массив, прежде чем продолжить?
Я попытался сделать это с помощью ReadLine, но это вызвало бесконечный цикл.

Richard MacCutchan

> После выполнения этой части кода в "ReceivedMessage" сохраняется только первый байт, а все остальное-ноль.
& gt; тестирование полученного сообщения, чтобы увидеть, все ли оно проходит (оно проходит).

Оба эти утверждения не могут быть истинными.

PIEBALDconsult

Я думаю, вы получите байт _last_.

Массив.Копия (буфер, ReceivedMessage, байты);
"байты "здесь должны быть" 0"?

2 Ответов

Рейтинг:
1

OriginalGriff

Последовательные данные таковы: последовательные-они поступают не все сразу, они поступают байт за байтом и довольно медленно по сравнению с современным программным обеспечением. Если ваш последовательный порт работает со скоростью 9600 бод, то самая быстрая скорость приема данных-около 100 байт в секунду.
Это означает, что каждый байт, скорее всего, будет генерировать свое собственное отдельное событие DataReceived, а не одно событие для всего набора.
Вместо того чтобы копировать их в буфер уровня класса, который отбросит все существующие данные и оставит вам только последний байт, попробуйте использовать консоль.Напишите, чтобы распечатать данные по мере их получения на панели вывода в отладчике, и посмотрите, сможете ли вы увидеть все данные тогда.
Если вы можете, посмотрите, есть ли у него Терминатор или вводный байт, чтобы вы могли синхронизировать свои данные и собрать полное сообщение из нескольких событий DataReceived.


Terrence13

Спасибо за ответ, Грифф, и за прекрасное объяснение.

Я собираюсь попробовать это и посмотреть, смогу ли я заставить его работать.

OriginalGriff

:большой палец вверх:

Рейтинг:
1

FranzBe

Несколько недель назад мне пришлось иметь дело с очень старым принтером, что, похоже, соответствует вашим требованиям, вот что я сделал.
Соберите входящие результаты из порта в stringbuilder, запишите то, что вы получаете, в файл. Как только вы определите индикатор "ответ завершен" (в моем случае заданную длину), вы можете вызвать обратный вызов.


public interface IHerma300
{
  void GetStatus(Action<string> callback);
}

public class Herma300 : IHerma300
{
  readonly System.IO.Ports.SerialPort _port;
  private Action<string> _callback;
  private readonly System.Text.StringBuilder _responseFromHerma;
  public const int statusResponseExpectedLength = 62;

  public Herma300(string portName
    , int baudRate
    , System.IO.Ports.Parity parity
    , int dataBits
    , System.IO.Ports.StopBits stopBits
    , int waitTimeMs)
  {
    _responseFromHerma = new StringBuilder(100);
    _port = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
    _port.DataReceived += OnPortDataReceived;
    _port.Open();
    _waitTimeMs = waitTimeMs;
  }

  private void OnPortDataReceived(object sender, SerialDataReceivedEventArgs e)
  {
    System.IO.Ports.SerialPort port = (System.IO.Ports.SerialPort)sender;
    int count = port.BytesToRead;
    byte[] data = new byte[count];
    port.Read(data, 0, data.Length);
    // use your logger here and write  BitConverter.ToString(data)
    var dataAsString = System.Text.Encoding.Default.GetString(data);
    _responseFromHerma.Append(dataAsString);
    if (_responseFromHerma.Length == statusResponseExpectedLength) CompleteAnswerReceived();
  }

  private void CompleteAnswerReceived()
  {
    _callback.Invoke(_responseFromHerma.ToString());
  }


  public void GetStatus(Action<string> callback)
  {
    _callback = callback;
    _responseFromHerma.Length = 0;
    string getStatusCommand = "send some command to the other side";
    _port.Write(getStatusCommand);
  }

}


// calling code
var labelPrinter = new Herma300(params...);
labelPrinter.GetStatus(OnStatusFromPrinter);

private void OnStatusFromPrinter(string result)
{
   // you are not in the ui thread here, so be careful when updateing ui controls
}


Terrence13

Эй, Франц. Спасибо за ответ и фрагмент кода.
Я попробую добавить это в свой код и посмотреть, смогу ли я заставить его работать.
Выглядит многообещающе.