From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

Discusiones sobre Productos NI

cancelar
Mostrando los resultados de 
Buscar en lugar de 
Quiere decir: 

labwindows activar boton dentro de rutina

Hola a todos, soy nuevo con el LabwindowsCVI y tengo un pequeño problema,  a ver si pueden ayudarme.

 

Estoy creado un trozo de código en el que cuando activo un control de tipo CommandBotton ejecuta una rutina la cual es larga, ya que se conecta a un instrumento y debe tomar muchas medidas. Pues buen mi problema es que quiera parar esa rutina cuando se pulse otro determinado control (CommandBotton) del mismo panel, pero como el programa ya que se encuentra dentro de la rutina que toma medidas, el panel está como bloqueado y no hace caso a nada hasta que la rutina. Eso si, una vez acabada la toma de medidas todos los botones y elementos del panel vuelven a estar activos y todo funciona.

 

 

He probado a poner un timer que cada cierto tiempo interrumpa la toma de medidas, pero éste tampoco se activa hasta que no finalizo a rutina.

 

Alguien me puede dar alguna solución?

 

Un saludo y gracias

0 kudos
Mensaje 1 de 8
3.451 Vistas

Hola,

el tuyo es un problema común entre los que se acercan al CVI y tienen que desarrollar rutinas de larga duración. Puedes solucionar tu probmea de dos maneras: una es bastante simple mientras que la otra impone desarrol el código de manera radicalmente diferente pero es mucho mas robusta.

 

La solución simple pasa por el ProcessSystemEvents (), una función que permite que el sistema maneje los eventos mientras que el programa està en un loop cerrado. Si haces una búsqueda por esta palabra clave encontrarás muchas discusiones que van a serte muy útiles, la más reciente creo que es esta. Hay algunas desventajas en este método, por ejemplo tienes que limitar los comandos que el usuario puede activar así que por ejemplo no se corra la rutina de prueba una segunda vez pulsando nuevamente el correspondiente botón. De igual manera, como ya has notado, se disturba en este modo el normal ritmo de emisión de los eventos (por ejemplo el timer) alterando en suma la estructura del sistema operativo, lo que puede comportar otros problemas.

 

Para evitar todo esto, es buena norma desarrollar el código de manera que no haya callbacks que corran por mucho tiempo; mjor es hacer que los botones activen routinas asíncronas, ya sea en un thread separado, en un timer u con otros métodos.

Una solución puede ser el uso de una "máquina de estados" (state machine: tambén hay muchos tutoriales y discusiones en este sitio sobre este argumento, por ejemplo esto; aunque casi todas se refieran al LabVIEW, sin embargo proporcionan elementos útiles para aplicarlos al CVI).

 

Una simple estructura con una máquina de estados desarrollada dentro de un timer puede ser esta: he puesto solamente un esquéleto para tomar medidas, pero pueden añadirse estados para otras operaciones y determinar las transiciones desde cada uno al siguiente por medio de la variable "status".

 

enum ESTADOS { OFF, PIDEMEDICIONES, ESPERA, LEEMEDICIONES, ERROR };


timer callback

{

  static int cnt;

  if (event != EVENT_TIMER_TICK) return 0;

  switch (status) {

    case OFF:

       // Fuera de la routina de prueba: no hace nada

       break;

    case PIDEMEDICIONES:

        // comandos al instrumento para pedir mediciones

       status = ESPERA; cnt = 0;

       break;

    case ESPERA:

       // El instrumento está listo para dar las mediciones: a segunda del tipo

       // de instrumento habrá una condición para señalar este estado

       if (hayMediciones) {

         status = LEEMEDICIONES;

         break;

       }

       if (++cnt > 3) {

          cnt = 0;

          status = ERROR;

          break;

       }

       break;

     case LEEMEDICIONES:

       // lee desde el instrumento

       status = PIDEMEDICIONES;

       break;

     case ERROR:

       // avisa al usuario, registra evento en el log....

       if (++cnt > 10) {

         // Intenta averiguar si puede conectarse al instrumento

         status = PIDEMEDICIONES;

       }

       break;

  }

  return 0;

}

 



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 kudos
Mensaje 2 de 8
3.439 Vistas

Muchas gracias Roberto por tus soluciones y por responder tan pronto, voy a ver como puedo integrarlas dentro de mi código. No pensé en una máquina de estados (muy buena alternativa) aunque tendré que probarla.

 

Bueno espero que tenga suerte y funcione.

 

Muchas Gracias

 

 

0 kudos
Mensaje 3 de 8
3.427 Vistas

