C# 等待串行端口的响应,然后发送下一个数据
我正在从.bin文件中读取字节数据,并将整个字节数据拆分为16-16字节帧,因此我希望逐个读取16字节帧,并等待第一帧完成其循环 SerialPort类的回调方法:C# 等待串行端口的响应,然后发送下一个数据,c#,serial-port,C#,Serial Port,我正在从.bin文件中读取字节数据,并将整个字节数据拆分为16-16字节帧,因此我希望逐个读取16字节帧,并等待第一帧完成其循环 SerialPort类的回调方法: private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) { // Read data from serial port: byte[] buffer = new byte[serialPort.BytesToRead]
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// Read data from serial port:
byte[] buffer = new byte[serialPort.BytesToRead];
serialPort.Read(buffer, 0, buffer.Length);
StringBuilder sb = new StringBuilder();
List<string> response = new List<string>();
for (int i = 0; i < buffer.Length; i++)
{
string currentByte = string.Format("{0:X2}", buffer[i]);
response.Add(currentByte);
sb.AppendFormat("{0:X2}", buffer[i]);
}
string responesCode = response[1].ToString();
if (responesCode == "44")
{
// Wait until the first response is not received
foreach (var packet in packetList.Skip(1))
{
// This method which sending the the data
this.ReadByteDataFromFile(packet);
}
}
}
ReadByteDataFromFile方法:
public void ReadByteDataFromFile(byte[] packet) {
try {
byte[] mBuffer = new byte[24];
byte[] payload = new byte[16];
int i = 0;
foreach(var bytes in packet) {
payload[i++] = bytes;
}
CheckSumHelper checkSumHelper = new CheckSumHelper();
var ckSum = checkSumHelper.GetCheckSum(payload);
mBuffer[0] = 0x02;
mBuffer[1] = 0x10;
mBuffer[2] = CheckSumHelper.GetBytesFromDecimal(packet[0]);
mBuffer[3] = CheckSumHelper.GetBytesFromDecimal(packet[1]);
mBuffer[4] = CheckSumHelper.GetBytesFromDecimal(packet[2]);
mBuffer[5] = CheckSumHelper.GetBytesFromDecimal(packet[3]);
mBuffer[6] = CheckSumHelper.GetBytesFromDecimal(packet[4]);
mBuffer[7] = CheckSumHelper.GetBytesFromDecimal(packet[5]);
mBuffer[8] = CheckSumHelper.GetBytesFromDecimal(packet[6]);
mBuffer[9] = CheckSumHelper.GetBytesFromDecimal(packet[7]);
mBuffer[10] = CheckSumHelper.GetBytesFromDecimal(packet[8]);
mBuffer[11] = CheckSumHelper.GetBytesFromDecimal(packet[9]);
mBuffer[12] = CheckSumHelper.GetBytesFromDecimal(packet[10]);
mBuffer[13] = CheckSumHelper.GetBytesFromDecimal(packet[11]);
mBuffer[14] = CheckSumHelper.GetBytesFromDecimal(packet[12]);
mBuffer[15] = CheckSumHelper.GetBytesFromDecimal(packet[13]);
mBuffer[16] = CheckSumHelper.GetBytesFromDecimal(packet[14]);
mBuffer[17] = CheckSumHelper.GetBytesFromDecimal(packet[15]);
mBuffer[18] = 0x17;
mBuffer[19] = 0x00;
mBuffer[20] = 0x00;
mBuffer[21] = 0x00;
mBuffer[22] = Convert.ToByte(int.Parse(ckSum, System.Globalization.NumberStyles.HexNumber));
mBuffer[23] = 0x03;
serialPort.Write(mBuffer, 0, mBuffer.Length);
} catch (Exception ex) {
ExceptionHandler exceptionHandler = new ExceptionHandler();
exceptionHandler.HandleException(ex);
}
}
如何为ReadByteDataFromFile方法添加延迟?在写入第一帧后,在循环中等待完整响应
// Set read timeout to value recommended in the communication protocol specification
// so serial port operations don't stuck.
_port.WriteTimeout = 200;
_port.ReadTimeout = 200;
public void OnClick()
{
// Write first frame.
_port.Write(...);
// Now wait for the full response.
// Expected response length. Look for the constant value from the device communication
// protocol specification or extract from the response header (first response bytes) if
// there is any specified in the protocol.
int count = ...;
var buffer = new byte[count];
var offset = 0;
while (count > 0)
{
var readCount = _port.Read(buffer, offset, count);
offset += readCount;
count -= readCount;
}
// Now buffer contains full response or TimeoutException instance is thrown by SerialPort.
// Check response status code and write other frames.
}
为了不阻塞UI线程,您很可能仍然需要利用同步API和Task.Run。请参阅有关StackOverflow的讨论
有关更多信息,请查看Kim Hamilton的文章。在编写第一帧后,在循环中等待完整响应
// Set read timeout to value recommended in the communication protocol specification
// so serial port operations don't stuck.
_port.WriteTimeout = 200;
_port.ReadTimeout = 200;
public void OnClick()
{
// Write first frame.
_port.Write(...);
// Now wait for the full response.
// Expected response length. Look for the constant value from the device communication
// protocol specification or extract from the response header (first response bytes) if
// there is any specified in the protocol.
int count = ...;
var buffer = new byte[count];
var offset = 0;
while (count > 0)
{
var readCount = _port.Read(buffer, offset, count);
offset += readCount;
count -= readCount;
}
// Now buffer contains full response or TimeoutException instance is thrown by SerialPort.
// Check response status code and write other frames.
}
为了不阻塞UI线程,您很可能仍然需要利用同步API和Task.Run。请参阅有关StackOverflow的讨论
有关更多信息,请查看Kim Hamilton的文章。您需要的是一种阻止某些代码执行的方法,直到发生其他事情,或者-如何在两个线程上同步运行。 .NET在System.Threading命名空间中有相当多的类用于同步。我们将在这里使用AutoResetEvent 把AutoResetEvent想象成一个旋转栅门 如果另一边的人停下来,你就不能前进。 当你向前移动时,你呼叫等待-它会阻止你移动, 直到有人打电话过来 现在,如果我们将其应用于我们的问题: 在得到可接受的响应之前,我们需要停止发送数据。 因此,在发送数据时调用Wait,并将响应处理代码调用设置为向前移动 下面是一个模拟调制解调器的示例。 您发送一些AT命令,它会响应,但响应总是以\r\n结尾 通过虚拟串行端口测试时的示例输出: 我只回答OK
您需要的是一种阻止某些代码执行的方法,直到发生其他事情为止,或者-如何在两个线程上同步运行。 .NET在System.Threading命名空间中有相当多的类用于同步。我们将在这里使用AutoResetEvent 把AutoResetEvent想象成一个旋转栅门 如果另一边的人停下来,你就不能前进。 当你向前移动时,你呼叫等待-它会阻止你移动, 直到有人打电话过来 现在,如果我们将其应用于我们的问题: 在得到可接受的响应之前,我们需要停止发送数据。 因此,在发送数据时调用Wait,并将响应处理代码调用设置为向前移动 下面是一个模拟调制解调器的示例。 您发送一些AT命令,它会响应,但响应总是以\r\n结尾 通过虚拟串行端口测试时的示例输出: 我只回答OK
请提供一份报告。从你的代码中,不清楚你的问题是什么。什么不起作用?在哪一行?你想要实现什么?此外,您的代码不完整:例如,缺少ReadByTedDataFromFile和packetList。@dymanoid我想将数据发送到串行端口,即此方法:ReadByteDataFromFile@dymanoid谢谢你的回复!我添加了代码,我的建议是首先编写可读代码,然后将内容拆分。F.e.有效载荷仅用于计算校验和,为什么还要复制数据?还有更好的方法可以将数据从一个阵列复制到另一个阵列。另外,我很确定GetBytesFromDecimal和校验和无关,或者是吗?另外,为什么需要解析校验和,如果它是一个数字,它可能应该返回一个int而不是字符串。另外,名为ReadByteDataFromFile的方法不会从文件中读取任何内容…@huysentruitw完全同意您的观点!请提供一份报告。从你的代码中,不清楚你的问题是什么。什么不起作用?在哪一行?你想要实现什么?此外,您的代码不完整:例如,缺少ReadByTedDataFromFile和packetList。@dymanoid我想将数据发送到串行端口,即此方法:ReadByteDataFromFile@dymanoid谢谢你的回复!我添加了代码,我的建议是首先编写可读代码,然后将内容拆分。F.e.有效载荷仅用于计算校验和,为什么还要复制数据?还有更好的方法可以将数据从一个阵列复制到另一个阵列。另外,我很确定GetBytesFromDecimal和校验和无关,或者是吗?另外,为什么需要解析校验和,如果它是一个数字,它可能应该返回一个int而不是字符串。另外,名为ReadByteDataFromFile的方法不会从文件中读取任何内容…@huysentruitw完全同意您的观点!所以实际上我需要在之后的一段时间里使用这个循环?还是在里面?循环是什么?我的代码片段中的while循环需要从设备获取完整响应(某种形式的帧确认,而不是其中的一部分),因为SerialPort.Read会在收到任何字节数后立即完成执行。这意味着我需要用while替换forloop,以便实际执行
ed想在一段时间后将其用于循环?还是在里面?循环是什么?我的代码片段中的while循环需要从设备获取某种形式的帧确认的完整响应,而不是它的一部分,因为SerialPort.Read在收到任何字节数后立即完成执行。这意味着我需要用while替换该forloop
var port = new SerialPort("COM2");
port.Open();
var mre = new AutoResetEvent(false);
var buffer = new StringBuilder();
port.DataReceived += (s, e) =>
{
buffer.Append(port.ReadExisting());
if (buffer.ToString().IndexOf("\r\n") >= 0)
{
Console.WriteLine("Got response: {0}", buffer);
mre.Set(); //allow loop to continue
buffer.Clear();
}
};
var commandsToSend = new string[] { "AT", "AT", "AT+CSQ" };
var responseTimeout = TimeSpan.FromSeconds(10);
foreach (var command in commandsToSend)
{
try
{
Console.WriteLine("Write '{0}' to {1}", command, port.PortName);
port.WriteLine(command);
Console.WriteLine("Waiting for response...");
//this is where we block
if (!mre.WaitOne(responseTimeout))
{
Console.WriteLine("Did not receive response");
//do something
}
}
catch (TimeoutException)
{
Console.WriteLine("Write took longer than expected");
}
catch
{
Console.WriteLine("Failed to write to port");
}
}
Console.ReadLine();
Write 'AT' to COM2
Waiting for response...
Got response: OK
Write 'AT' to COM2
Waiting for response...
Got response: OK
Write 'AT+CSQ' to COM2
Waiting for response...
Did not receive response