我正在编写控制机器人的应用程序。我有一个按钮点击方法,它应该打开或关闭端口。
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事件处理程序尝试从串口缓冲区获取该数据。
感谢您阅读这封情书,感谢您的帮助:)。
答案 0 :(得分:1)
我自己刚遇到此问题,解决方法是在BeginInvoke()
eventhandler中使用Invoke()
而不是SerialPort.DataRecieved
。
答案 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
}