c#串口在收到数据后挂起

本文关键字:数据 挂起 串口 | 更新日期: 2023-09-27 18:08:25

这是我的代码

    public void ClosePort()
    {
        if (comPort.IsOpen == true)
        {
            Thread CloseDown = new Thread(() => CloseSerialOnExit(comPort)); //close port in new thread to avoid hang
            CloseDown.Start(); //close port in new thread to avoid hang
        }
    }
    private void CloseSerialOnExit(SerialPort port)
    {
        port.DiscardOutBuffer();
        port.Close();
        DisplayData(MessageType.Error, "Port communication has been closed" + " " + DateTime.Now + "'n");
    }

为什么当我的应用程序收到数据关闭不工作?这是这个案例的另一种解吗?我的工作步骤是:

  1. 连接端口,
  2. 扫描和接收数据,
  3. 断开连接端口,并再次从连接端口重复启动,但当我们想要启动连接端口时,系统显示错误信息:

访问com端口被拒绝。

表示由于端口实际上没有关闭而发生的事情。如何关闭港口?

这是我在开放端口下的代码

public bool OpenPort()
    {
        try
        {
            //first check if the port is already open
            //if its open then close it
            if (comPort.IsOpen == true) comPort.Close();
            //set the properties of our SerialPort Object
            comPort.BaudRate = int.Parse(_baudRate);    //BaudRate
            comPort.DataBits = int.Parse(_dataBits);    //DataBits
            comPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), _stopBits);    //StopBits
            comPort.Parity = (Parity)Enum.Parse(typeof(Parity), _parity);    //Parity
            comPort.Handshake = (Handshake)Enum.Parse(typeof(Handshake), _parity);    //Parity                
            comPort.PortName = _portName;   //PortName
            //now open the port
            comPort.WriteTimeout = 400;//Write timeout, if the efficiency of the serial driver software, can effectively avoid the deadlock
            comPort.ReadTimeout = 400;//Read timeout, ibid
            comPort.Open();
            comPort.DtrEnable = false;
            comPort.RtsEnable = false;
            //display message
            DisplayData(MessageType.Normal, "Port opened at " + DateTime.Now + "'n");
            //return true
            return true;
        }
        catch (Exception ex)
        {
            DisplayData(MessageType.Error, ex.Message);
            return false;
        }
    }
