Autor Tema: ¿Como hacer que una variable deje de contar si pasa algo en especifco?  (Leído 1407 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado GLG011

  • PIC10
  • *
  • Mensajes: 3
  Hola, tengo una duda y quisiera saber si alguien me puede ayudar.
 
  Estoy utilizando el pic 18f452 en mplab para hacer un contador de 30 a 0 que va disminuyendo cada un segundo, mostrandose el numero en 2 displays 7 segmentos multiplexados con timer0, pero este tiene que, si se activa la interrupcion externa (Se presiona el pulsador que esta conectado al pin RB0), pausarse y continuar con el descuento si se vuelve a presionar (despausa). Yo lo que hice, fue poner un if que dice que si se activo la interrupcion externa, y la cuenta (variable que guarda el numero que se esta mostrando en los displays) es mayor a 0. Dentro de ese if tengo que poner algo para que las variables que estan contando para que siga la cuenta se frenen y asi la cuenta quede en pusa, una vez que toque de nuevo el pulsador las variables empiezen a contar de nuevo.

  dejo la parte del codigo del que hablo para que se den cuenta de lo que digo:

if (INTCONbits.INT0IF == 1) // Si se activa la interrupcion externa.
    {
        if (cuenta > 0) // Si al activarse la interrupcion externa, la cuenta es mayor a 0.
        {
           
        }
       
        if( cuenta == 0) // Si la cuenta es igual a 0.
        {
            cuenta = 30; // Reinicia la cuenta, volviendo a 30.
        }
      INTCONbits.INT0IF = 0; 
    }

  Espero que alguien pueda brindarme alguna ayuda, muchas gracias.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:¿Como hacer que una variable deje de contar si pasa algo en especifco?
« Respuesta #1 en: 09 de Febrero de 2018, 17:45:30 »
Crea una nueva variable... supongamos "contar", de forma volatile

Código: C
  1. volatile char contar = 0;

En tu loop principal, o en tu interrupcion externa haces:

if(botonPresionado)
{
   contar ^= 1;
}

El timer que maneja la cuenta, supongamos que el timer entra 1 ves por segundos para que sea mas simple

Código: C
  1. if (INTCONbits.INT0IF == 1) // Si se activa la interrupcion externa.
  2. {
  3.         if(contar)
  4.         {
  5.               cuenta--;
  6.               if( cuenta == 0) // Si la cuenta es igual a 0.
  7.               {
  8.                  cuenta = 30; // Reinicia la cuenta, volviendo a 30.
  9.                }
  10.        }
  11.       INTCONbits.INT0IF = 0;  
  12. }

De esa forma si esta desactivado (en 0) no se va a producir el decremento de cuenta. Pero si se va a reiniciar el Timer, es decir el Timer va a seguir corriendo, pero evitas que se decremente.  Si queres que pare, cuando reestableces el valor cuenta a 30, lo pones en 0 a "contar"

Desconectado GLG011

  • PIC10
  • *
  • Mensajes: 3
Re:¿Como hacer que una variable deje de contar si pasa algo en especifco?
« Respuesta #2 en: 09 de Febrero de 2018, 18:36:40 »
  Hola, gracias por responder. Talvez me falto decir que tendo 17 años y hace medio año empece con esto de la programacion, asi que hay cosas que todavia no entiendo como eso de la variable volatile porque no me las enseñaron en el colegio.
 
  Estuve pensando y queria saber si se puede hacer una funcion la cual, cuando la llame, ponga todas las variables por encima del numero al que tienen que llegar para que decremente la cuenta, de esta manera se pausaria la cuenta, y otra funcion que ponga todas las variables a 0 para que se empiecen a incrementar de nuevo y la cuenta siga decrementandose. ¿Es posible que funcione?

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:¿Como hacer que una variable deje de contar si pasa algo en especifco?
« Respuesta #3 en: 09 de Febrero de 2018, 20:15:40 »
Citar
  Hola, gracias por responder. Talvez me falto decir que tendo 17 años y hace medio año empece con esto de la programacion, asi que hay cosas que todavia no entiendo como eso de la variable volatile porque no me las enseñaron en el colegio.

No te preocupes, ya vas a aprender. Volatile usalo cuando la misma variable la uses en una funcion de interrupcion y tambien en el programa principal ( main ). tene como regla eso y no vas a tener problema, lo que hace es obligar al compilador que revise la variable. El problema viene cuando tenes optimizaciones, si el compilador observa esta funcion:


Código: C
  1. if (INTCONbits.INT0IF == 1) // Si se activa la interrupcion externa.
  2. {
  3.         if(contar)
  4.         {
  5.        }
  6.       INTCONbits.INT0IF = 0;  
  7. }

Y quiere optimizar el codigo para que sea mas veloz, se va a dar cuenta que contar nunca se modifica. Por lo tanto lo va a quitar de alli ya que para el , al no modificarse nunca, no tiene sentido preguntar por la misma. Recorda que las funciones de interrupcion nunca se llaman desde el main, por lo tanto no hay ninguna conexion por mas que vos modifiques en el main ese valor. Con el volatile lo olbigas a que si o si pregunte por la variable porque puede haber cambiado sin intervencion de la persona, un ejemplo donde se usa volatile son los puertos, ya que como pueden cambiar por si solos ( sin que el usuario escriba una instruccion sobre este) se lo obliga al compilador que si o si lea de nuevo el puerto cada ves que se le pide.

Citar
Estuve pensando y queria saber si se puede hacer una funcion la cual, cuando la llame, ponga todas las variables por encima del numero al que tienen que llegar para que decremente la cuenta, de esta manera se pausaria la cuenta, y otra funcion que ponga todas las variables a 0 para que se empiecen a incrementar de nuevo y la cuenta siga decrementandose. ¿Es posible que funcione?

Pensa esto... La funcion del Timer asi como esta tal ves le falten 2 o 3 lineas de codigo. Te conviene crear funciones con 1 o 2 lineas de codigo nomas?.
Cuando no es largo o cuando no se repite el codigo ( para que puedas reutilizarlo en varios lados ) por ahi no tiene sentido crear una funcion extra.

Cualquier cosa plantea la funcion, hacelo y observa si se vuelve mas legible de lo que ya esta. Lo importante es la legibilidad del codigo, mientras mas entendible mejor.

Desconectado GLG011

  • PIC10
  • *
  • Mensajes: 3
Re:¿Como hacer que una variable deje de contar si pasa algo en especifco?
« Respuesta #4 en: 10 de Febrero de 2018, 17:21:42 »
  Ahora voy entendiendo mejor lo que es una variable volatile, pero igual creo que es mejor no usarla, ya que al no haberla aprendido en el colegio, si me llega a ir mal en mi examen en las proximas semanas debido a que use una variable que no fue enseñada, no voy a tener excusa ya que utilize temas mas avanzados.
  Si no es molestia, paso mi codigo por aca (El cual termine ayer) y me podrian decir si puede que funcione o que le faltaria o esta mal. Yo estoy creando una placa en protheus para probar el codigo, pero si alguien ve un error de entrada me lo podria hacer saber.
 
  Desde ya, muchas gracias.

 -Codigo terminado:

/*
 * File:   _Code febrero.c
 * Author: Gonzalez, Lautaro.
 *
 * Created on 5 de febrero de 2018, 10:37
 */

#include <stdio.h>
#include <stdlib.h>
#include "_Config febrero.h"
#define cero   63
#define uno    6
#define dos    91
#define tres   79
#define cuatro 102
#define cinco  109
#define seis   125
#define siete  7
#define ocho   127
#define nueve  103
#define Tuni  PORTEbits.RE1 // Se define como "Tuni" al pin RE0.
#define Tdec  PORTEbits.RE0 // Se define como "Tdec" al pin RE1.
#define Pulsador  PORTBbits.RB0 // Se define como "Pulsador" al pin RB0.

void visualizar (); // Se declara la funcion visualizar.
void pausa (); // Se declara la funcion pausa.
void despausa (); // Se declara la funcion despausa.

int Unidad = 0; // Variable que guarda el numero de la unidad.
int Decena = 0; // Variable que guarda el numero de la  decena.
int A = 0; // Variable para visualizar los numeros cada 1 segundo.
int B = 0; // Variable para visualizar los numeros de la cuenta a 2 Hz.
int modo = 0; // Variable para pausa/despausa.
int cuenta = 30; // Variable que lleva el numero que se muestra en los displays.

void main ()
{
    INTCON = 0xB0; // Configuracion del registro de interrupciones.
    T0CON = 0xC7; // Configuracion del registro del timer0.
    TRISD = 0x00; // Se configuran los pines, donde estan conectados los displays, como salida.
    TRISBbits.RB0 = 1; // Se configura el pin "RB0", el cual se conecta al pulsador, como entrada.
    ADCON1bits.PCFG0 = 0;
    ADCON1bits.PCFG1 = 1;
    ADCON1bits.PCFG2 = 1;
    ADCON1bits.PCFG3 = 0;
   
    while(1)
    {
       
    }
}

void visualizar ()
{
    Decena = cuenta/10; // El numero que se tiene que mostrar en la decena de la cuenta, se obtiene dividiendo el  numero en 10.
    Unidad = cuenta%10; // Para obtener la unidad, se divide el numero en 10 pero el valor que toma la variable es el numero despues de la coma.
   
    switch (Unidad)
    {
        case 0:
            PORTD = cero;
            break;
        case 1:
            PORTD = uno;
            break;
        case 2:
            PORTD = dos;
            break;
        case 3:
            PORTD = tres;
            break;
        case 4:
            PORTD = cuatro;
            break;
        case 5:
            PORTD = cinco;
            break;
        case 6:
            PORTD = seis;
            break;
        case 7:
            PORTD = siete;
            break;
        case 8:
            PORTD = ocho;
            break;
        case 9:
            PORTD = nueve;
            break;
    }
   
    Tuni = 1; // Se activa el transistor predeterminado para mostrar la unidad.
    __delay_ms(10); // El numero se muestra por 10 ms.
    Tuni = 0; // Se pone a cero el transistor para que no muestre mas el numero.
   
    switch (Decena)
    {
        case 0:
            PORTD = cero;
            break;
        case 1:
            PORTD = uno;
            break;
        case 2:
            PORTD = dos;
            break;
        case 3:
            PORTD =  tres;
            break;
        case 4:
            PORTD = cuatro;
            break;
        case 5:
            PORTD = cinco;
            break;
        case 6:
            PORTD = seis;
            break;
        case 7:
            PORTD = siete;
            break;
        case 8:
            PORTD = ocho;
            break;
        case 9:
            PORTD = nueve;
            break;         
    }
   
    Tdec = 1; // Se activa el transistor predeterminado para mostrar la decena.
    __delay_ms(10); // El numero se muestra por 10 ms.
    Tdec = 0; // Se pone a cero el transistor para que no muestre mas el numero.
}

void interrupt isr ()
{
    if (INTCONbits.TMR0IF == 1) // Si se activa la interrupcion por timer.
    {
        visualizar(); // Se muestra el numero de la cuenta en los displays.
        A++; // La variable "A" se pone a contar.
        if (A == 15) // Si "A" llega a 15.
        {
            A = 0; // "A" regresa a 0.
            cuenta--; // La cuenta disminuye un numero.           
        }
        if (cuenta < 10) // Si la cuenta es menor a 10.
        {
            B++; // La variable "B" se pone a contar.
            if (B == 8) // Si "B" llega a 8.
            {               
                PORTD = 0x00; // Se ponen todos los pines "D" en 0, apagandose los displays.
            }
            if (B == 16) // Si "B" llega a 16.
            {
                PORTD = 0xFF; // Se ponen todos los pines "D" en 1, prendiendose nuevamente los displays.
            }
        }
        if (cuenta == 0) // Si la cuenta llega a 0.
        {
            pausa();
        }       
      INTCONbits.TMR0IF = 0; // Se baja la bandera de interrupcion por timer.       
    }
   
    if (INTCONbits.INT0IF == 1) // Si se activa la interrupcion externa.
    {
        if (cuenta > 0) // Si al activarse la interrupcion externa, la cuenta es mayor a 0.
        {
            modo++; // La variable "modo" se incrementa.
            if (modo == 1) // Si "modo" es igual a 1.
            {
                pausa(); // Se desata la funcion "pausa".
            }
            if (modo == 2) // Si "modo" llega a 2.
            {
                modo = 0; // "modo" vuelve a 0.
                despausa(); // Se desata la funcion "despausa".
            }   
        }
       
        if( cuenta == 0) // Si la cuenta es igual a 0.
        {
            cuenta = 30; // Reinicia la cuenta, volviendo a 30.
        }
      INTCONbits.INT0IF = 0; // Se baja la bandera de interrupcion por timer. 
    }
}

void pausa ()
{
    A = A; // La variable "A" se queda con el valor con el que tenia.
}

void despausa ()
{
    A = 0; // "A"  vuelve a 0.
}

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:¿Como hacer que una variable deje de contar si pasa algo en especifco?
« Respuesta #5 en: 10 de Febrero de 2018, 20:42:50 »
No te va a servir....

Ya que a la interrupcion del timer se sigue accediendo. Por lo tanto A se sigue incrementando y va a llegar a 15 en algun momento, es decir luego de 15 entradas a la interrupcion.
Ponerlo a 0 lo unico que vas a lograr es "demorar" el decremento de cuenta.

No se cual es el objetivo de esto:

Código: C
  1. B++; // La variable "B" se pone a contar.
  2.             if (B == 8) // Si "B" llega a 8.
  3.             {              
  4.                 PORTD = 0x00; // Se ponen todos los pines "D" en 0, apagandose los displays.
  5.             }
  6.             if (B == 16) // Si "B" llega a 16.
  7.             {
  8.                 PORTD = 0xFF; // Se ponen todos los pines "D" en 1, prendiendose nuevamente los displays.
  9.             }

Arriba estas intentando mostrar el numero y luego pones todas las salidas en 0 o en 1. sin ningun sentido, ya que luego cuando se ejecute el visualizar esos valores se van a ir.

----------------------------------------------------------------------------------

El siguiente codigo que voy a poner puede resolverse facilmente con un array, pensa que si tenes un 0 quiere decir que accedes al indice 0 del mismo

Código: C
  1. switch (Unidad)
  2.     {
  3.         case 0:
  4.             PORTD = cero;
  5.             break;
  6.         case 1:
  7.             PORTD = uno;
  8.             break;
  9.         case 2:
  10.             PORTD = dos;
  11.             break;
  12.         case 3:
  13.             PORTD = tres;
  14.             break;
  15.         case 4:
  16.             PORTD = cuatro;
  17.             break;
  18.         case 5:
  19.             PORTD = cinco;
  20.             break;
  21.         case 6:
  22.             PORTD = seis;
  23.             break;
  24.         case 7:
  25.             PORTD = siete;
  26.             break;
  27.         case 8:
  28.             PORTD = ocho;
  29.             break;
  30.         case 9:
  31.             PORTD = nueve;
  32.             break;
  33.     }

Es decir usar algo asi, primero definir el array y luego usarlo:

Código: C
  1. // Esto definido arriba, junto a las otras variables
  2. const char numeros[] = {63,6,91,79,102,109,125,7,127,103};
  3.  
  4. // Esto es como usarlo, y que si observas tenes el mismo resultado.
  5. PORTD = numeros[Unidad];


-----------------------------------------------------

Como consejo jamas pongas un delay en una interrupcion, por mas que no afecte actualmente al programa.

Código: C
  1. __delay_ms(10); // El numero se muestra por 10 ms.

Y respecto al Timer lo estas mal utilizando, de tal forma que ni siqueira es necesario el timer o su interrupcion.

-----------------------------------------------------

Te presento un codigo y te muestro la diferencia.

Código: C
  1. #define Tuni  PORTEbits.RE1 // Se define como "Tuni" al pin RE0.
  2. #define Tdec  PORTEbits.RE0 // Se define como "Tdec" al pin RE1.
  3. #define Pulsador  PORTBbits.RB0 // Se define como "Pulsador" al pin RB0.
  4.  
  5. void visualizar (); // Se declara la funcion visualizar.
  6.  
  7. const char numeros[] = {63,6,91,79,102,109,125,7,127,103};
  8. char EsUnidad = 0;      // Variable que guarda el numero de la  decena.
  9. int interrupciones = 0; // Variable para visualizar los numeros cada 1 segundo.
  10. int pausa = 1;           // Variable para pausa/despausa.
  11. int cuenta = 30;        // Variable que lleva el numero que se muestra en los displays.
  12.  
  13. void main ()
  14. {
  15.     TRISD = 0x00;       // Se configuran los pines, donde estan conectados los displays, como salida.
  16.     TRISBbits.RB0 = 1; // Se configura el pin "RB0", el cual se conecta al pulsador, como entrada.
  17.     ADCON1bits.PCFG0 = 0;
  18.     ADCON1bits.PCFG1 = 1;
  19.     ADCON1bits.PCFG2 = 1;
  20.     ADCON1bits.PCFG3 = 0;
  21.  
  22.     T0CON = 0x04;   // Configuracion del registro del timer0 Preescaler 1:32.
  23.     TMR0H = 0xFE;   // Valores de ""10ms"" para distintos valores de oscilador:
  24.     TMR0L = 0xC8;   // 4Mhz: 0xFEC8  8Mhz: 0xFD8F  10Mhz: 0xFCF3 20Mhz: F9E6
  25.  
  26.     T0CONbits.TMR0ON = 1;   //Activo el TMR0
  27.     INTCON = 0xB0;  // Configuracion del registro de interrupciones.
  28.    
  29.     while(1)
  30.     {
  31.        
  32.     }
  33. }
  34.  
  35. void visualizar()
  36. {
  37.   if(EsUnidad)
  38.   {
  39.     Tdec = 0;
  40.     PORTD = numeros[cuenta%10];
  41.     Tuni = 1;
  42.   }
  43.   else
  44.   {
  45.     Tuni = 0;
  46.     PORTD = numeros[cuenta/10];
  47.     Tdec = 1;
  48.   }
  49. }
  50.  
  51. void interrupt isr ()
  52. {
  53.     /*
  54.      * Seccion de interrupcion del Timer0
  55.      */
  56.     if (INTCONbits.TMR0IF == 1) // Si se activa la interrupcion por timer.
  57.     {
  58.       INTCONbits.TMR0IF = 0;    // Se Limpia la bandera
  59.       TMR0H = 0xFE;             // Recargo el Timer, para que vuelvan a ser 10ms
  60.       TMR0L = 0xC8;
  61.  
  62.       visualizar();             // Se muestra el numero de la cuenta en los displays.
  63.  
  64.       if(pausa == 0)                // Esta corriendo?, si es asi sigo contando hasta que pase el segundo
  65.       {
  66.         interrupciones++;
  67.         if(interrupciones >= 100)   // 100 * 10ms = 1s , si paso el segundo procedo a decrementar.
  68.         {
  69.           interrupciones = 0;
  70.           cuenta--;                 // La cuenta disminuye un numero.
  71.           if(cuenta == 0)
  72.           {
  73.             pausa = 1;              // Si llego al final lo pauso por las dudas
  74.           }
  75.         }
  76.       }
  77.     }
  78.  
  79.     /*
  80.      *  Seccion de interrupcion de RB0
  81.      */    
  82.     if (INTCONbits.INT0IF == 1) // Si se activa la interrupcion externa.
  83.     {
  84.         if( cuenta == 0) // Si la cuenta es igual a 0.
  85.         {
  86.             cuenta = 30;  // Reinicia la cuenta, volviendo a 30.
  87.         }
  88.         else
  89.         {
  90.             pausa ^= 1;    // Si es 0 lo deja en 1, si es 1 lo deja en 0. es decir es pausa XOR 0b0000 0001
  91.         }
  92.  
  93.       INTCONbits.INT0IF = 0; // Se baja la bandera de interrupcion por timer.  
  94.     }
  95. }

En este codigo tenemos las siguientes diferencias.

Antes al mostrar vos procedias a poner el dato, activar el comun, y usar un delay, aca lo hacemos distinto.
Esta ves vamos a usar correctamente el Timer, si observas calcule los valores para 10ms (aproximados) con distintos cristales que le puedas poner ( suponiendo que no usas el PLL )
Esto hace que el Timer entre si o si cada 10ms, al entrar vuelve a recargar el Timer para que vuelva a entrar cada 10ms.

¿Que ventajas tengo?
No necesito genera un delay, el tiempo lo espera por si solo el Timer, cada ves que entre a la interrupcion por el timer va a activar la unidad o la decena. La primera ves que entra muestra la decena, y no lo desactiva hasta que entra de nuevo (10ms) luego desactiva y muestra la unidad y no lo desactiva hasta que entra de nuevo (10ms) entonces tenes el mismo comportamiento que antes.

El uso de array facilita mucho las cosas, lo que si nunca hay una proteccion de que cuenta supere alguna ves el maximo que es 99, asi que hay que tenerlo en cuenta.
La pausa como ves lo unico que hace es que se evite la cuenta de las interrupciones, nada mas. Si se detiene esa cuenta se detiene el decremento.
Pero no evita que se siga ejecutando el  la parte de visualizar los datos.
« Última modificación: 10 de Febrero de 2018, 20:46:10 por KILLERJC »


 

anything