1

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

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

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

4

3 回答 3

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;
于 2015-01-21T17:28:18.990 回答
1

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

参考:重复问题

于 2013-11-01T09:50:13.423 回答
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
}
于 2015-06-05T05:49:31.787 回答