试图关闭()串行端口后程序崩溃



我正在编写控制机器人的应用程序。我有一个按钮点击方法,它应该打开或关闭端口。

private void cONNECTToolStripMenuItem_CheckStateChanged(
                 object sender, EventArgs e)
{
    if (cONNECTToolStripMenuItem.Checked)
    {
        cONNECTToolStripMenuItem.Text = "DISCONNECT!";
        ports.connect();
    }
    else
    {
        cONNECTToolStripMenuItem.Text = "CONNECT!";
        ports.disconnect();
    }
}

此外,我有DataReceived事件处理程序,它在接收到串行端口的一些数据后被调用。

private void serialPort_DataReceived(
                 object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    SerialPort sp = (SerialPort)sender;
    string data = sp.ReadExisting();
    mainForm.addData(data);
} 

当这个事件处理程序试图调用addData(data)函数

public void addData(string data)
{
    //if (!this.Disposing || !this.IsDisposed || 
    //    !this.listBox1.Disposing || !this.listBox1.IsDisposed)
    if (this.listBox1.InvokeRequired)
    {
        SetTextCallback d = new SetTextCallback(addData);
        this.Invoke(d, new object[] { data });
    }
    else
        listBox1.Items.Add(data);         
}

有一个跨线程错误,所以我把函数内容包装成invokerrequiredcondition。

现在有其他错误:1. 程序在尝试调用ports.disconnect()函数后崩溃

public void disconnect()
{
    serialPort.Close();
}

港口类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
namespace server_client
{
    public class COM_Port
    {
        private Main_Form mainForm;
        public SerialPort serialPort;
        //MySQL - 1, XML File - 2, None - 0
        public int writeStatus;
        public COM_Port(Main_Form form)
        {
            mainForm = form;
            //by default niekur neirasineja nebent pasirenka
            writeStatus = 0;
            //sukuriam serialPort kintamaji
            serialPort = new SerialPort();
            //nustatom duomenis portui
            serialPort.BaudRate = 9600;
            serialPort.DataBits = 8;
            serialPort.StopBits = StopBits.One;
            serialPort.ReadTimeout = 500;
            serialPort.WriteTimeout = 500;

        }
        ~COM_Port()
        {
            disconnect();
            serialPort.Dispose();
        }
        public void connect()
        {
            if (!serialPort.IsOpen)
                if (serialPort.PortName != "") 
                    serialPort.Open();
                else
                    MessageBox.Show("Please choose COM Port in settings.");
        }
        public void disconnect()
        {
            //serialPort.DiscardInBuffer();
            //serialPort.DiscardOutBuffer();
            serialPort.Close();
        }
        public void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            string data = null;
            SerialPort sp = (SerialPort)sender;
            if (sp.IsOpen)
                data = sp.ReadExisting();
            else
                data = null;
            //perduoda duomenis atvaizdavimui i maina
            if (data != null)
            {
                mainForm.addData(data);
                switch (writeStatus)
                {
                    //neirasyti
                    case 0:
                        break;
                    //irasyti i mysql
                    case 1:
                        MySQL mysql = new MySQL();
                        break;
                    //irasyti i xml file
                    case 2:
                        File file = new File();
                        break;
                    default:
                        break;
                }
            }
        } 
    }
}

我相信,关闭端口机器人仍在向我发送数据,DataReceived事件处理程序试图从串口缓冲区获取该数据。

谢谢你读这封情书,谢谢你的帮助:)。

如果接收到大量数据,就会发生这种情况。DataReceived事件处理程序一直很忙,并试图读取缓冲区。在这个处理程序中,ReadExisting()的执行时间最长。当DataReceived处理程序正在执行时,不能关闭端口。您不能等待ReadExisting()完成,因为在此等待期间,DataReceived事件将再次被触发。

因此,在关闭端口之前,必须停止调用ReadExisting(),例如:

首先构造一个新的SerialPort实例

 SerialComPort = new SerialPort();
 SerialComPort.DataReceived += new SerialDataReceivedEventHandler(SerialComPort_DataReceived);
 SerialComPort.ReadTimeout = 100; //[ms] Time out if Read operation does not finish
 bool SerialPortPendingClose=false;

那么DataReceived处理程序看起来像:

byte[] InputData = new byte[512]; 
private void SerialComPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
     if (!SerialPortPendingClose)
     { SerialComPort.Read(InputData, 0, 512); }
     //Do something with InputData
}
最后,使用(例如)关闭端口:
SerialPortPendingClose = true;
Thread.Sleep(SerialComPort.ReadTimeout); //Wait for reading threads to finish
SerialComPort.Close();
SerialPortPendingClose = false;

我自己刚刚遇到这个问题,解决方案是在SerialPort.DataRecieved事件处理程序中使用BeginInvoke()而不是Invoke()

参考:重复问题

我将使用以下处理程序

private void SerialComPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
 if (!SerialPortPendingClose)
 { SerialComPort.Read(InputData, 0, 512); }
 //Do something with InputData
 else
 { SerialComPort.DataReceived -= SerialComPort_DataReceived;} //to ensure this will be called only once
}

最新更新