none
Cambiar configuracion puerto serie en tiempo real

    Question

  • Hola a todos

    Estoy desarrollando una aplicacion con Visual C++ 2008, con Windows Forms. La aplicacion tiene una serie de ventanas, donde aparecen una serie de checkbox para comprobar el estado de una serie de entradas y salidas. Esta comprobacion se hace mediante el envio de comandos por puerto serie, que llegan al controlador y este me devuelve el valor de las entradas y salidas.

    El problema que tengo, es que debo de tener una ventana donde poder configurar los parametros del puerto serie a mi antojo. Inicialmente, tengo una velocidad en baudios de 19200, 8 bits de datos, sin paridad y 1 bit de stop. La pregunta que formulo aqui es la siguiente:

    Supongamos que estoy refrescando las ventanas de mi aplicacion con una determinada configuracion de puerto serie, y en un momento determinado quiero cambiar los parametros del puerto serie, ¿podria seguir monitorizando con la nueva configuracion, o tendria que dejar de monitorizar? Yo actualmente, tengo un .h dentro del proyecto, con el valor inicial de los parametros del puerto serie, cuando hago algun cambio en ellos (en la ventana desarrollada para ello), se actualizan sus valores en ese .h. Pero lo que no se es como y cuando puede coger el puerto serie esta nueva configuracion.

    La solucion sencilla, es cambiar los valores del .h segun quiera una configuracion u otra, pero lo que quiero es que la configuracion se pueda cambiar en tiempo real.

    Agradeceria mucho vuestra ayuda.

    Un saludo

    Wednesday, November 10, 2010 1:21 PM

