我正在编写控制机器人的应用程序。我有一个按钮点击方法,它应该打开或关闭端口。
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
}