尝试关闭()串口后程序崩溃

时间:2013-03-24 08:10:04

标签: c# serial-port

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

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(数据)函数

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

ports class:

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事件处理程序尝试从串口缓冲区获取该数据。

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

3 个答案:

答案 0 :(得分:1)

我自己刚遇到此问题,解决方法是在BeginInvoke() eventhandler中使用Invoke()而不是SerialPort.DataRecieved

参考:duplicate question

答案 1 :(得分:1)

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

答案 2 :(得分:1)

我会使用以下处理程序

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
}