All replies

  • Buenas tardes,

    Si puedes hacer estos cambios. En funcion de como estés haciendo la implementacion del puerto serie, se deben realizar de una manera o de otra.

    Por ejemplo, si usas el componente SerialPort, es muy sencillo realizar los cambios ya que contiene todos los metodos necesarios para realizar dicha operacion. Lo unico que debes tener en cuenta es que hay que cerrar el puerto, realizar los cambios de la modificacion y abrir el puerto posteriormente.

    Por otro lado si usas las Api de windows (CreateFile, ReadFile y WriteFile), lo suyo es crear una estructura con la configuracion del puerto.

    Puedes ver informacion del uso de las api aqui: http://articulos.conclase.net/serie/

    Saludos.

    Wednesday, November 10, 2010 4:20 PM
  • La implementacion del puerto serie la hago con un componente SerialPort, y por supuesto se que tiene todos los metodos necesarios para cambiar la configuracion.

    Entonces, por tu respuesta entiendo que para cambiar la configuracion de los parametros del puerto serie es necesario cerrar el puerto. Sin embargo, en mi aplicacion el puerto serie se abre en cuanto iniciamos el programa, y se cierra solo cuando salimos. ¿Quiere decir esto que con mi implementacion es imposible cambiar los parametros del puerto serie en tiempo real?

    Yo habia pensado en utilizar un timer que cada cierto tiempo fuera comprobando los parametros del puerto serie situados en el .h y actualizar la configuracion, pero sin cerrar el puerto...

    Gracias

    Un saludo

    Thursday, November 11, 2010 9:54 AM
  • Buenas de nuevo,

    No se puede, hay que cerrar el puerto antes de hacer cualquier cambio en la configuracion. Es como cuando abres un archivo en modo lectura y despues quieres escribir en el, tienes que cerrarlo y abrirlo en modo escritura o lectura+escritura. Mientras tengas el puerto abierto, estará ocupado y no podrás realizar los cambios.

    Puedes hacer un timer, cerrar el puerto, establecer la configuracion y abrir el puerto rápidamente, no le llevará mucho, haz pruebas quizas ni lo note la aplicacion...

    Nota un hilo es mucho mas rapido que un timer.tick = 1;

    igual puedes ahorrarte mas ms con el cambio de la configuracion y hacer que este efecto se vea disminuido al maximo posible.

    Saludos

    Thursday, November 11, 2010 11:12 AM
  • Efectivamente, tal y como te comenta jnavero tienes que cerrar el puerto sí o sí a la hora de cambiar la velocidad. No es un problema de .NET, sino que el chip del puerto serie necesita parar para cambiar los registros que los configuran, y volver a arrancar.

    Por supuesto, mientras el puerto esté cerrado, si recibes algo, lo perderás.

    Además, si accedes al puerto desde algún thread aparte del principal tendrás que sincronizar el acceso antes de hacer la operación o algún hilo reventará cuando cierres el puerto (o reventará el hilo en el que estés intentando cerrar)...


    MVP Visual C++ - Visita mi blog sobre desarrollo: http://geeks.ms/blogs/rfog/
    Thursday, November 11, 2010 7:26 PM
  • Hola Marodal,

    Realmente no quiero llevar la contraria a nadie :-), pero creo recordar que utilizando el SerialPort de System.IO.Ports no era necesario 'abrir' y 'cerrar', simplemente podias cambiarlo al vuelo. Aunque sinceramente, no es demasiado coherente, pues representa que la comunicacion entre DTE y DCE debe fijarse con unas condiciones predeterminadas para ambos.

    La explicacion seria que con las llamadas al 'Kernel32' efectivamente tal como mencionan mis compañeros, debe ser necesario forzar el 'Open' 'Close', pero ya te digo si la memoria no me falla realice un laboratorio con el System.IO.Ports.Serieal donde precisamente se demostraba.

    Aqui tienes un enlace... y si la cosa se complica puedo volver a verificar que es asi, de esa forma si me equivoco podre pediros disculpas, jajajaja.

    http://msmvps.com/blogs/peplluis/archive/2009/11/10/se-puede-cambiar-la-velocidad-del-puerto-serie.aspx

    Saludos a todos,
    Pep Lluis,


    MVP - Visual Developer
    Saturday, November 13, 2010 8:24 AM
  • Pep, qué tal.
     
    Yo te aseguro sobre la Biblia de las UARTS que para cambiar de velocidad   
    no sólo hay que cerrar el puerto, sino vaciar el buffer y resetear  varios  
    registros a no ser que quieras una excepción hardware en el peor de  los  
    casos o un error de trama nada más abrir con la nueva velocidad...
     
    Lo cierto y verdad es que hace como veintipico años que no "toco" u na uart  
    de PC, pero sí la de otros muchos procesadores y todos funcionan m� �s o  
    menos igual. En algunos el cerrar y abrir supone que haga todo lo dem� �s  
    automáticamente, pero en otros no.
     
    Ahora imagina la situación siguiente: estás a medio recibir un  byte. En  
    este momento el registro de desplazamiento que está acumulando los  bits  
    tiene el bit de start, y 3 bits más y está entrando el cuarto.  Cambias los  
    registros de la velocidad "a pelo". Eso significa cambiar la base de  
    tiempos sobre la cual se realiza la comparación del "cortador" de b its. Es  
    decir, al cambiar la velocidad, el cortador tomará en otro instante   
    diferente lo que debía haber tomado antes o después. Con un po co de  
    suerte, recibirá el "mismo" 1 ó 0... pero fuera de tiempo. Ent re medias se  
    le habrán escapado otros unos y ceros (o nada si lo que hemos hecho  ha  
    sido bajar la velocidad), con lo que ya no estás recibiendo lo que  quieres.
     
    Con suerte recibirás bytes basura. Para la UART todo tendrá se ntido (sobre  
    todo si no hay paridad), con algún que otro "frame error" cuando se  reciba  
    un cero como bit de start (si lo hay)... que por cierto es lo que pasa  
    cuando pones un puerto serie a diferente velocidad de la que deberí as:  
    recibes basura.
     
    Por lo tanto, en el hipotético caso de que se permitiera, deben est ar  
    pasando una de DOS o las DOS a la vez:
     
    A) El .NET (o el Kelmer de Windows) automáticamente cierra y abre l a UART  
    ante un cambio de velocidad.
    B) Se puede realizar el cambio automáticamente sin abrir/cerrar (co sa que  
    seriamente dudo)... y en el peor de los casos tienes una BSOD y en el  
    mejor recibes basura.
     
    [No obstante, se me ocurre un muy poderoso sistema de seguridad con fluj o  
    de datos variable, en el que la seguridad no está en qué se en vía, sino  
    también a qué velocidad, pero dado el grado de exactitud neces ario para  
    los cambios de tiempos, en un PC, con la capa HAL, el Kernel, y luego el   
    .NET lo veo completamente inviable...]
     On Sat, 13 Nov 2010 09:24:28 +0100, <PepLluis> wrote:
     
    > Hola Marodal,
    >
    > Realmente no quiero llevar la contraria a nadie :-), pero creo recorda r  
    > que
    > utilizando el SerialPort de System.IO.Ports no era necesario 'abrir' y   
    > 'cerrar',
    > simplemente podias cambiarlo al vuelo. Aunque sinceramente, no es  
    > demasiado
    > coherente, pues representa que la comunicacion entre DTE y DCE debe  
    > fijarse con
    > unas condiciones predeterminadas para ambos.
    >
    > La explicacion seria que con las llamadas al 'Kernel32' efectivamente   
    > tal como
    > mencionan mis compañeros, debe ser necesario forzar el 'Open' 'Cl ose',  
    > pero ya
    > te digo si la memoria no me falla realice un laboratorio con el  
    > System.IO.Ports.Serieal
    > donde precisamente se demostraba.
    >
    > Aqui tienes un enlace... y si la cosa se complica puedo volver a  
    > verificar que
    > es asi, de esa forma si me equivoco podre pediros disculpas, jajajaja.
    >
    >
    > Saludos a todos,
    > Pep Lluis,
    >
    > MVP - Visual Developer
     -- 
    Microsoft Visual C++ MVP => http://geeks.ms/blogs/rfog
    ======================== =============== Llegará un día que nuestros recuerdos serán nuestra rique za.
     -- Paul Geraldy. (1855-1954) Escritor francés.
     

    MVP Visual C++ - Visita mi blog sobre desarrollo: http://geeks.ms/blogs/rfog/
    Saturday, November 13, 2010 9:46 AM
  • RFOG Sabía yo que la conversación se alargaría J,

    Creo recordar en una prueba realizada entre un DCE y un DTE, me permitió cambiar las velocidades al vuelo y siempre previo cambio  de velocidad antes de enviar. Por eso estoy matizando que no se trata de un acceso a través del Kernel y la estructura DCB, ni de un TSR controlando la interrupción de la UART mapeada al 03F8, si no de System.IO.Ports.SerialPort por lo tanto debo suponer que la capa del espacio de nombres realiza de una forma automatizada y por debajo las llamadas al ‘Close’ y ‘Open’ cada vez que realizas un cambio en la configuración del mismo. Lo que es seguro es que puedes realizarlo sin que pete nada.

    En cuanto pueda vuelvo a probarlo y os doy el código y los resultados.
    Saludos,
    Pep Lluis,


    MVP - Visual Developer
    Saturday, November 13, 2010 10:50 PM
  • Buenas,

    A mi tambien me interesa el tema, pero ahora mismo no puedo hacer pruebas. para probar se podría enviar una tanda de x bytes al puerto e intentar cambiar la velocidad al vuelo como dices. pero, si es asi, por fuerza el componente serialport debe abrir y cerrar el puerto osea se perderán datos en vez de provocar una excepcion.

    Otra cosa que puede suceder, es que puedas "cambiar la velocidad" pero, que no tenga efecto hasta que no cierres y abras el puerto a mano. Es logico pesar que use una estructura (Metodos) de lectura y escritura que se los pase al puerto al hacer open y por mucho que cambie los valores hasta no volver a hacer el open no se tendrán en cuenta.

    Esto son suposiciones. Quedo a la espera de las pruebas.

    Saludos.

    Sunday, November 14, 2010 3:08 AM
  • Hola, ante todo gracias por contestar y por el interes mostrado.

    Para mi el problema seria que saltara una excepcion si intento cambiar la velocidad del puerto serie al vuelo. Rfog, si hay error en la trama siguiente al cambio de velocidad, el algoritmo que tengo implementado la detectaria y descartaria esa trama, por lo que la perdida en el rendimiento de la aplicacion tampoco serian excesivas, no?

    Si esto del cambio de parametros al vuelo no se pudiese hacer...como lo conseguiria en mi aplicacion? Recuerden que el puerto serie de mi aplicacion debe estar siempre abierto, desde el momento en el que se lanza, puesto que produce una comunicacion continua entre mi aplicacion y un plc mediante puerto serie. Lo de cerrar el puerto serie antes de cambiar los parametros supondria que tuviese que cerrar cualquier comunicacion que se estuviese produciendo en ese momento, puesto que si no se produciria la excepcion, que es lo que estoy intentando evitar a toda costa.

    Muchas gracias

    SAludos

     

    Tuesday, November 16, 2010 8:49 AM
  • Hola Marodal,

    Tal y como intento explicar, los recuerdos que tengo sobre un laboratorio que realice entre un DTE y un DCE me permitian cambiar la velocidad al vuelo, utilizando el SerialPort de System.IO.Ports sin recibir excepcion alguna. Ademas no veo porque deberia saltar una excepcion. Presumiblemente cuando interactuas a traves del SerialPort, es el mismo el que se encarga de realizar las operaciones en el orden adecuado para preservar estados.

    Aqui tienes el ejemplo para probar directamente, este ejemplo te enviara una trama a una velocidad diferente cada vez que invoques el sub... o sea a 19200, la siguiente a 9600, 4800..etc.

    '..     Dim MiPuerto As New System.IO.Ports.SerialPort
    '..     MiPuerto = My.Computer.Ports.OpenSerialPort("COM1")
    … Sub EnviarTrama …
            Select Case MiPuerto.BaudRate
                Case 19200
                    MiPuerto.BaudRate = 9600
                Case 9600
                    MiPuerto.BaudRate = 4800
                Case 9600
                    MiPuerto.BaudRate = 2400
                Case Else
                    MiPuerto.BaudRate = 19200
            End Select
            MiPuerto.WriteLine("Hola... enviando a :" + MiPuerto.BaudRate.ToString)


    MVP - Visual Developer
    Tuesday, November 16, 2010 9:10 AM
  • Pep, ¿Pasará lo mismo si en ese momento otro hilo está in tentando enviar o
    recibiendo algo?
     
    Es decir, independientemente de que .NET o Windows hagan el
    cierre/apertura, ¿qué pasa cuando otro hilo está en el aj o? ¿Lo has
    probado? Yo creo que el tema está aquí.
     
    On Tue, 16 Nov 2010 10:10:40 +0100, <PepLluis> wrote:
     
    > Hola Marodal,
    >
    > Tal y como intento explicar, los recuerdos que tengo sobre un  
    > laboratorio que
    > realice entre un DTE y un DCE me permitian cambiar la velocidad al vue lo,
    > utilizando el SerialPort de System.IO.Ports sin recibir excepcion  
    > alguna. Ademas
    > no veo porque deberia saltar una excepcion. Presumiblemente cuando  
    > interactuas a
    > traves del SerialPort, es el mismo el que se encarga de realizar las  
    > operaciones
    > en el orden adecuado para preservar estados.
    >
    > Aqui tienes el ejemplo para probar directamente, este ejemplo te envia ra  
    > una
    > trama a una velocidad diferente cada vez que invoques el sub... o sea  a  
    > 19200,
    > la siguiente a 9600, 4800..etc.
    >
    > '.. Dim MiPuerto As New System.IO.Ports.SerialPort
    > '.. MiPuerto = My.Computer.Ports.OpenSerialPort("COM1")
    > �?� Sub EnviarTrama �?�
    > Select Case MiPuerto.BaudRate
    > Case 19200
    > MiPuerto.BaudRate = 9600
    > Case 9600
    > MiPuerto.BaudRate = 4800
    > Case 9600
    > MiPuerto.BaudRate = 2400
    > Case Else
    > MiPuerto.BaudRate = 19200
    > End Select
    > MiPuerto.WriteLine("Hola... enviando a :" + MiPuerto.BaudRate.ToString )
    >
    > MVP - Visual Developer
     -- 
    Microsoft Visual C++ MVP => http://geeks.ms/blogs/rfog
    ======================== =============== Llegará un día que nuestros recuerdos serán nuestra rique za.
     -- Paul Geraldy. (1855-1954) Escritor francés.
     

    MVP Visual C++ - Visita mi blog sobre desarrollo: http://geeks.ms/blogs/rfog/
    Saturday, November 20, 2010 2:37 PM
  • Weno señores, os cuento lo que estoy haciendo,

    Como os he dicho, tengo una ventana de configuracion de los parametros del puerto serie, con botones para aceptar la configuracion, cargar una configuracion guardada, salvar la configuracion actual en un archivo, o salir sin guardar los cambios.

    Pues la solucion que se me ocurre, pero que no me convence mucho es lo siguiente:

    Tengo un archivo de cabecera llamado Parametros.h, donde almaceno los cambios en los parametros del puerto serie, es decir, cuando en la ventana de configuracion de los parametros del puerto serie pulso el boton de aceptar la configuracion, almaceno en las variables situadas en Parametros.h la nueva configuracion de los parametros, y tambien almaceno en una variable booleana llamada cambioConfiguracion, si he pulsado el boton de aceptar la configuracion. Este fichero.h es accesible por todas las ventanas de mi aplicacion. Pues bien, en la ventana donde declaro el puerto serie, y que es donde se realizan todas las comunicaciones, y donde se ejecuta el hilo que atiende las peticiones del puerto serie (Rfog no se si lo recuerdas :D), declaro un timer donde cada cierto tiempo compruebo si la variable booleana se ha puesto a true, lo que me indicara un cambio en la configuracion de los parametros. Si esto es asi, pues asigno mediante las variables disponibles en SerialPort la nueva configuracion.

    El motivo de que no me convenza mucho es que pienso que puedo estar perdiendo tiempo en ejecutar un timer que la mayoria de las veces no hace nada, por lo que disminuye el rendimiento de la aplicacion, aun mas cuando tengo varios hilos en la misma, y el tiempo es un recuerso muy preciado :P

    He probado todo esto ejecutando mi aplicacion sin conectarlo a un PLC, es decir, unicamente abriendo una ventana y enviando comandos por puerto serie (que no recibiran respuesta puesto que no esta conectado a nada), y al menos no me saltan excepciones de ningun tipo.

    Weno, escribo esto para ver si podeis dejarme comentarios, sugerencias o opiniones de cualquier tipo.

    Muchas gracias

    Saludos

     

    Tuesday, November 23, 2010 12:57 PM
  • Claro que me acuerdo, Marodal. :-)

    Personalmente creo que lo del timer es una pérdida de tiempo y recursos. Si creo recordar bien cómo lo estás haciendo, yo inyectaría un comando en la cola de comandos que fuera cambiar la velocidad del puerto, y así cuando me tocar el siguiente, comprobaría si es un cambio de velocidad y lo haría en el propio hilo del puerto serie.

    Pero si eso te hace estar mirando con "if(comando.Orden==CAMBIAR_VELOCIDAD" o algo similar porque tus comandos no sean una jerarquía de objetos automáticos, pondría un flag booleano y cada vez que termine de procesar un comando, comprobaría si tengo que cambiar la velocidad y lo haría. Más o menos como lo haces ahora con ese flag, pero que la respuesta esté dentro de tu procesador de comandos. Así incluso evitas que se te quede un comando a medio enviar o recibir en el cambio de velocidad.


    MVP Visual C++ - Visita mi blog sobre desarrollo: http://geeks.ms/blogs/rfog/
    Sunday, November 28, 2010 11:09 AM
  • Hola:

    Por aquí tengo un ejemplo hecho cambiar en tiempo real el puerto serie.

    http://electronica-pic.blogspot.com/2010/05/probando-interfaz-picrs232-v2-puerto.html

    Saludo.


    Tuesday, November 30, 2010 10:39 AM