none
Recibir por la línea serie. Va lento. RRS feed

  • Pregunta

  • Hola:

     

    Tengo mi ordenador conectado a un dispositivo que me envía por la línea serie una cadena de caracteres cada décima de segundo. El problema que me encuentro es que mi programa, que funciona con un thread, recibe esos datos aproximadamente con medio segundo de retraso.

     

    Pienso que estoy haciendo algo mal pero no sé qué puede ser. Llevo varios días dándole vueltas y no sé qué es lo que pasa. El programa creo que recibe todos los datos y los interpreta a una buena velocidad. No sé si es que se queda esperando a recibir algo concreto o qué es lo que le ocurre. Las cadenas que tengo que recibir tienen un principio y un final determinado como debe ser, pero he observado que cuando se dispara el evento de leer, lee más de una cadena cada vez, o quizá una cadena y media. Las cadenas son de longitud variable.

     

    ¿Sabéis por dónde puedo estudiar este tema?

     

    Gracias.

    sábado, 11 de octubre de 2008 11:50

Respuestas

  • Ese retardo es normal, como también es normal que recibas las tramas a pedazos... ¿Evento de leer? ¿CreateFile con OVERLAPPED? Otra opción es que leas "a mano". Como ya estás en un hilo no es casi problema que éste se quede enganchado en un ReadFile.

     

    sábado, 11 de octubre de 2008 14:05
    Moderador
  • Pues no veo nada raro en tu código... aunque no es una forma muy habitual de leer un puerto serie, ya que estás mezclando el modo "overlapped" de forma un poco extraña... y creo que incorrecta.

     

    Con que es normal me refiero a que en Windows hay un montón de capas por encima de la UART física y que ese retardo es casi aceptable dentro de los tiempos de Windows.

     

    Con "leer a mano" me refiero a que no uses los OVERLAPPED, sino que abras el puerto y leas con ReadFile de forma síncrona. Es decir, tu hilo será el que abra el puerto y luego entre en bucle para ir leyendo con ReadFile mientras haya bytes en el puerto. De este modo los retardos serán mínimos...

     

    Para abrir el puerto serie: http://msdn.microsoft.com/en-us/library/aa363201(VS.85).aspx

    Para leer es igual que si leyeres desde un fichero, la única diferencia es que debes ajustar los timeouts con SteCommTimeouts http://msdn.microsoft.com/en-us/library/aa363437(VS.85).aspx

     

    IMPORTANTE: Veo que estás usando CreateThread. Eso es muy peligroso y puede terminar en serias fugas de memoria si utilizas en el programa alguna llamada al API de C estándar. El hilo lo debes crear con _beginthreadex. Aquí lo tienes explicado (casi al final del todo): http://msdn.microsoft.com/en-us/library/ms682453.aspx

     

     

    sábado, 11 de octubre de 2008 16:20
    Moderador

