Considerando interesante la pregunta y con el permiso de Cream, me gustaría compartir esta pequeña cuestión en tanto a la metodología en la recepción de datos usando el IO.Ports.
La pregunta:
“no siempre recibo bien los datos o no los capturo por el puerto serie”.. el código que estoy usando actualmente es el siguiente :
puertoSerie.write(«R») ‘enviamos carácter
dato=Asc(puertoSerie.ReadExisting.Chars(1)) ‘leemos y cogemos valor de x
Una de las características de las comunicaciones serie en uno de sus modos, es que son asíncronas… lo que significa que los ‘Bytes’ se serializan y transmiten sin que el receptor conozca el momento preciso. Es decir el bit de ‘start’ indica al receptor el envío de un ‘byte’ pero en ningún caso y por ausencia de protocolo conocemos de antemano la cantidad de ‘bytes’ que vamos a recibir asi como el intervalo de tiempo que va a transcurrir en la transmision entre byte’s.
Como tu bien dices y expresas en tus razonamientos, estas ejecutando la lectura directamente sin esperar al evento de ‘Data Received’, es presumible que en la rapidez de proceso del PC nos dispare la excepción de “index out of range exception” pues estas intentando procesar la posición del segundo carácter que evidentemente aun no has recibido y por lo tanto es inexistente.
El mandato ReadExisting, lee los bytes recibidos que actualmente permanecen en el buffer, en tu caso y en ocasiones, dependiendo del flujo de ejecución, en el buffer debes tener por leer, 0, quizas 1 o cuando te funciona bien2 bytes.
La práctica correcta es formalizar el intercambio de tramas delimitándolas con un carácter de inicio y otro de fin… por ejemplo la mayoría implementan el CR o Chr(13) como fin de trama, algunos fabricantes optan por utilizar como fin de trama secuencias tales como 2 bytes de FCS + Un Carácter identificativo + LF + CR, en fin como siempre hay para todos los gustos. Al menos con este método podrás estar seguro de que la transmisión a finalizado correctamente.
Deberías implementar el disparo de recepción y procesar los datos una vez se ha completado la recepción. En todo caso otra opción podría ser algo parecido a:
‘String de recepción utilizado como buffer
Private PortSerie_Recepcion As String = «»
‘Anadir el manipulador de recepción en la sub New, Load…
AddHandler Serie.DataReceived, AddressOf Rx
Sub Rx(ByVal sender As Object, _
ByVal e As serialDataReceivedEventArgs)
Try
‘Añadir la recepción actual al buffer
PortSerie_Recepcion += Serie.ReadExisting
If PortSerie_Recepcion.Contains(Chr(13)) Then
….PROCESAR LA INFORMACION
PortSerie_Recepcion = «»
End If
Catch ex As Exception
‘En caso de excepción
End Try
End Sub
Si la longitud de tus tramas es de 2 bytes… una idea muy básica puede ser controlar el número de caracteres que están en el buffer pendientes de ser leídos y antes de procesarlos con: PuertoSerie.BytesToRead
‘ Prohibido definitivamente
‘
If PuertoSerie.BytesToRead = 2 Then
dato = Asc(PuertoSerie.ReadExisting.Chars(1))
End If
‘ Definitivamente NO ES RECOMENDABLE!
‘
If PuertoSerie.BytesToRead > 2 Then
dato = Asc(PuertoSerie.ReadExisting.Chars(1))
End If
El problema utilizando el primer caso es que nunca se procesara el dato si no se reciben exactamente dos caracteres, por ende y peor aún si BytesToRead es > 2 nunca procesara los bytes recibidos, poniendo en apuros a nuestra aplicación cuando él se desborde el buffer de recepción. En segundo caso y en determinadas situaciones de intercambios muy rápidos o con interferencias podria perder la secuencia lecturas de pares de bytes y procesar inadecuadamente por desplazamiento de posiciones… como mal menor necesitarías usar PuertoSerie.BytesToRead > 2 conjuntamente con PuertoSerie.Read(Dato(),0,2), aunque insisto lo mejor es incluir un fin de trama en cada transmisión desde el firmware del dispositivo.
‘ una propuesta… Quizas
‘
Dim Trama() As Char
If PuertoSerie.BytesToRead > 2 Then
PuertoSerie.Read(Trama, 0, 2)
dato = Asc(Trama(1))
End If
Saludos,
Pep Lluis,