serial read open example ejemplo datareceived com1 c# serial-port

c# - read - using serial port



System.IO.IOException: un dispositivo conectado al sistema no funciona C#.NET 4.0 (2)

En mi experiencia, 9 de cada 10 veces esto sucede cuando otro subproceso (terminado o no) no tiene acceso exclusivo al puerto de hardware.

Intente escribir un contenedor para las operaciones del puerto, lo más importante es abrirlo / cerrarlo, usando SyncLock . https://msdn.microsoft.com/en-us/library/3a86s51t.aspx

En una nota similar, en general, consideraría que probar / detectar el control del hardware es una mala práctica, a menos que haya un adecuado manejo de excepciones.

La razón (que podría aplicarse aquí) es que, en el caso de que se produzca una excepción, el hardware se bloqueará y, lo que es peor, la excepción ocultará la verdadera causa de los errores.

En el código anterior veo salida de mensajes en el estilo.

DebugPrint(ex.Message);

sería bastante mejor hacer esto como

DebugPrint(ex.tostring());

ya que esto también exportará el seguimiento de la pila en la excepción.

Lo que haría sería implementar un registrador de excepciones que escriba esas excepciones en un archivo de texto (con marca de tiempo) en algún lugar de la computadora que esté ejecutando. Seguir los datos de excepción registrados (junto con toda la información pertinente) puede llevar a una mejor comprensión de por qué sucede exactamente esto.

He construido una aplicación C # que lee y escribe datos desde un puerto serie. El dispositivo conectado al puerto serie es un convertidor FTDI USB a serie que se comunica con el hardware a través de un módulo inalámbrico XBee. El hardware prueba los módulos de la batería para determinar la capacidad y el voltaje de estado estable, etc. Estas pruebas tardan días en completarse.

De vez en cuando, el puerto serie parece dejar de responder y emite una excepción System.IO.IOException: un dispositivo conectado al sistema no funciona correctamente.

Aquí está la traza de la pila:

at system.IO.Ports.InternalResources.WinIOError at system.IO.Ports.SerialStream.EndWrite at system.IO.Ports.SerialStream.Write at system.IO.Ports.SerialPort.Write at BatteryCharger.CommunicationClass.ApiTransmission

después de que se produce este error, se System.UnauthorizedAccessException: Access to the port is denied un System.UnauthorizedAccessException: Access to the port is denied produce un error y este error se produce cada vez que el software intenta escribir en el puerto y nunca se recupera hasta que detenga la depuración y reinicio del software solo para lo mismo Que suceda unos días después.

¿Cómo evito que ocurra este error o hay una manera de recuperarme exitosamente de estos errores en la declaración de captura del error?

Estoy leyendo el puerto serie continuamente en un subproceso de trabajo en segundo plano y escribiendo desde otro subproceso.

También he intentado todas las partes y piezas de errores heredadas que se han sugerido en este foro, pero ninguna de ellas parece hacer ninguna diferencia. El error se produce en Windows XP Pro SP3 32bit y Windows7 Pro 32bit.

Aquí está el CommunicationClass.cs - código de transmisión en serie.

