【问题标题】:Program crashes after trying to close() serial port尝试关闭()串行端口后程序崩溃
【发布时间】:2013-03-24 08:10:03
【问题描述】:

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

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

有一个跨线程错误,所以我将函数内容包装到 InvokeRequired 条件中。

现在还有其他错误: 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 事件处理程序会尝试从串行端口的缓冲区中获取该数据。

感谢您阅读这封情书,感谢您的帮助:)。

【问题讨论】:

  • 将 try/catch 块添加到您的函数和事件处理程序中,然后查看您得到了什么异常。
  • “崩溃”是什么意思?
  • 在我的情况下崩溃意味着程序不再响应,我的视觉工作室无法收到任何错误;/
  • 如果程序不再响应,那就是“挂起”,而不是“崩溃”。
  • @Coder 为什么会有用?如果引发了未处理的异常,它将继续冒泡,直到找到异常处理程序。如果您的程序中没有异常处理代码,它将到达全局异常处理程序,该处理程序将显示有关“未处理异常”的错误消息。仅仅为了调试目的而添加 try-catch 块是没有用的。

标签: c# serial-port


【解决方案1】:

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

参考:duplicate question

【讨论】:

    【解决方案2】:

    如果您收到大量数据,就会发生这种情况。 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;
    

    【讨论】:

      【解决方案3】:

      我会使用以下处理程序

      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
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多