这是我在comPort_datareceived 中的代码
void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
            //determine the mode the user selected (binary/string)
            switch (CurrentTransmissionType)
            {
                //user chose string
                case TransmissionType.Text:
                    //read data waiting in the buffer
                    string msg = comPort.ReadExisting();
                    //display the data to the user
                    DisplayData(MessageType.Incoming, msg + "'n");
                    break;
                //user chose binary
                case TransmissionType.Hex:
                    //retrieve number of bytes in the buffer
                    int OpeCode = 0;
                    int RequestID = 0;
                    int Product = 0;
                    int IPenNo = 0;
                    string status = " ";
                    while (true)
                    {
                        DateTime time = DateTime.Now;             // Use current time.
                        string format = "dddddddd, MMMMM d, yyyy HH:mm:ss";
                        string currentTime = time.ToString(format);
                        byte[] TrueData = new byte[256];
                        try
                        {
                            int bytes = comPort.BytesToRead;
                            if (bytes == 0) continue;
                            //create a byte array to hold the awaiting data
                            byte[] comBuffer = new byte[bytes];
                            comPort.Read(comBuffer, 0, bytes);
                            DisplayData(MessageType.Incoming, "Hexa :" + ByteToHex(comBuffer) + "'n");
                            DisplayData(MessageType.Incoming, "Byte :" + bytes.ToString() + "'n");
                            if (bytes == 3)
                            {
                                var lines = File.ReadAllLines(Fullpath).ToList();
                                // Remove as many lines as you'd like from the end
                                if (lines.Count > 2)
                                {
                                    lines.RemoveRange(lines.Count - 2, 2);
                                }
                                // Iterate backwards through the list until we've updated 2 (or more or less) lines
                                var linesUpdated = 0;
                                for (var i = lines.Count - 1; i >= 0 && linesUpdated < 1; i--)
                                {
                                    if (lines[i].Contains("OK"))
                                    {
                                        lines[i] = lines[i].Replace("OK", "NG");
                                        linesUpdated++;
                                    }
                                }
                                File.WriteAllLines(Fullpath, lines.ToArray());
                                //DisplayData(MessageType.Incoming, "NG" + "'n");
                            }
                            if (bytes == 2)
                            {
                                continue;
                            }
                            int etx_ok = 0;
                            for (int i = 0; i < bytes; i++)
                            {
                                if (comBuffer[i] == 0x02)
                                {
                                    //DisplayData(MessageType.Incoming, "cek II:" + checkStatus + "'n");
                                    int length = comBuffer[i + 1];
                                    DisplayData(MessageType.Incoming, "Length=" + length.ToString() + "'n");
                                    if (String.IsNullOrEmpty(bytes.ToString()))
                                    {
                                        status = "NG";
                                    }
                                    if (length + i + 1 != bytes && status == " ")
                                    {
                                        DisplayData(MessageType.Incoming, length.ToString() + " " + i.ToString() + " " + bytes.ToString() + " ");
                                        status = "NG";
                                        DisplayData(MessageType.Incoming, "ERROR 'n");
                                        //break;
                                    }
                                    else
                                    {
                                        status = "OK";
                                    }
                                    DisplayData(MessageType.Incoming, "ini statusnya  : " + status + "'n");
                                    if (comBuffer[length + i - 1] == 0x03)
                                    {
                                        DisplayData(MessageType.Incoming, "ETX OK'n");
                                        etx_ok = 1;
                                        OpeCode = comBuffer[i + 2];
                                        DisplayData(MessageType.Incoming, "OpeCode=" + OpeCode.ToString() + ",");
                                        RequestID = comBuffer[i + 3];
                                        DisplayData(MessageType.Incoming, "RequestID=" + RequestID.ToString() + ",");
                                        int StoreCode = comBuffer[i + 4];
                                        DisplayData(MessageType.Incoming, "StoreCode=" + StoreCode.ToString() + ",");
                                        int ProductBatteryTraining = comBuffer[i + 5];
                                        DisplayData(MessageType.Incoming, "ProductBatteryTraining=" + ProductBatteryTraining.ToString() + ",");
                                        Product = ProductBatteryTraining >> 4;
                                        DisplayData(MessageType.Incoming, "  Product=" + Product.ToString() + ",");
                                        int Battery = ProductBatteryTraining & 4;
                                        DisplayData(MessageType.Incoming, "  Batery=" + Battery.ToString() + ",");
                                        int Training = ProductBatteryTraining & 1;
                                        DisplayData(MessageType.Incoming, "  Training=" + Training.ToString() + ",");
                                        IPenNo = comBuffer[i + 6];
                                        DisplayData(MessageType.Incoming, "IPenNo=" + IPenNo.ToString() + ",");
                                        int CrcCalc = comBuffer[length + i] + 0x11;
                                        for (int j = 7, k = 0; j < length; j++, k++)
                                        {
                                            //syswrite STDOUT , "TrueDataX " . $length . "'n";
                                            DisplayData(MessageType.Incoming, "TrueDataX " + length.ToString() + "," + "'n");
                                            TrueData[k] = comBuffer[i + j];
                                        }
                                        if (OpeCode == 0x63)
                                        {
                                            byte[] replyStr = new byte[] { 
                                        Convert.ToByte(0x45), Convert.ToByte(0x53), Convert.ToByte(0x4c), Convert.ToByte(0x14), Convert.ToByte(0x09), Convert.ToByte(0x00),                             //#Length Change
                                        Convert.ToByte(0x02), Convert.ToByte(0x08),Convert.ToByte(OpeCode), Convert.ToByte(RequestID),Convert.ToByte(Product-1), Convert.ToByte(IPenNo),                                       //#Reply Header Data                   
                                        Convert.ToByte(0x00),                                                                                                                                           //#Reply Status      
                                        Convert.ToByte(0x03), Convert.ToByte(CrcCalc),                                                                                                                     //#Footer Data    
                                        Convert.ToByte(0xcc), Convert.ToByte(0xcc) 
                                        };
                                            comPort.Write(replyStr, 0, replyStr.Length);
                                            //write file to textfile
                                            //string path = @"d:'yosafat'testfile'tes1_Friday0916201614.33.txt"; 
                                            string IPenID = IPenNo.ToString();
                                            string appendText = ("IPen ID 't" + "Datetime't't't't't" + "Status" + Environment.NewLine + IPenID + "'t't" + currentTime + "'t't" + status + Environment.NewLine);
                                            File.AppendAllText(Fullpath, appendText);
                                        }
                                    }
                                    else
                                    {
                                        OpeCode = 0;
                                        //syswrite STDOUT , "ETX Bad Data" . $length . "'n";
                                        DisplayData(MessageType.Incoming, "ETX Bad Data" + length.ToString() + "'n");
                                        break;
                                    }
                                }
                                if (etx_ok == 1)
                                {
                                    break;
                                }
                            }
                        }
                        catch (Exception) { }
                    }
            }
        }
    public static int GetFirstOccurance(byte byteToFind, byte[] byteArray)
    {
        return Array.IndexOf(byteArray, byteToFind);
    }

c#串口在收到数据后挂起

SerialPort.DataReceived事件处理程序中将return添加到catch块中,以便在exception发生时退出while循环。

while (true)
{
    //...
    try {
        //...
    } catch (Exception) { return; //add this}
}

在另一个线程Close端口之后,读取数据时可能出现Exception(这一行:comPort.Read(comBuffer, 0, bytes);)。没有return语句,您将永远不会退出while循环,GC将不会处理SerialPort。因此,当您尝试重新打开端口时,您将失败。

为什么在一个单独的线程中调用CloseSerialOnExit ?把它称为同步不是更容易吗?真的要花很多时间吗?

无论如何,如果你需要这样,你应该确保Thread对象在线程完成之前不会被GC化。你应该让CloseDown成为成员。

您还可以使用一些同步来查看ClosePort是否在OpenPort开始时完成。

Thread CloseDown = null;
public void ClosePort()
{
    if (comPort.IsOpen == true)
    {
        CloseDown = new Thread(() => CloseSerialOnExit(comPort)); //close port in new thread to avoid hang
        CloseDown.Start(); //close port in new thread to avoid hang
    }
}