等待来自串行端口的响应,然后发送下一个数据

时间:2019-03-06 14:57:31

标签: c# serial-port

我正在从Public Sub Application_ItemSend(ByVal thisItem As Object, Cancel As Boolean) Dim ns As Outlook.NameSpace Dim olfolder As MAPIFolder Dim Item As Object Set olApp = CreateObject("Outlook.Application") Set olNs = olApp.GetNamespace("MAPI") Set firstFolder = olNs.Folders("test@dk.com") ' name of my shared inbox Set olfolder = firstFolder.Folders("sent items") ' iterate thru emails For Each Item In olfolder.Items ' check subject content & date difference If InStr(Item.Subject, thisItem.Recipients) And DateDiff("m", Item.SentOn, Now) < 1 Then ' added this part If MsgBox("already sent", vbYesNo + vbQuestion + vbMsgBoxSetForeground, "Message Text Warning") = vbNo Then ' cancel the email Cancel = True End If Exit For End If 文件中读取字节数据,并将整个字节数据拆分为.bin字节帧,所以我想一个接一个的16字节帧,然后等到第一个帧结束其循环

SerialPort类的回调方法:

16-16

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); } } } 按钮单击:

FdBrowseFile_Click

ReadByteDataFromFile方法:

private void FdBrowseFile_Click(object sender, RoutedEventArgs e)
{
    Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
    Nullable<bool> result = dlg.ShowDialog();
    if (result == true)
    {
        byte[] fileBytes = File.ReadAllBytes(filename);

        foreach (byte[] copySlice in fileBytes.Slices(16))
        {
            var splitedByteArray = copySlice;
            if (splitedByteArray.Length != 16)
            {
                byte[] padd = new byte[16];
                var startAt = 0;
                Array.Copy(splitedByteArray, 0, padd, startAt, splitedByteArray.Length);
                packetList.Add(padd);
            }
            else
            {
                packetList.Add(splitedByteArray);
            }
        }
        ReadByteDataFromFile(packetList[0]);
    }
}

如何为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); } } 方法添加延迟?

2 个答案:

答案 0 :(得分:1)

写完第一帧后,循环等待完整响应。

// 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的C# await event and timeout in serial port communication讨论。

有关更多信息,请查看Kim Hamilton的Top 5 SerialPort Tips文章。

答案 1 :(得分:1)

您需要的是一种阻止某些代码执行的方法,直到发生其他事情为止,或者-如何使事情在两个线程上同步运行。 .NET在System.Threading命名空间中有很多类用于同步。我们将在此处使用AutoResetEvent

AutoResetEvent视为旋转门。

turnstile

如果另一边的人停下来,您将无法前进。 继续前进时,您拨打Wait-它阻止您前进, 直到有人致电Set

现在,如果我们将其应用于我们的问题: 我们需要停止发送数据,直到获得可接受的响应。 因此,在发送数据时调用Wait,然后让响应处理代码调用Set使其前进。

这是一个模拟调制解调器的示例。 您发送一些AT命令,它会响应,但是响应始终以\r\n结尾。

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();

通过虚拟串行端口测试时的样本输出: (我只回复OK<CR><LF>

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