Autor Tema: Botones de Inicio, Pausa y Reset en Cronometro con Pic16F877A  (Leído 6912 veces)

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

Desconectado JM89

  • PIC10
  • *
  • Mensajes: 3
Botones de Inicio, Pausa y Reset en Cronometro con Pic16F877A
« en: 18 de Junio de 2018, 10:26:18 »
Buen dia Compañeros,

Reciban un cordial saludo desde Colombia

Estoy iniciando en el mundo de los pic y hace rato estoy en el trabajo de realizar un cronometro de seis digitos (Min, Seg y Dec-Seg), con un Pic16F877A, ya pude desarrollar la idea pero estoy estancado en el control del cronometro ya que desde el momento de que recibe energia este empieza el conteo, y lo que necesito es poder iniciarlo con un sensor qrd1114 y detenerlo con otro qrd1114 y poderle dar reset para que inicie otra vez en 0's.

Adjunto el codigo, lo estoy desarrollando en en MikroC Pro for PIC 2013

Puertos C y D estan como salidas para los 7 Segmentos

Les Agradeceré eternamente su ayuda.


#define datos PORTC
void d1 ()   {
portd=0b00000001;
           }
           
void d2 ()   {
portd=0b00000010;
           }
           
           void d3 ()   {
portd=0b00000100;
           }
               void d4 ()   {
portd=0b00001000;
           }
                 void d5 ()   {
portd=0b00010000;
           }
           void d6 ()   {
portd=0b00100000;
           }

short numero[]={192,249,164,176,153,146,130,248,128,144
};
int i,minuto,minuto1,segundo,segundo1,milisegundo,milisegundo1;


void main() {



adcon1=6;

TRISC=0;
TRISD=0;


PORTC=0;
PORTD=0;


while(1)  {






for(minuto1=0;minuto1<=5;minuto1++){
for(minuto=0;minuto<=9;minuto++){

for(segundo1=0;segundo1<=5;segundo1++){
for(segundo=0;segundo<=9;segundo++){

for(milisegundo1=0;milisegundo1<=9;milisegundo1++){
for(milisegundo=0;milisegundo<=9;milisegundo++){


if(minuto1==5 & minuto==9){
minuto=0;
minuto1=0;
}
for(i=0;i<1;i++) {

d6();
datos=numero[milisegundo];
delay_ms(1);
d5();
datos=numero[milisegundo1];
delay_ms(1);

d4();
datos=numero[segundo];
delay_ms(1);
d3();
datos=numero[segundo1];
delay_ms(1);

d2();
datos=numero[minuto];
delay_ms(1);
d1();
datos=numero[minuto1];
delay_ms(1);
}
         }
         }
         }

        }
      }
          }
         }
       }






Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Botones de Inicio, Pausa y Reset en Cronometro con Pic16F877A
« Respuesta #1 en: 18 de Junio de 2018, 21:04:20 »
Hacerlo con delays es malo, seguramente le erre en tiempo y por mucho. Pero para comenzar no veo mal la idea. Tu programa lo deberias dividir en varias partes que poco a poco podes ir mejorando.. Necesitas:

- Leer los pulsadores y actuar en consecuencia.
- Aumentar el tiempo acumulado en caso de ser necesario
- Mostrar los datos en un display.

Entonces vamos a tener un main algo asi:

Código: C
  1. void main(void)
  2. {
  3.   //Configuracion de pines
  4.  
  5.   while(1)
  6.   {
  7.     LecturaDeSensores();
  8.     if(RelojCorriendo == 1)
  9.     {
  10.         AumentarReloj();
  11.     }
  12.     MostrarEnDisplay();
  13.     Delay_ms(10);
  14.   }
  15. }

