none
Problema con lectura de datos de puerto serie RRS feed

  • Pregunta

  •  

    Hola, estoy empezando y utilizo Visual Studio 2005 en lenguaje Basic, estoy realizando un proyecto Smart Device para PDA, para leer datos del puerto serial provenientes de un bus RS485 y por mas que busco informacion no consigo hacerlo andar bien.

    Necesito representar en un textbox los datos recibidos, los cuales son trasmitidos espontaneamente y cuyas cadenas son de distintas longitudes, en este caso intento recibir a modo de prueba una  la trama fija"7B010100" y consigo mostrarla en el textbox pero byte a byte , primero me saca 7B1 y despues 10 y necesitaria obtener de golpe la cadena entera en el textbox para despues poder compararla , os agraceceria alguna ayuda al respecto estoy usando el siguente codigo:

    Delegate Sub WriteDataDelegate(ByVal str As String)

    Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived

    Dim strData As String = SerialPort1.ReadByte

    Dim WriteInvoke As New WriteDataDelegate(AddressOf Me.WriteData)

    Me.Invoke(WriteInvoke, strData)

    End Sub

     

    Private Sub WriteData(ByVal str As String)

    TextBox1.Text = TextBox1.Text & Hex(str)

    End Sub

    Gracias.

    lunes, 11 de diciembre de 2006 18:13