Hola de nuevo, he estado probando las soluciones que Roberto me dió pero no he obtenido muchos resultados (seguranmente por la falta de tiempo en realizar pruebas), de todos modos os dejo aqui un trozo de código a ver si me podeis orientar de nuevo sobre el problema que tengo, lo comento:

 

Cuando presiono el boton "empezar" se carga un panel de medidas en el cual represento varias medias, algunas de estas medidas duran bastante tiempo ya que realiza la busqueda de algunos valores de un transmisor, pues bien necesitaría parar el proceso que se encuentra dentro de la callback empezar y volver al panel principal con otro botón denominado "parar" pero éste (y ningún otro botón del panel de medidas) no funciona a menos que finalice la callback de "empezar". Además en el panel principal hay un botón de "salir" que deberá finalizar la aplicación.

 

Aqui os dejo un trozo de código simplicado del programa. La callback "empezar" tiene algo más de cógido pero no he querido extenderlo mucho ya que carece de importancia y se ejecuta rápidamente.

 

Un saludo y gracias.

 

 

 

0 kudos
Mensaje 4 de 8
3.410 Vistas

Hola ACMEPIC,

he mirado a tu código pero no encuentro ni una ocurrencia del ProcessSystemEvents que te sugerí; tampoco hay un esquema de máquina de estados. Es bastante claro el porque no logras interrumpir la prueba, ya que mientras estás en la callback "empezar" el sistema no va mirando a las acciones del usuario.

No he estado modificando directamente al código, pero creo que una primera solucción podría ser en:

 

1. Cambiar el botón de parada en un toggle button, sin asociar ninguna callback al mismo

 

2. Modificar por lo menos la routina "buscanivel" de esta manera:

 

double buscanivel (double nivelinicial, short modulac, double modinf, double modsup, int *parada)
{
    // ...
    do
    {    
        ProcessSystemEvents ();
        GetCtrlVal (panelHandle, controlID, parada);
        if (*parada) break;

        // Otro código aquí

    } while ((temp1<=modinf)||(temp1>=modsup));
             
    return (resultado -= 0.1);
}

 

3. Modificar la llamada a "buscanivel" de esta manera:

 

    nivel85 = buscanivel (nivelinicial, modulac, modinf, modsup, &parada);

    if (parada) {

       // Interrumpir la routina

    }

 

4. Modificar de manera semejante todo el código después de la etiqueta /*MEDIDA DE ESPECTRO*/

 

5. Averiguar si las routinas Send () y Receive () incluyen loops cerrados sin mirar al sistema y en el caso pensar si pueden ser modificadas u si no vale la pena (por ser muy rápidas por ejemplo)

 

6. Pensar en modificar todas las pausas con Delay en este modo:

 

    tini = Timer ();
    while (Timer () - tini < 0.5) {
        ProcessSystemEvents ()
        GetCtrlVal (panelHandle, controlID, &parada);
        if (parada) {
            // Parar la prueba y salir
        }
    }

 

Estas sugerencias no abarcan todo el asunto; sin embargo constituyen un incio del que empezar trabajando por tu cuenta en la modificación del código para que salga como tu quieres.



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 kudos
Mensaje 5 de 8
3.407 Vistas

Gracias de nuevo Roberto, hice pruebas con el ProcessSystemEvents(); pero sin resultado, ya que no sustituí el boton parar por un toggle button y su callback correspondiente. Además en la pruebas también puse la sentencia ProcessSystenEvents(); al inicio de la callback empezar.

 

En cuanto a lo de la máquina de estados creo que tendría que modificar mucho la estructura del programa y tampoco tengo claro si funcionaría.

 

Bueno probaré tus sugerencias y a ver si tengo suerte.

 

 

Un saludo y muchas gracias por tu colaboración.

0 kudos
Mensaje 6 de 8
3.395 Vistas

ACMEPIC ha scritto:

Gracias de nuevo Roberto, hice pruebas con el ProcessSystemEvents(); pero sin resultado, ya que no sustituí el boton parar por un toggle button y su callback correspondiente. Además en la pruebas también puse la sentencia ProcessSystenEvents(); al inicio de la callback empezar


No es suficiente con poner la instrucción solamente en un sitio: puesto que la callback es de larga duración tienes que controlar los eventos muchas veces. Por esto te sugerí ponerla en BuscaNivel (): me parece que la mayor parte del tiempo de la callback se gasta en ésta. Además, por estar dentro de un loop el ProcessSystemEvents () es ejecutado con la mayor frecuencia posible.



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 kudos
Mensaje 7 de 8
3.392 Vistas

Aunque ahora estoy algunos días de vacaciones y no puedo experimentar con el código, probaré tu propuesta que seguro que funciona.

 

Un saludo y gracias de nuevo.

0 kudos
Mensaje 8 de 8
3.380 Vistas