Algunas cosa a tener en cuenta al diseñar esto... la idea es que ninguna de esas funciones ocupe demasiado tiempo, sino que lo mas consumidor en todas las instrucciones que puede tener dentro del while sea el delay en este ejemplo. Esto te va a llevar a pensar de otra forma.
Ejemplo, como incremento mis numeros.
Yo se que pasaron 10ms (aproximado) desde que entro la anterior ves, gracias a mi delay de 10ms. Entonces podria aumentar mi decima de milisegundo cada ves que entra.. Supongamos que tenemos estas variables: ( MM:SS:mm

Milisegundo
DecimaMilisegundo
Segundo
DecimaSegundo
Minuto
DecimaMinuto

Entonces al entrar haria:

Código: C
  1. Milisegundo++;
  2. if(Milisegundo>9)
  3. {
  4.   Milisegundo = 0;
  5.   DecimaMilisegundo ++;
  6. }
  7. if(DecimaMilisegundo>9)
  8. {
  9.   DecimaMilisegundo = 0;
  10.   Segundo ++;
  11. }
  12. // etc...

Es decir incremento mi decima y luego corrijo.

Pero.... que pasa con mostrar en el display...
Algo tentador seria hacer esto:

Código: C
  1. void MostrarDisplay(void)
  2. {
  3.       //Muestro Display1
  4.       //delay
  5.       //Muestro Display2
  6.       //delay
  7. }

Pero estariamos agregando delays, y eso afecta a nuestra base de tiempo conocida, que son esos 10ms!!!!!. NO sirve.. vamos a necesitar otra forma que muestre 1 numero y luego salga, pero la proxima ves que entre muestre el numero que le sigue! Para esto lo mejor son los arrays y tener una variable para indicar cual es el que debemos encender.

Todas tus funciones d1,d2,d3, etc se van a simplificar. Y por ahora vamos a usar un switch case, pero podrias tranquilamente tambien usar un array para guardar tus numeros, luego pongo un codigo mas simple.

Código: C
  1. unsigned char ComunPuerto[] = {0b1,0b10,0b100,0b1000,0b10000};
  2. unsigned char numeroDeDigito = 0;
  3.  
  4. void Mostrar_Display(void)
  5. {
  6.   switch(numeroDeDigito)
  7.   {
  8.   case 0:
  9.     PORTC = numero[Milisegundo];
  10.     break;
  11.   case 1:
  12.     PORTC = numero[DecimaMilisegundo];
  13.     break;
  14.   case 2:
  15.     PORTC = numero[Segundo];
  16.     break;
  17.   case 3:
  18.     // seguir rellenenado
  19.   }
  20.   PORTD = ComunPuerto[numeroDeDigito];
  21.   numeroDeDigito++;
  22.   if(numeroDeDigito > sizeof ComunPuerto) numeroDeDigito = 0;
  23. }


Como ves mostramos mucho mas rapido con un array.. que pasaria si crearamos OTRO array para almacenar los numeros a mostrar. Ejemplo:

short numero[]={192,249,164,176,153,146,130,248,128,144};
unsigned char ComunPuerto[] = {0b1,0b10,0b100,0b1000,0b10000,0b100000};
unsigned char NumerosMostrar[] = {1,2,4,8,9,7};      // 12 minutos, 48 segundos, 97 milesimas
unsigned char numeroDeDigito = 0;

Mi funcion de mostrar ahora seria asi:

Código: C
  1. void Mostrar_Display(void)
  2. {
  3.   PORTC = numero[NumerosMostrar[numeroDeDigito]];
  4.   PORTD = ComunPuerto[numeroDeDigito];
  5.   numeroDeDigito++;
  6.   if(numeroDeDigito > sizeof ComunPuerto) numeroDeDigito = 0;
  7. }

Se simplifico bastante no?
Respecto a los sensores, es leer el pin, y si esta activo, podrias por ejemplo cambiar una variable RelojCorriendo, entre 0 y 1, de esa forma podes "parar" (haces que no auemnte la cuenta) el reloj. Y si activa el sensor de reset, procedes a poner a 0 en cada posicion el array NumerosMostrar. Por supuesto, esto va a entrar cada 10ms, por lo que vas a tener que tener en cuenta que si el sensor se mantiene activo por mas de 10ms, no le hagas caso, podes esperar que se suelte por ejemplo. Esta parte te la dejo a vos, venis con una solucion y luego le damos otra vuelta de tuerca.

Desconectado JM89

  • PIC10
  • *
  • Mensajes: 3
Re:Botones de Inicio, Pausa y Reset en Cronometro con Pic16F877A
« Respuesta #2 en: 03 de Agosto de 2018, 13:48:14 »
Killer aqui logré controlar el start del cronometro, no he logrado realizar el stop

Código: C
  1. #define datos PORTC
  2. void d1 ()   {
  3. portd=0b00000001;
  4.            }
  5.  
  6. void d2 ()   {
  7. portd=0b00000010;
  8.            }
  9.  
  10.            void d3 ()   {
  11. portd=0b00000100;
  12.            }
  13.                void d4 ()   {
  14. portd=0b00001000;
  15.            }
  16.                  void d5 ()   {
  17. portd=0b00010000;
  18.            }
  19.            void d6 ()   {
  20. portd=0b00100000;
  21.            }
  22.  
  23. short numero[]={192,249,164,176,153,146,130,248,128,144
  24. };
  25. int i,minuto,minuto1,segundo,segundo1,milisegundo,milisegundo1;
  26.  
  27.  
  28. void main() {
  29.  
  30.  
  31.  
  32. adcon1=6;
  33.  
  34. TRISC=0;                   // SALIDA
  35. TRISD=0;           // SALIDA
  36. TRISA=1; // ENTRADA
  37.  
  38.  
  39. PORTC=0;
  40. PORTD=0;
  41.  
  42.  
  43.  
  44.  
  45.  
  46.  
  47. while(1)  {
  48.  
  49. if(PORTA.RA0 == 1)
  50.  
  51.  
  52.    {
  53.  
  54. for(minuto1=0;minuto1<=5;minuto1++){
  55. for(minuto=0;minuto<=9;minuto++){
  56.  
  57. for(segundo1=0;segundo1<=5;segundo1++){
  58. for(segundo=0;segundo<=9;segundo++){
  59.  
  60. for(milisegundo1=0;milisegundo1<=9;milisegundo1++){
  61. for(milisegundo=0;milisegundo<=9;milisegundo++){
  62.  
  63.  
  64. if(minuto1==5 & minuto==9){
  65. minuto=0;
  66. minuto1=0;
  67. }
  68. for(i=0;i<1;i++) {
  69.  
  70. d6();
  71. datos=numero[milisegundo];
  72. delay_ms(1);
  73. d5();
  74. datos=numero[milisegundo1];
  75. delay_ms(1);
  76.  
  77. d4();
  78. datos=numero[segundo];
  79. delay_ms(4);
  80. d3();
  81. datos=numero[segundo1];
  82. delay_ms(4);
  83.  
  84. d2();
  85. datos=numero[minuto];
  86. delay_ms(1);
  87. d1();
  88. datos=numero[minuto1];
  89. delay_ms(1);
  90. }
  91.  
  92.  
  93.          }
  94.          }
  95.          }
  96.  
  97.         }
  98.       }
  99.           }
  100.          }
  101.  
  102.          else(portd=255);
  103.  
  104.          }  //cierra el if del push de start
  105.  
  106.  
  107. }

Te agradezco tu ayuda, aqui traté de armar el codigo que me pasaste ahi voy

Código: C
  1. unsigned char ComunPuerto[] = {0b1,0b10,0b100,0b1000,0b10000};
  2. unsigned char numeroDeDigito = 0;
  3.  
  4. void Mostrar_Display(void)
  5. {
  6.   PORTC = numero[NumerosMostrar[numeroDeDigito]];
  7.   PORTD = ComunPuerto[numeroDeDigito];
  8.   numeroDeDigito++;
  9.   if(numeroDeDigito > sizeof ComunPuerto) numeroDeDigito = 0;
  10. }
  11.  
  12. void main(void)
  13. {
  14.  TRISC=0;                   // SALIDA
  15. TRISD=0;           // SALIDA
  16. TRISA=1; // ENTRADA
  17.  
  18.  
  19. PORTC=0;
  20. PORTD=0;  //Configuracion de pines
  21.  
  22.   while(1)
  23.   {
  24.     LecturaDeSensores();
  25.     if(RelojCorriendo == 1)
  26.     {
  27.         AumentarReloj();
  28.     }
  29.     MostrarEnDisplay();
  30.     Delay_ms(10);
  31.   }

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Botones de Inicio, Pausa y Reset en Cronometro con Pic16F877A
« Respuesta #3 en: 03 de Agosto de 2018, 16:39:38 »
El problema de que no lo podes parar es porque estas haciendo el reloj con un FOR. que es imparable, y que si lo llegas a "parar" es salir del for, y eso implica que comienze de 0 todo. Peor aun si es que tenes varios for anidados, por eso mismo te hice el programa que me pasas abajo..

En el programa que te pase, en una vuelta del while, no muestra todos los numeros de golpe, solo muestra 1 numero y cuando pasa de nuevo por el while, muestra el siguiente, como esto se produce cada 10ms ( que es el tiempo de tu reloj ) tambien cada ves que pasa por el while debo incrementar en 1. Si quiero pararlo, solo debo hacer que no incremente en 1, y eso es todo. que es la funcion de ese " if(RelojCorriendo == 1) ", yo al poner esa variable en 0 deja de incrementar mi reloj, pero sigue mostrando.

En fin:

Código: C
  1. // Variables relacionadas al funcionamiento
  2. short RelojCorriendo = 0;
  3. short Reloj[6] = {0,0,0,0,0,0};   // MM:SS:mm
  4. // Variables relacionadas a mostrar en el 7 segmento
  5. unsigned char numeroDeDigito = 0;
  6. short numero[]={192,249,164,176,153,146,130,248,128,144};  // Conversion binario a 7 semgntos
  7. unsigned char ComunPuerto[] = {0b00000001,0b00000010,0b00000100,0b00001000,0b00010000,0b00100000};
  8.  
  9. void Mostrar_Display(void)
  10. {
  11.   PORTD = 0;  // Apago los comunes
  12.   PORTC = numero[Reloj[numeroDeDigito]];
  13.   PORTD = ComunPuerto[numeroDeDigito];
  14.   numeroDeDigito++;
  15.   if(numeroDeDigito >= sizeof ComunPuerto) numeroDeDigito = 0;
  16. }
  17.  
  18. /*
  19. * Aca leo el sensor, uso uno solo, es para poder activarlo y pararlo con este sensor nomas
  20. */
  21.  
  22. void LecturaDeSensores()
  23. {
  24.   // variable para almacenar el estado de la ultima ves que entro a este punto
  25.   // el static hace que por mas que salga de la funcion, se siga manteniendo la variable
  26.   static short anteriorestado = 0;
  27.  
  28.   if((PORTA.RA0 == 1) && (anteriorestado == 0))  // Flanco positivo nomas, esto es para que al entrar cada 10ms aca, no se produzca la parada y arranque muchas veces.
  29.   {
  30.     RelojCorriendo ^= 1;              // XOR con 1
  31.   }
  32.  
  33.   anteriorestado = PORTA.RA0;
  34. }
  35.  
  36. /*
  37. * Incremento el menor numero y luego arreglo todos los que se pasaron.
  38. */
  39.  
  40. void AumentarReloj()
  41. {
  42.   Reloj[5]++;
  43.   if(Reloj[5] > 9) { Reloj[4]++; Reloj[5] = 0; }
  44.   if(Reloj[4] > 9) { Reloj[3]++; Reloj[4] = 0; }
  45.   if(Reloj[3] > 9) { Reloj[2]++; Reloj[3] = 0; }
  46.   if(Reloj[2] > 5) { Reloj[1]++; Reloj[2] = 0; }
  47.   if(Reloj[1] > 9) { Reloj[0]++; Reloj[1] = 0; }
  48.   if(Reloj[0] > 5) { Reloj[0] = 0; }
  49. }
  50.  
  51.  
  52. /*
  53. *   Mi main, con el funcionamiento del Timer
  54. */
  55.  
  56. void main(void)
  57. {
  58.   TRISC=0;                   // SALIDA
  59.   TRISD=0;           // SALIDA
  60.   TRISA=1; // ENTRADA
  61.  
  62.  
  63.   PORTC=0;
  64.   PORTD=0;  //Configuracion de pines
  65.  
  66.   while(1)
  67.   {
  68.     LecturaDeSensores();
  69.     if(RelojCorriendo == 1)
  70.     {
  71.         AumentarReloj();
  72.     }
  73.     MostrarEnDisplay();
  74.     Delay_ms(10);
  75.   }
  76. }

Si tenes alguna duda de porque hago alguna cosa en el codigo, o como funciona cierta parte, pregunta.

Lo importante aca es que las funciones NUNCA pero NUNCA se bloquean, es decir que entran y salen, no hay nada que los detenga en un punto.
Y eso hace que el delay_ms sea la funcion que me defina el tiempo entre cada incremento y muestra en el display.

PD: Si lo ves en el simulador, seguramente debas bajar el tiempo o comentarlo ( me refiero al delay del while) ya que en al simulacion es todo mas lento.

Desconectado JM89

  • PIC10
  • *
  • Mensajes: 3
Re:Botones de Inicio, Pausa y Reset en Cronometro con Pic16F877A
« Respuesta #4 en: 03 de Agosto de 2018, 19:34:32 »
El problema de que no lo podes parar es porque estas haciendo el reloj con un FOR. que es imparable, y que si lo llegas a "parar" es salir del for, y eso implica que comienze de 0 todo. Peor aun si es que tenes varios for anidados, por eso mismo te hice el programa que me pasas abajo...

Killer de nuevo muchas gracias por toda la ayuda que me estas prestando, pasé este codigo y compilé pero no arranca en proteus,, al hacer click en el pulsador (Que se reemplazará por un QRD1114 el conteo no se inicia, puedes indicarme donde puede estar el error y yo intento solucionarlo porfavor?

Saludos!!

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Botones de Inicio, Pausa y Reset en Cronometro con Pic16F877A
« Respuesta #5 en: 03 de Agosto de 2018, 20:58:10 »
Acabo de probar el codigo, y el codigo funciona correctamente.  Y cambiando "MostrarEnDisplay" que no coincidia el nombre con la funcion, todo funciona bien, le comento el delay que seguro sea ese el problema:

Código: C
  1. // Variables relacionadas al funcionamiento
  2. short RelojCorriendo = 0;
  3. short Reloj[6] = {0,0,0,0,0,0};   // MM:SS:mm
  4. // Variables relacionadas a mostrar en el 7 segmento
  5. unsigned char numeroDeDigito = 0;
  6. short numero[]={192,249,164,176,153,146,130,248,128,144};  // Conversion binario a 7 semgntos
  7. unsigned char ComunPuerto[] = {0b00000001,0b00000010,0b00000100,0b00001000,0b00010000,0b00100000};
  8.  
  9. void MostrarEnDisplay(void)
  10. {
  11.   PORTD = 0;  // Apago los comunes
  12.   PORTC = numero[Reloj[numeroDeDigito]];
  13.   PORTD = ComunPuerto[numeroDeDigito];
  14.   numeroDeDigito++;
  15.   if(numeroDeDigito >= sizeof ComunPuerto) numeroDeDigito = 0;
  16. }
  17.  
  18. /*
  19. * Aca leo el sensor, uso uno solo, es para poder activarlo y pararlo con este sensor nomas
  20. */
  21.  
  22. void LecturaDeSensores()
  23. {
  24.   // variable para almacenar el estado de la ultima ves que entro a este punto
  25.   // el static hace que por mas que salga de la funcion, se siga manteniendo la variable
  26.   static short anteriorestado = 0;
  27.  
  28.   if((PORTA.RA0 == 1) && (anteriorestado == 0))  // Flanco positivo nomas, esto es para que al entrar cada 10ms aca, no se produzca la parada y arranque muchas veces.
  29.   {
  30.     RelojCorriendo ^= 1;              // XOR con 1
  31.   }
  32.  
  33.   anteriorestado = PORTA.RA0;
  34. }
  35.  
  36. /*
  37. * Incremento el menor numero y luego arreglo todos los que se pasaron.
  38. */
  39.  
  40. void AumentarReloj()
  41. {
  42.   Reloj[5]++;
  43.   if(Reloj[5] > 9) { Reloj[4]++; Reloj[5] = 0; }
  44.   if(Reloj[4] > 9) { Reloj[3]++; Reloj[4] = 0; }
  45.   if(Reloj[3] > 9) { Reloj[2]++; Reloj[3] = 0; }
  46.   if(Reloj[2] > 5) { Reloj[1]++; Reloj[2] = 0; }
  47.   if(Reloj[1] > 9) { Reloj[0]++; Reloj[1] = 0; }
  48.   if(Reloj[0] > 5) { Reloj[0] = 0; }
  49. }
  50.  
  51.  
  52. /*
  53. *   Mi main, con el funcionamiento del Timer
  54. */
  55.  
  56. void main(void)
  57. {
  58.   TRISC=0;                   // SALIDA
  59.   TRISD=0;           // SALIDA
  60.   TRISA=1; // ENTRADA
  61.  
  62.  
  63.   PORTC=0;
  64.   PORTD=0;  //Configuracion de pines
  65.  
  66.   while(1)
  67.   {
  68.     LecturaDeSensores();
  69.     if(RelojCorriendo == 1)
  70.     {
  71.         AumentarReloj();
  72.     }
  73.     MostrarEnDisplay();
  74.     //Delay_ms(10);
  75.   }
  76. }

Pero en fisico vas a tener que agregarlo si o si, y que sea de 10ms


 

anything