public static bool ApiTransmission(TXpacket transmission) { //clear all previous data that may have been in the buffer before doing a transmission Variables.dataParserPacket_buff.Clear(); //TXpacket xbeetransmision = new TXpacket(); byte[] packet = transmission.GeneratePacket(); try { if (_serialPort.IsOpen) { #if Console Log.write("TX-Packet: " + StringHandler.listToString(packet.ToList<byte>())); #endif _serialPort.Write(packet, 0, packet.Length); Thread.Sleep(100); } else { #if Console Log.write("serial port is closed"); #endif return false; } } catch (UnauthorizedAccessException ex) { MessageBox.Show(ex.ToString()); Log.write("UnauthorizedAccessException"); } catch (IOException ex) { MessageBox.Show(ex.ToString()); Log.write("IOexception"); //_serialPort.Close(); //Thread.Sleep(100); //_serialPort.Open(); } catch (Exception ex) { MessageBox.Show(ex.ToString()); #if Console Log.write(ex.ToString()); #endif } return true; }

Así es como inicializo mi puerto serial.

public CommunicationClass(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits) { _analysePacketBGW.DoWork += new DoWorkEventHandler(_analysePacketBGW_DoWork); _analysePacketBGW.WorkerReportsProgress = true; _analysePacketBGW.WorkerSupportsCancellation = true; _readBGW.DoWork += new DoWorkEventHandler(_readThread_DoWork); _readBGW.WorkerSupportsCancellation = true; _readBGW.WorkerReportsProgress = true; _parserStarterBGW.DoWork += new DoWorkEventHandler(_parserStarterThread_DoWork); _parserStarterBGW.WorkerSupportsCancellation = true; _parserStarterBGW.WorkerReportsProgress = true; if (_readBGW != null) { _readBGW.CancelAsync(); } _serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits); //SerialPortFixer.Execute(portName); //Thread.Sleep(1000); //using (_serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits)) //{ // //_serialPort.Open(); //} _serialPort.ErrorReceived += new SerialErrorReceivedEventHandler(_serialPort_ErrorReceived); _dataqueuepp = new ManualResetEvent(false); _serialPort.Open(); _readBGW.RunWorkerAsync(); _parserStarterBGW.RunWorkerAsync(); CommunicationClass.PacketReceived += new DataPacketReceived(CommunicationClass_PacketReceived); }

Y el trabajador de fondo que maneja la lectura del puerto serie.

void _readThread_DoWork(object sender, DoWorkEventArgs e) { #if Console Log.write("Read()"); #endif while (!_readBGW.CancellationPending) { try { int message = _serialPort.ReadByte(); try { Variables.dataQueue.Enqueue(message); } catch (Exception ex) { MessageBox.Show(ex.Message + " " + message.ToString()); } _dataqueuepp.Set(); //Console.Write(String.Format("{0:X2}", message) + " "); } catch (TimeoutException) { Log.write("read timeout"); } catch (IOException) { Log.write("read IOException"); } catch (ThreadAbortException) { Log.write("read thread aborted"); } catch (Exception ex) { MessageBox.Show(ex.ToString()); } finally { } } }

Ahora reescribiré el código para leer y escribir en / desde el puerto serie desde el mismo hilo para ver si eso hace alguna diferencia.

EDITAR

Basándome en los comentarios de Jim, agregué lo siguiente a la declaración de captura de IOException:

catch (IOException ex) { MessageBox.Show(ex.ToString()); Log.write("IOexception"); _readBGW.CancelAsync(); Thread.Sleep(100); _serialPort.Close(); Thread.Sleep(100); _serialPort.Open(); Thread.Sleep(100); _readBGW.RunWorkerAsync(); _serialPort.Write(packet, 0, packet.Length); }

Esperemos que al detener el _serialPort.trabajo del trabajador de fondo, cerrar el puerto, volver a abrir el puerto, ejecutar nuevamente el trabajador de fondo e intentar escribir el mismo comando será suficiente para recuperarse exitosamente de este error. El cuadro de mensaje todavía bloquea el código para que pueda ver cuándo se produce el error y puede supervisar cómo se recupera.

No me gustan los parches de software como este, pero si funciona, entonces funciona.

Editar 2

Después de agregar el código anterior, mi software se bloqueó nuevamente pero ahora arroja una "UnauthorizedAccessException: el acceso al puerto está denegado" cuando llamo a _serialPort.Close ();

System.UnauthorizedAccessException was unhandled Message=Access to the port is denied. Source=System StackTrace: at System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str) at System.IO.Ports.InternalResources.WinIOError() at System.IO.Ports.SerialStream.Dispose(Boolean disposing) at System.IO.Stream.Close() at System.IO.Ports.SerialPort.Dispose(Boolean disposing) at System.IO.Ports.SerialPort.Close() at BatteryCharger.CommunicationClass.ApiTransmission(TXpacket transmission) in E:/Mijn Documenten/Research/Copy of BatteryCharger_V12/BatteryCharger/CommunicationClass.cs:line 436 at BatteryCharger.CommunicationClass.tx1(TXpacket packet, String callingMethod) in E:/Mijn Documenten/Research/Copy of BatteryCharger_V12/BatteryCharger/CommunicationClass.cs:line 356 at BatteryCharger.XBee.setPin(String pinID, Byte status, XBee slave) in E:/Mijn Documenten/Research/Copy of BatteryCharger_V12/BatteryCharger/XBee.cs:line 215 at BatteryCharger.XBee.setPins(Int32 pins, XBee slave) in E:/Mijn Documenten/Research/Copy of BatteryCharger_V12/BatteryCharger/XBee.cs:line 177 at BatteryCharger.BatteryCharger.requestVoltage(Int32 block) in E:/Mijn Documenten/Research/Copy of BatteryCharger_V12/BatteryCharger/BatteryCharger.cs:line 595 at BatteryCharger.BatteryCharger.requestVoltages() in E:/Mijn Documenten/Research/Copy of BatteryCharger_V12/BatteryCharger/BatteryCharger.cs:line 612 at BatteryCharger.Form1.RunCommandOn(List`1 battList, Int32 command, Double lowerLimit, Double upperLimit) in E:/Mijn Documenten/Research/Copy of BatteryCharger_V12/BatteryCharger/Form1.cs:line 522 at BatteryCharger.Form1.chargeBlock(Int32 blockNr, Double lowerLimit, Double upperLimit) in E:/Mijn Documenten/Research/Copy of BatteryCharger_V12/BatteryCharger/Form1.cs:line 689 at BatteryCharger.Form1.<btnCheckCapacities_Click>b__13() in E:/Mijn Documenten/Research/Copy of BatteryCharger_V12/BatteryCharger/Form1.cs:line 619 at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException:

¿Que esta pasando aqui?


Uso intensamente la clase SerialPort para comunicarme continuamente con PLC a través de adaptadores USB durante meses sin interrupción. Así que no estoy de acuerdo con quién dice que la clase SerialPort .NET no funciona. Intente insertar la creación de la clase en el hilo, aquí hay una muestra de código con BackgroundWorker.

void ThreadEngine_DoWork(object sender, DoWorkEventArgs e) { // Do not access the form''s BackgroundWorker reference directly. // Instead, use the reference provided by the sender parameter. BackgroundWorker objBackgroundWorker = sender as BackgroundWorker; try { mSerialPort = new SerialPort(GetPortName(mPortName), DefaultBaudRate, Parity.Even, 7, StopBits.Two); mSerialPort.Open(); objBackgroundWorker.ReportProgress(0); while (objBackgroundWorker.CancellationPending == false) { if (IOScanner(objBackgroundWorker, false) == true) { ScannerStationData(); IsReady = true; IsError = false; } else { IsReady = false; IsError = true; } Thread.Sleep(1); } // Performs last scan before thread closing if (objBackgroundWorker.CancellationPending == true) { IOScanner(objBackgroundWorker, true); } mSerialPort.Close(); mSerialPort = null; e.Result = null; } catch (Exception objErr) { string sMessage = string.Format("PlcService.ThreadEngine_DoWork Err={0}", objErr.Message); mLogSysService.AddItem(sMessage); IsError = true; } }

El método IOScanner llama a otros métodos para comunicarse como el siguiente.

protected bool WriteDMWord(int iAddress, int[] aryValues) { bool bRetValue = true; try { mSerialPort.NewLine = "/r"; mSerialPort.ReadTimeout = DefaultTimeout; string sTxData = HostLinkProtocol.BuildWriteDMWord(iAddress, aryValues); mSerialPort.WriteLine(sTxData); string sRxData = string.Empty; sRxData = mSerialPort.ReadLine(); if (HostLinkProtocol.ParseWriteDMWord(sRxData) == true) { bRetValue = true; } } catch (Exception objErr) { Console.WriteLine("WriteDMWord [{0}]", objErr.Message); bRetValue = false; } return bRetValue; }