Todas las respuestas

  • Ese retardo es normal, como también es normal que recibas las tramas a pedazos... ¿Evento de leer? ¿CreateFile con OVERLAPPED? Otra opción es que leas "a mano". Como ya estás en un hilo no es casi problema que éste se quede enganchado en un ReadFile.

     

    sábado, 11 de octubre de 2008 14:05
    Moderador
  • Muchas gracias por la respuesta. El create file es:

     

    Code Snippet

    CreateFile(szPorts[theApp.comInfo.bPort],

    GENERIC_READ | GENERIC_WRITE,

    0,

    0,

    OPEN_EXISTING,

    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,

    0);

     

     

     

    Y el thread:

     

    Code Snippet

    if (NULL == (hCommWatchThread =

    CreateThread( (LPSECURITY_ATTRIBUTES) NULL,

    0,

    (LPTHREAD_START_ROUTINE) CommWatchProc(NULL),

    0,0, &dwThreadID )))

     

     

     

    Y el proceso:

     

    Code Snippet

    DWORD FAR PASCAL CommWatchProc( LPSTR lpData )

    {

    DWORD dwEvtMask ;

    NPINFOCOM npTTYInfo = (NPINFOCOM) lpData ;

    OVERLAPPED os ;

    int nLength ;

    BYTE abIn[ MAXBLOCK + 1];

    extern CDeportesEquipoApp theApp;

    memset( &os, 0, sizeof( OVERLAPPED ) ) ;

    // create I/O event used for overlapped read

    os.hEvent = CreateEvent( NULL, // no security

    TRUE, // explicit reset req

    FALSE, // initial event reset

    NULL ) ; // no name

    if (os.hEvent == NULL)

    {

    // MessageBox( NULL, "Failed to create event for thread!", "TTY Error!",

    // MB_ICONEXCLAMATION | MB_OK ) ;

    return ( FALSE ) ;

    }

    if (!SetCommMask( theApp.comInfo.hComPort, EV_RXCHAR ))

    return ( FALSE ) ;

    while ( theApp.m_conectado )

    {

    dwEvtMask = 0 ;

    WaitCommEvent( theApp.comInfo.hComPort,&dwEvtMask, NULL );

    if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR)

    {

    do

    {

    if (nLength = ReadCommBlock( (LPSTR) abIn, MAXBLOCK ))

    {

    abIn[nLength]='\0'; //terminamos la cadena

     theApp.comInfo.entrada=abIn;

    }

    while ( nLength > 0 ) ;

    }

    }

    // get rid of event handle

    CloseHandle( os.hEvent ) ;

    // clear information in structure (kind of a "we're done flag")

    theApp.comInfo.dwThreadID = 0 ;

    theApp.comInfo.hWatchThread = NULL ;

    return( TRUE ) ;

    } // end of CommWatchProc()

     

     

     

    ¿Qué es lo me quieres decir con leer a mano? La verdad es que ese retraso de medio segundo me parece demasiado, cuando yo necesito tener los datos a la décima. Creo que no sería aceptable un retraso de más de una o dos décimas.

     

    sábado, 11 de octubre de 2008 15:54
  • Pues no veo nada raro en tu código... aunque no es una forma muy habitual de leer un puerto serie, ya que estás mezclando el modo "overlapped" de forma un poco extraña... y creo que incorrecta.

     

    Con que es normal me refiero a que en Windows hay un montón de capas por encima de la UART física y que ese retardo es casi aceptable dentro de los tiempos de Windows.

     

    Con "leer a mano" me refiero a que no uses los OVERLAPPED, sino que abras el puerto y leas con ReadFile de forma síncrona. Es decir, tu hilo será el que abra el puerto y luego entre en bucle para ir leyendo con ReadFile mientras haya bytes en el puerto. De este modo los retardos serán mínimos...

     

    Para abrir el puerto serie: http://msdn.microsoft.com/en-us/library/aa363201(VS.85).aspx

    Para leer es igual que si leyeres desde un fichero, la única diferencia es que debes ajustar los timeouts con SteCommTimeouts http://msdn.microsoft.com/en-us/library/aa363437(VS.85).aspx

     

    IMPORTANTE: Veo que estás usando CreateThread. Eso es muy peligroso y puede terminar en serias fugas de memoria si utilizas en el programa alguna llamada al API de C estándar. El hilo lo debes crear con _beginthreadex. Aquí lo tienes explicado (casi al final del todo): http://msdn.microsoft.com/en-us/library/ms682453.aspx

     

     

    sábado, 11 de octubre de 2008 16:20
    Moderador
  • Bueno, pues muchas gracias de nuevo. Creo que este trozo de código lo cogí de algún foro de estos hace tiempo y llevo tiempo usándolo en otras aplicaciones que no son tan críticas en tiempo y me funciona bien.

     

    Voy a leer toda la documentación que me envías y a estudiarlo despacio, a ver si consigo resolverlo. Ya llevo días pensando en intentar leer de forma síncrona, pero la verdad es que me da un poco de pereza intentarlo. En cualquier caso voy a estudiar todo esto y ya te contaré.

     

    Muchas gracias por tu interés.

     

    sábado, 11 de octubre de 2008 16:33
  • Hola:

    Puedes descargar el manual en pdf sobre VC++ y  puerto serie.
    Saludo.

    http://electronica-pic.blogspot.com
    martes, 26 de mayo de 2009 21:48