Todas las respuestas

  • La respuesta es simple. Estas utilizando el evento 'DataReceived', por tanto esta dispara cuando finaliza la recepcion del primer byte completo, para avisarte de que se han recibido datos. En transmissiones asincronas, ademas de conocer cuando se recibien datos, necesitamos saber cuando finaliza dicha recepcion, pues necesitamos componer nuestros datos a modo de trama con indicadores de 'inicio' 'datos' y 'final'. En algunos casos podemos omitir el 'inicio' sin embargo poco podremos hacer si no identificamos un final.

    En muchas aplicaciones el caracter 13 o 'Cr' indica que ha finalizado la trama, pero en tu caso no observo ningun caracter especial indicador de 'Final'... ya que el '0' se repite en diversas ocasiones. Puedes optar por dos soluciones :

    1) Utilizar un indicador... como por ejemplo el caracter 13 o Cr

        Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived

            Static strData As String = ""

            strData += SerialPort1.ReadExisting()

            If strData.IndexOf(Chr(13)) > 0 Then

                Dim WriteInvoke As New WriteDataDelegate(AddressOf Me.WriteData)

                Me.Invoke(WriteInvoke, strData)

            End If

        End Sub

    2) Leer tramas por longitud fija, no recomendada pues al peder la sincronia en un caracter, nunca seremos capaces de componer una trama completa.

        Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived

            Static strData As String = ""

            strData += SerialPort1.ReadExisting()

            If strData.lenght = 8 Then

                Dim WriteInvoke As New WriteDataDelegate(AddressOf Me.WriteData)

                Me.Invoke(WriteInvoke, strData)

            End If

        End Sub

     

    3) Tambien dispones de instrucciones como 'ReadLine', pero tienen el inconveniente de no finalizar su funcion de lectura hasta que reciben un Char(13).

     

    Lo mejor en estos casos es montar un buffer circular, donde se van añadiendo los caracteres recibidos y tu aplicacion comprueba en busca de tramas completas, ello evita muchos problemas.

    No dudes en contactar de nuevo para cualquier aclaracion.
    Pep Lluis,

     

    martes, 12 de diciembre de 2006 9:18
    Moderador
  • Hola PepLluis , yo tambien empiezo con el puerto serie; lo q pasa es q me gusto tu idea de hacer un buffer circular, pero no se como hacerlo, tengo la idea de hacer un while, yo tengo q leer en bytes, mi inicio es un hexadecimal 01........y 3F mi final, y tambien lo muestro en un textobox por medio de un delegado, podrias ayudarme!! de antemano gracias.
    jueves, 11 de enero de 2007 15:23
  • Hola Pablo,
    Estoy de viaje... en cuanto vuelva a casa te pongo un sencillo ejemplo.
    viernes, 12 de enero de 2007 15:17
    Moderador
  • Hola PepLluis; creo q me servira mucho tu ejemplo; muchas gracias,

    lo espero impacientemente,, jijij....

    gracias

    viernes, 12 de enero de 2007 19:20
  • bueno Pablo... nunca es tarde si la dicha es buena!

    Podrias intentar con este codigo, pero no deja de ser una idea, si necesitas una solucion concreta, deberias especificar exactamente el contexto.

    Dim Datos As String
    '
    'Disparo por datos recibidos
    Private Sub DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived

        If Me.SerialPort1.BytesToRead > 1 Then     'Esperamos leer al menos 1 byte

            Datos += Me.SerialPort1.ReadExisting   'Leer (y crear buffer)

            '

            'Verificar fin de trama... termina con un '3F'?

            'La longitud de la trama es de 18 Caracteres... por ejemplo

            Do

                If Asc(Datos.Substring(17, 1)) = &H3F Then

                    ProcesarDatos() 'Comprobar que la primera posicion es un '01'

                Else

                    'trama incorrecta, descartar esta parte de la trama

                    'remover todos los caracters hasta el primer '3F'

                    If Datos.IndexOf(&H3F) > 0 Then

                        Datos.Remove(0, Datos.IndexOf(&H3F))

                    End If

                End If

            Loop Until Datos.Length < 18

        End If

    End Sub

    Saludos,
    Pep Lluis,

    martes, 16 de enero de 2007 8:01
    Moderador
  • Hola PepLLuis, soy nuevo en esto (nunca habia programado en visual basic y estoy un poco perdido con los tipos de datos) y estoy haciendo un proyecto para monitorizar los datos de un Gps trimble que envia una cadena por el com1 con conexion Rs232 y hacer un comparativa con otro gps, el problema es que no se como recibir esa cadena y mostrarla en un textbox, ya que se supone que manda datos en hexadecimal y lo que he probado de momento hace que me aparezcan simbolos raros. Adjunto mi programa.

    Private Sub Form_Load()
      txtDisplay.Text = "" 'Habilita Port
      MSComm1.PortOpen = True 'Abre port
      MSComm1.Output = "0" + Chr(13)  'Configura Port Como entrada
    End Sub

    Private Sub tmrTimer_Timer()
      txtDisplay.Text = txtDisplay.Text + Chr(13) + MSComm1.Input
    End Sub

    Gracias y saludos.

    miércoles, 17 de enero de 2007 11:57
  • Gracias PepLluis , me sirvio mucho tu codigo; me fue de gran ayuda; solo q cuando recibo los bytes en el evento DataRecived del SerialPort1; a veces estos bytes me llegan completos otras no; solucione este problema con tu idea de un bucle; solo q este bucle lo hice infinito, es decir, un while (true) y todo mi codigo para almacenar esos bytes y desplegarlos en en textbox1; pormedio del delegado; mi pregunta es ¿existe alguna otra manera para recibir esta trama completa desde mi inicio H10.......H3F;  de 19 elementos de longuitd; a veces me llegan H10....3F; de por decir 15 elementos de longuitud; y esto si lo soluciono con el bucle while; pero no lo quiero hacer infinito? espero haberme explicado bien y me puedas ayudar.

    Gracias; en realidad puedo decirte q m emociono mucho tu ayuda por q en ningun otro foro me habian ayudado,

    Gracias.

    miércoles, 17 de enero de 2007 17:31
  • German, es muy parecido a lo q o estoy hacieno, solo q veo q utilizas vb6, por q no elegir net? VB2005, como apenas estas aprendiendo VB podria ser mas facil para ti; ya q este trae una clase mucho mas eficaz para comunicarte al RS232, con VB vas a batallar un poquito mas; si trabajas con bytes, al recibir, podras mostrarlos en hexadecimal con un &H, lo q pasa es q recibes caracteres raros por q trabajas con caracter y los simbolos q no sean equivalentes a hexadecimal los mostrara con un caracter raro.

    Espero haberte dado una idea mejor para analizar tu problema, ya q no te lo resolvi.

     

    miércoles, 17 de enero de 2007 17:39
  • Pablo,

    Me complace saber que te hemos podido ayudar. Te pido un poco mas de paciencia, en cuanto tenga un ratito me pongo a desarrollar un ejemplo para recibir tramas de longitud variable y que finalizen con el byte &h3F.
    Saludos,

     

    miércoles, 17 de enero de 2007 18:02
    Moderador
  • En principio si estas utilizando VB6 i el control ocx MSCOMM32, deberias observar lo siguiente, si es que no recuerdo mal:

    MSComm1.RThreshold = 1
    MSComm1.Settings = "9600,E,7,2" .. Deberias ajustar la especificacion de velocidad,paridad etc de tu GPS (2400/4800..etc)
    MSComm1.PortOpen = True

    Luego debes recibir los caracteres en un string... (Dim Recibidos as String), y antes de asignarlos al textbox, recorrer uno a uno la cadena y convertir sus valores con las funciones Asc y Chr.

    Tengo este tema un poco olvidado, pero si necesitas mas ayuda tanto a ti como a Pablo os recomiendo crear un hilo nuevo para cada tema, pues de otra forma se hace impracticable.
    No dudes en crear un nuevo hilo dirigido a mi, Con el tema : Pregunta Sobre el Puerto Serie para PepLluis., en cuanto la vea estare encantado de contestaros.

    Saludos,
    Pep Lluis,

    miércoles, 17 de enero de 2007 18:26
    Moderador
  • Muchas gracias por la ayuda PepLluis, seguire haciendo pruebas y en cunato saque algo en claro te lo comento.

    Respcto a lo que me comentas de la version de visual basic, es que es para mi proyecto fin de carrera y me piden que lo haga con vb6, asi que no tengo otra opcion.

    Saludos y gracias de nuevo.

    miércoles, 17 de enero de 2007 23:04
  • Hola PepLluis, estoy haciendo algunas pruebas con el codigo que me mandaste, solo que vuelvo a recibir los bytes por el puerto serial, solo que al desplegarlos en el textbos, me aparecen carateres raros; esto lo hace cuando trabajo con el string, yo trabaje recibiendo bytes y si aparecen en el textbox, mi pregunta es, como los podre manejar esas tramas de bytes para hacer mi busqueda para retirarlas del buffer, desde el 01 al 3f; espero me puedas ayudar.

    De antemano Gracias

    martes, 23 de enero de 2007 15:47
  • Pablo,

    La idea para retirar tramas completas es desechar todo lo que no este incluido entre el 01 y 3F... no te preocupes ya veras como lo conseguimos, Si eres tan amable mandame el fragmento de codigo que estas trabajando e intento montar el ejemplo que te he prometido a partir de este.

    Gracias,
    Pep Lluis,

     

    martes, 23 de enero de 2007 17:44
    Moderador
  •  

    Gracias PepLuis,  cree otro tema en el foro de C#, por que intento programarlo en c#, solo que no hbia encontrado informacion a cerca del puerto serie e intento pasarlo de vb a c#, por lo q mejor pase al foro de c#, espero no te molestes. Ahi lo explico mejor.

    Gracias por tu ayuda, me sirve de mucho.

    martes, 23 de enero de 2007 18:47
  • Hola, muy bueno el codigo. Ahora que es el      ProcesarDatos()
    te agradeceria si podes responder a la brevedad,ya que estoy en un apuro

    MUCHISIMAS GRACIAS!
    lunes, 10 de noviembre de 2008 13:47