如何通过串行端口接收字节数组 [英] How do I receive a byte array over the serial port

查看:73
本文介绍了如何通过串行端口接收字节数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述




我正在通过制作应用程序自学C#。这是一个缓慢的进展,在论坛上花了很多时间,但仍然很有趣...



至于问题。我做的代码发送了一个字节数组,并应该返回一个字节数组作为回复。我相信当我尝试保存收到的消息时,我的问题就出现了。



到目前为止,我得到的最好结果是保存收到的第一个字节,仅此而已。



 //此部分在我的主要代码中。 
myport.DataReceived + = new SerialDataReceivedEventHandler(port_DataReceived);

private void port_DataReceived(object sender,SerialDataReceivedEventArgs e)
{
if(!myport.IsOpen)return; //如果端口关闭退出
int bytes = myport.BytesToRead; //找到所需数组的大小
byte [] buffer = new byte [bytes]; //创建数组
myport.Read(buffer,0,bytes); //读取消息并将其保存到缓冲区
byte [] ReceivedMessage = new byte [bytes]; //创建一个大小相同的数组
Array.Copy(buffer,ReceivedMessage,bytes); //将它复制到
}





在此部分代码运行后,只有第一个字节保存在ReceivedMessage中其余的都是空的。收到的消息假设长25个字节。



我尝试过:



测试Received消息以查看是否全部通过(确实如此)。

尝试了不同形式的Read命令(似乎没有真正的帮助)。

解决方案

串行数据只是:串行 - 它不是一次全部到达,它是逐字节到达的,与现代软件相比相当慢。如果您的串行端口以9600波特率运行,那么您接收数据的最快速度大约为每秒100字节。

这意味着每个字节很可能会生成它自己独立的DataReceived事件而不是您为整个集合获取一个事件。

而不是将它们复制到类级别缓冲区 - 这将丢弃任何现有数据并只留下最新字节 - 尝试使用Console.Write打印数据当你收到它到调试器的输出窗格,看看你是否可以看到所有的数据。

如果可以的话,看看它是否有一个终结符或一个引入字节,所以你可以同步您的数据并汇集来自许多DataReceived事件的完整消息。


几周前我不得不处理一台非常旧的打印机,这似乎与您的要求类似,这里是我做了什么。

从字符串构建器中的端口收集传入的结果,记录你得到的文件。一旦确定答案已完成指示符(在我的情况下为给定长度),您就可以调用回调。





公共接口IHerma300 
{
void GetStatus(Action< string> callback );
}

公共类Herma300:IHerma300
{
readonly System.IO.Ports.SerialPort _port;
private Action< string> _打回来;
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(对象发送者,SerialDataReceivedEventArgs e)
{
System.IO.Ports.SerialPort port =(System.IO.Ports.SerialPort)发件人;
int count = port.BytesToRead;
byte [] data = new byte [count];
port.Read(data,0,data.Length);
//在这里使用你的记录器并写入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 =向另一方发送一些命令;
_port.Write(getStatusCommand);
}

}


//调用代码
var labelPrinter = new Herma300(params ...);
labelPrinter.GetStatus(OnStatusFromPrinter);

private void OnStatusFromPrinter(字符串结果)
{
//你不在这里的ui线程中,所以在更新ui控件时要小心
}


Hallo All.

I am currently teaching myself C# through making an app. It is slow progress with a lot of time spent on forums, but still fun none the less...

As for the problem. The code I have made sends an array of bytes out and should get a byte array back as a reply. I believe my problem is coming up when I try and save the received message.

The best outcome I have gotten so far was to save the 1st byte received and nothing more.

//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
   }



After this part of the code runs only the first byte is saved in "ReceivedMessage" and the rest is all null. The message received is suppose to be 25 bytes long.

What I have tried:

Testing the Received message to see if it all comes through (it does).
Tried different forms of the Read command (doesn't seem to really help).

解决方案

Serial data is just that: serial - it does not all arrive at once, it arrives byte-by-byte, and pretty slowly compared to modern software. If your serial port is running at 9600 baud, then the fastest you can receive data is at about 100 bytes per second.
That means that each byte will most likely generate it's own separate DataReceived event rather than you getting one event for the whole set.
Instead of copying them to a class level buffer - which will discard any existing data and leave you with only the latest byte - try using Console.Write to print the data as you receive it to the Output pane in the debugger and see if you can see all the data then.
If you can, see if it has a terminator or a lead-in byte, so you can synchronise your data and assemble the complete message from a number of DataReceived events.


I had to deal with a very old printer some weeks ago, what seems to be similar to your requirements, here is what I did.
Collect the incoming results from the port in a stringbuilder, log what you get into a file. Once you identify the "the answer is complete" indicator (in my case a given length) you can invoke a callback.


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
}


这篇关于如何通过串行端口接收字节数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