c#串口在收到数据后挂起
本文关键字:数据 挂起 串口 | 更新日期: 2023-09-27 18:08:25
这是我的代码
public void ClosePort()
{
if (comPort.IsOpen == true)
{
Thread CloseDown = new Thread(() => CloseSerialOnExit(comPort)); //close port in new thread to avoid hang
CloseDown.Start(); //close port in new thread to avoid hang
}
}
private void CloseSerialOnExit(SerialPort port)
{
port.DiscardOutBuffer();
port.Close();
DisplayData(MessageType.Error, "Port communication has been closed" + " " + DateTime.Now + "'n");
}
为什么当我的应用程序收到数据关闭不工作?这是这个案例的另一种解吗?我的工作步骤是:
- 连接端口,
- 扫描和接收数据,
- 断开连接端口,并再次从连接端口重复启动,但当我们想要启动连接端口时,系统显示错误信息:
访问com端口被拒绝。
表示由于端口实际上没有关闭而发生的事情。如何关闭港口?
这是我在开放端口下的代码
public bool OpenPort()
{
try
{
//first check if the port is already open
//if its open then close it
if (comPort.IsOpen == true) comPort.Close();
//set the properties of our SerialPort Object
comPort.BaudRate = int.Parse(_baudRate); //BaudRate
comPort.DataBits = int.Parse(_dataBits); //DataBits
comPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), _stopBits); //StopBits
comPort.Parity = (Parity)Enum.Parse(typeof(Parity), _parity); //Parity
comPort.Handshake = (Handshake)Enum.Parse(typeof(Handshake), _parity); //Parity
comPort.PortName = _portName; //PortName
//now open the port
comPort.WriteTimeout = 400;//Write timeout, if the efficiency of the serial driver software, can effectively avoid the deadlock
comPort.ReadTimeout = 400;//Read timeout, ibid
comPort.Open();
comPort.DtrEnable = false;
comPort.RtsEnable = false;
//display message
DisplayData(MessageType.Normal, "Port opened at " + DateTime.Now + "'n");
//return true
return true;
}
catch (Exception ex)
{
DisplayData(MessageType.Error, ex.Message);
return false;
}
}
这是我在comPort_datareceived
中的代码void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//determine the mode the user selected (binary/string)
switch (CurrentTransmissionType)
{
//user chose string
case TransmissionType.Text:
//read data waiting in the buffer
string msg = comPort.ReadExisting();
//display the data to the user
DisplayData(MessageType.Incoming, msg + "'n");
break;
//user chose binary
case TransmissionType.Hex:
//retrieve number of bytes in the buffer
int OpeCode = 0;
int RequestID = 0;
int Product = 0;
int IPenNo = 0;
string status = " ";
while (true)
{
DateTime time = DateTime.Now; // Use current time.
string format = "dddddddd, MMMMM d, yyyy HH:mm:ss";
string currentTime = time.ToString(format);
byte[] TrueData = new byte[256];
try
{
int bytes = comPort.BytesToRead;
if (bytes == 0) continue;
//create a byte array to hold the awaiting data
byte[] comBuffer = new byte[bytes];
comPort.Read(comBuffer, 0, bytes);
DisplayData(MessageType.Incoming, "Hexa :" + ByteToHex(comBuffer) + "'n");
DisplayData(MessageType.Incoming, "Byte :" + bytes.ToString() + "'n");
if (bytes == 3)
{
var lines = File.ReadAllLines(Fullpath).ToList();
// Remove as many lines as you'd like from the end
if (lines.Count > 2)
{
lines.RemoveRange(lines.Count - 2, 2);
}
// Iterate backwards through the list until we've updated 2 (or more or less) lines
var linesUpdated = 0;
for (var i = lines.Count - 1; i >= 0 && linesUpdated < 1; i--)
{
if (lines[i].Contains("OK"))
{
lines[i] = lines[i].Replace("OK", "NG");
linesUpdated++;
}
}
File.WriteAllLines(Fullpath, lines.ToArray());
//DisplayData(MessageType.Incoming, "NG" + "'n");
}
if (bytes == 2)
{
continue;
}
int etx_ok = 0;
for (int i = 0; i < bytes; i++)
{
if (comBuffer[i] == 0x02)
{
//DisplayData(MessageType.Incoming, "cek II:" + checkStatus + "'n");
int length = comBuffer[i + 1];
DisplayData(MessageType.Incoming, "Length=" + length.ToString() + "'n");
if (String.IsNullOrEmpty(bytes.ToString()))
{
status = "NG";
}
if (length + i + 1 != bytes && status == " ")
{
DisplayData(MessageType.Incoming, length.ToString() + " " + i.ToString() + " " + bytes.ToString() + " ");
status = "NG";
DisplayData(MessageType.Incoming, "ERROR 'n");
//break;
}
else
{
status = "OK";
}
DisplayData(MessageType.Incoming, "ini statusnya : " + status + "'n");
if (comBuffer[length + i - 1] == 0x03)
{
DisplayData(MessageType.Incoming, "ETX OK'n");
etx_ok = 1;
OpeCode = comBuffer[i + 2];
DisplayData(MessageType.Incoming, "OpeCode=" + OpeCode.ToString() + ",");
RequestID = comBuffer[i + 3];
DisplayData(MessageType.Incoming, "RequestID=" + RequestID.ToString() + ",");
int StoreCode = comBuffer[i + 4];
DisplayData(MessageType.Incoming, "StoreCode=" + StoreCode.ToString() + ",");
int ProductBatteryTraining = comBuffer[i + 5];
DisplayData(MessageType.Incoming, "ProductBatteryTraining=" + ProductBatteryTraining.ToString() + ",");
Product = ProductBatteryTraining >> 4;
DisplayData(MessageType.Incoming, " Product=" + Product.ToString() + ",");
int Battery = ProductBatteryTraining & 4;
DisplayData(MessageType.Incoming, " Batery=" + Battery.ToString() + ",");
int Training = ProductBatteryTraining & 1;
DisplayData(MessageType.Incoming, " Training=" + Training.ToString() + ",");
IPenNo = comBuffer[i + 6];
DisplayData(MessageType.Incoming, "IPenNo=" + IPenNo.ToString() + ",");
int CrcCalc = comBuffer[length + i] + 0x11;
for (int j = 7, k = 0; j < length; j++, k++)
{
//syswrite STDOUT , "TrueDataX " . $length . "'n";
DisplayData(MessageType.Incoming, "TrueDataX " + length.ToString() + "," + "'n");
TrueData[k] = comBuffer[i + j];
}
if (OpeCode == 0x63)
{
byte[] replyStr = new byte[] {
Convert.ToByte(0x45), Convert.ToByte(0x53), Convert.ToByte(0x4c), Convert.ToByte(0x14), Convert.ToByte(0x09), Convert.ToByte(0x00), //#Length Change
Convert.ToByte(0x02), Convert.ToByte(0x08),Convert.ToByte(OpeCode), Convert.ToByte(RequestID),Convert.ToByte(Product-1), Convert.ToByte(IPenNo), //#Reply Header Data
Convert.ToByte(0x00), //#Reply Status
Convert.ToByte(0x03), Convert.ToByte(CrcCalc), //#Footer Data
Convert.ToByte(0xcc), Convert.ToByte(0xcc)
};
comPort.Write(replyStr, 0, replyStr.Length);
//write file to textfile
//string path = @"d:'yosafat'testfile'tes1_Friday0916201614.33.txt";
string IPenID = IPenNo.ToString();
string appendText = ("IPen ID 't" + "Datetime't't't't't" + "Status" + Environment.NewLine + IPenID + "'t't" + currentTime + "'t't" + status + Environment.NewLine);
File.AppendAllText(Fullpath, appendText);
}
}
else
{
OpeCode = 0;
//syswrite STDOUT , "ETX Bad Data" . $length . "'n";
DisplayData(MessageType.Incoming, "ETX Bad Data" + length.ToString() + "'n");
break;
}
}
if (etx_ok == 1)
{
break;
}
}
}
catch (Exception) { }
}
}
}
public static int GetFirstOccurance(byte byteToFind, byte[] byteArray)
{
return Array.IndexOf(byteArray, byteToFind);
}
在SerialPort.DataReceived
事件处理程序中将return
添加到catch
块中,以便在exception
发生时退出while
循环。
while (true)
{
//...
try {
//...
} catch (Exception) { return; //add this}
}
在另一个线程Close
端口之后,读取数据时可能出现Exception
(这一行:comPort.Read(comBuffer, 0, bytes);
)。没有return
语句,您将永远不会退出while
循环,GC将不会处理SerialPort。因此,当您尝试重新打开端口时,您将失败。
为什么在一个单独的线程中调用CloseSerialOnExit
?把它称为同步不是更容易吗?真的要花很多时间吗?
无论如何,如果你需要这样,你应该确保Thread
对象在线程完成之前不会被GC化。你应该让CloseDown
成为成员。
您还可以使用一些同步来查看ClosePort
是否在OpenPort
开始时完成。
Thread CloseDown = null;
public void ClosePort()
{
if (comPort.IsOpen == true)
{
CloseDown = new Thread(() => CloseSerialOnExit(comPort)); //close port in new thread to avoid hang
CloseDown.Start(); //close port in new thread to avoid hang
}
}