Contador descendente con PIC16F877A

Hola amigos!

Me pongo en contacto con ustedes para pedirles un poco de luz :p

Necesito hacer un proyecto para un paintball

Quiero que tenga dos cosas:

Por un lado un contador regresivo de 4 bcd que cuente minutos y segundos que sea programable en los minutos y segundos mediante pulsadores. He encontrado ejemplos con 16f84A y un decoder pero no se si directamente 4 bcd se pueden conectar diirectamente al 16F877 y emplear el mismo codigo que con el proyecto del 16F84A y que me quede un puerto libre para lo siguiente:

quiero simular un juego de policias y ladrones, quiero que cogiendo una entrada del pic16f877 vallan a sus pines unos cables que aleatoriamente se configure para cuando tenga que cortarlos si no es la entrada aleatoria aumente la velocidad de contaje o dispare un buzzer.

Es decir: Tengo 8 cables que van desde VCC hasta el puerto C. Cuando tengan que desconectar el circuito si cortan el cable que esta como entrada, se desconecta el temporizador. En caso contrario si cortaran el cable que no esta configurado como entrada aumentara la velocidad o disparar un buzzer.

Veo varias cosas que no se como despejarlas (programo en basic)

Por un lado si genero un numero aleatorio de 8 bits como puedo conseguir que solo contenga un UNICO 0 y el resto siete 1 pero que ese UNICO 0 sea aleatorio entre los 8 bits cada vez que se le de al pulsador de start

Supongo que la solucion seria trabajar poniendo todo como entradas (TRISC=%11111111) y un bucle que compare el estado de las entradas que mientras no corten un cable seran todas 1 al estar en VCC.

Pero encuentro que en la comparacion fallaria porque mientras no corten un cable siempre sera diferente al numero aleatorio y por tanto sonaria el buzze...

Como creen ustedes que se podria hacer esa comparacion para que solo comparara en caso de que un cable hubiera sido cortado? Con un pulsador? es decir antes de cortar que pulse el boton y corte un cable y realice la comparacion? habria alguna manera de hacerlo de manera automatica?

Y para hacerlo mas interesante se podria hacer que tengan dos oportunidades es decir que la primera comparacion si han fallado aumente la velocidad de contaje y en un segundo intento si vuelven a fallar que salte el buzz (Todo esto sin cambiar el numero aleatorio que le hemos dado al principio)

Es un poco complicador pero no quiero que me lo resuelvan del todo sino me den alguna ayuda en el tema del comparador y si es viable poder ponerle directamente los 4 bcd + pulsadores de control (1 start, 1 stop y reset) + la entrada de 8 cables los cuales tienen que cortar.

Muchas gracias de antemano

Saludos
 
El tema de los aleatorios siempre es complicado en un micro... la salida simple es cargar una tabla aleatoria en la memoria del micro e ir seleccionando un dato a la vez... el problema es que una vez agotada la tabla los valores se reptiten...

Tambien puedes hacer una cuenta muy rapida durante el tiempo que se mantenga pulsado un boton, como todos los tiempos seran diferentes el resultado seria azarozo, incluso puedes meter esa cuenta a la tabla de busqueda para hacerlo aun menos secuencial

Al principio del juego puedes "armar" el circuito presionando el boton, el valor generado se guarda en memoria y despues se compararia contra el cable que corten... si coinciden entonces se desarma, de lo contrario se incrementa el tiempo de cuenta...
 
Que deberia entonces... almacenar los 8 valores y generar un direccionamienti por ejemplo en la eprom del pic y que sea ese direccionamiento el que sea aleatorio?? como se podria hcer en basic que ese direccionamiento fuera aleatorio?

Lo que me interesa tambien es el tema de los 4 bcd si hay akguna manera de conectarlos al pic o adaptar el esquematico del pic 16f84A de pablin al pic

http://www.pablin.com.ar/electron/circuito/mc/timer/index.htm

utilizando el mismo decoder etc...

En el tema del pic veis factible en vez de hacerlo con un16f877 hacerlo con un 16f84?
 
El uso del 84 o del 877 ya es personal, ambos PICs pueden manejar toda esa informacion, pero algunas veces se usa el grande por tener mas pines que se pueden destinar a otra cosa... en el buscador del foro coloca "multiplexado display" o "timer PIC" y encontraras mucha informacion al respecto de como implementar los displays, en realidad es muy facil

En cuanto a la parte de la generacion de un numero aletorio tambien es simple:

Primero cargas en EEPROM una tabla con varios numeros aleatorios, posiblemente unos 50 o mas valores, y si quieres que sean del tipo que vas a usar... osea todos en uno pero cambiando al azar el cero que necesitas

Despues esperas a que se presione un boton, eso iniciara un contador lo mas velozmente posible, y que debe de contar todas las localidades de la EEPROM, ese contador lo detendras cuando el PIC detecte que soltaron el boton, como este tiempo de presionado siempre es diferente, se tendra el componente de azar que necesitamos

Con ese valor del contador vas a la tabla de busqueda, obtienes el dato (que se usara como comparativo), y comienzas el juego... si la persona rompe un cable equivocado entonces disminuyes el tiempo de contado, si se rompe el cable correcto entonces se detiene el contador...
 
Última edición por un moderador:
Bueno pues tengo un pequeño problema y no se como hacerlo.
Seguro que esta mas que explicado pero no veo donde.
Estoy intentando hacer un contador que vaya desde 2 hora asta 00 horas, 00 minutos y 00 segundos y con el que hecho no consigo que cuando llegue a 00:00:00 se pare, sigue contando hacia atras y de hay no salgo, he probado muchas cosas pero no hacierto con la funcion que hace que se pare, tambien quiero que salga de esa forma "00:00:00", sale bien pero no aparece el 0 delante, me explico cuando esta en 0 horas que aparezca 00 y en minutos y segundos lo mismo, cuando va por un digito solo aparece un digito y no aparece el 0 delante, esto no es un problema pero me gustaria saber como se hace.
Si alguien me hecha un cable pues gracias.
 

Adjuntos

  • contador regresivo.rar
    25.9 KB · Visitas: 28
Para que salga los números con dos dígitos, debes modificar el printf(), cambiando los %d por %02d.

Eso lo que hace es indicar a printf() que en esa posición va a ir un entero de dos dígitos con relleno de cero (por la izquierda).

En cuanto a la forma de ir contando hacia atrás, veo que no funciona: solo hay un bucle de 60 segundos. Debería haber tres controles para saber cuándo parar, decrementando las horas, minutos y segundos. Algo así:

PHP:
void main() { 
    lcd_init();
    lcd_putc("\f");

    do {
        lcd_gotoxy(5,2);
        printf(lcd_putc," %02d : %02d : %02d ",hor, min, seg); 

        delay_ms(1000);                      /* pasa el tiempo */

        if (seg == 0) {                      /* llegamos al final del minuto */
            seg = 60;                        /* reiniciamos segundero */

            if (min == 0) {                  /* llegamos al final de la hora */
                min = 60;                    /* reiniciamos minutero */

                hor--;                       /* una hora menos */
            }

            min--;                           /* un minuto menos */
        }

        seg--;                               /* un segundo menos */

    } while (hor >= 0);                      /* repetir mientras queden horas */
}
 
Última edición por un moderador:
Estoy intentando hacer un contador que vaya desde 2 horas hasta 00 horas, 00 minutos y 00 segundos y con el que hecho no consigo que cuando llegue a 00:00:00 se pare, sigue contando hacia atrás y de ahí no salgo.
He probado muchas cosas pero no acierto con la función que hace que se pare.
También quiero que salga de esta forma "00:00:00"
Hace un tiempo realicé este programa: Temporizador regresivo programable hasta 100 horas
De ese programa hice un extracto de la rutina de conteo descendente para que lo tomes como ejemplo.

Este programa no usa los timers del PIC, ya que no se requería de mucha precisión.

Espero te sirva.

Saludos.
 

Adjuntos

  • 16F877A Contador regresivo.rar
    54.6 KB · Visitas: 53
Para que salga los números con dos dígitos, debes modificar el printf(), cambiando los %d por %02d.

Gracias JoaquinFerrero, tienes mas razon que un santo y lo peor es que tengo un par de programas que despues de mirarlos los tengo como tu dices y no me acordaba de que es asi, uno se empecina y no ve mas alla de las narices jejeje.
Ya me gustaria soltarme como vosotros con C pero me da que para mi tiene que ser poco.
Probare hacerlo como tu me indicas, ya te cuento.



Hace un tiempo realicé este programa: Temporizador regresivo programable hasta 100 horas
De ese programa hice un extracto de la rutina de conteo descendente para que lo tomes como ejemplo.

Este programa no usa los timers del PIC, ya que no se requería de mucha precisión.

Espero te sirva.

Saludos.
(y) lo he descargado y lo estoy mirando, ya te digo que estoy disfrutando un monton, lo bueno que tienes campeon es que te gusta explicar cada funcion, todo lo mejor que puedes, y eso para gente como yo que me gusta entender el por que de las cosas esta muy bien, muchas gracias.
 
Última edición:
joaquinferrero con tu codigo, que te agradezco, tal y como esta puesto, solo cuenta segundos hacia atras, me permitido hacer unas modificaciones, que espero no te moleste, y entonces se para en 01 : 01 : 01 y de hay no sigue bajando y no le veo el por que.
Asi es como lo he dejado:
do {
lcd_gotoxy(5,2);
printf(lcd_putc," %02d : %02d : %02d ",hor, min, seg);
delay_ms(1000); /* pasa el tiempo */
seg--;


/* Contador regresivo */
if (seg == 0) {
seg = 59;
min-=1;}

if (min == 0) {
seg = 59;
min = 59;
hor-=1;}


} while ( hor>0 && min>0 && seg>0);
 
Si señor eso es lo que buscaba, "GRACIAS", pegale un vistazo si te apetece al de D@rkbytes, que esta muy bien, CREO YO, estoy comprendiendo conceptos pero uffff, en ese hay mucha tela que aprender, pero como tiempo tengo jejeje, una cosa los cabezas pensantes como vosotros no os teneis que morir nunca, gracias a vosotros aprendo a pasos agigantados ya que copiar es lo mas facil del mundo ahora aprender eso es otra cosa, otra cosa te quiero comentar, a lo mejor es el compilador que tengo yo que es anticuado, te has dado cuenta que en tu codigo la cuenta termina en 00 : 00 : 01 segundo?, por lo demas perfecto.
Un saludo.
 
Hola Joaquin me tienes que decir que compilador usas y que version, te digo esto por que lo he probado con el mio y continua contando, cuando llega a 0, y empieza a -1 hora y asi hacia atras.
De la otra forma que pusiste al llegar a 00:00:01 se paraba, de hay mi pregunta con el compilador.
Por ultimo que frecuencia pones para compilar?.
Lo de comentar es perfecto, aunque como este codigo es sencillo lo entiendo todo, pero ayuda mucho.
 
He usado el gcc, el que viene con Linux. Y es extraño que te pase eso. A mi me salen exactamente 7201 líneas:
02 : 00 : 00
01 : 59 : 59
01 : 59 : 58
01 : 59 : 57
01 : 59 : 56
01 : 59 : 55
01 : 59 : 54
...
00 : 00 : 05
00 : 00 : 04
00 : 00 : 03
00 : 00 : 02
00 : 00 : 01
00 : 00 : 00
Este es el programa:
PHP:
#include <stdio.h>

int hor = 2;
int min = 0;
int seg = 0;

void main() { 

    do {
        printf(" %02d : %02d : %02d\n",hor, min, seg); 

        //delay_ms(1000);        /* pasa el tiempo */

        /* Contador regresivo */
        if (seg == 0) {
            seg = 60;
            if (min == 0) {
                min = 60;
                hor--;
            }
            min--;
        }
        seg--;

    } while (hor >= 0);
}
y lo compilo con la orden cc -o kk kk.c (no muy original :) )

Debemos tener distinto código, porque el while (hor >= 0) impide ver ninguna hora con valores negativos...
 
Última edición por un moderador:
Pues tal vez puede que sea ese el problema, yo tengo el compilador de CCs PCW y tal vez este anticuada la version, voy a mirar de actualizar la version y ya te contare.
Se me olvidaba uso XP.
 
Última edición:
Es puro lenguaje C estándar, así que debería funcionar con cualquier compilador conocido.
 
Ya tengo actualizado el compilador y sigue quedandose en 00:00:01 segundo, pero dentro de lo que cabe me sirve para lo que necesito, de todas formas voy a formatear el portatil que me hace muchas cosas raras y me salen cukis cokos cakos y de todo, jeje. gracias de todas formas.
Un par de preguntas para D@rkbytes, en el programa de timer, que ya lo he mirado y remirado, que me indicastes hay unos conceptos que me gustaria me expliques.
en el programa hay una funcion que pone:
"lcd_cursor_on(1); //enciende el cursor con parpadeo", pues bien yo esta funcion no la habia visto nunca, ¿como la sacas? o ¿de donde las sacado?,
y la otra pregunta, que puede ser ignorancia por no haber leido mas, como se decide que una variable sea de int8, int16, int32 o mas grande
 
Sería interesante ver tu código para ver por qué sigue saliendo el '00:00:01'.

La decisión de elegir una variable entera es sabiendo el rango que puede almacenar.

Por ejemplo, un int8 podrá almacenar valores entre -128 y +127. Un unsigned int8, entre 0 y 255. int16 son dos bytes e int32, 4.
 
Un par de preguntas para D@rkbytes.
En el programa de timer, que ya lo he mirado y remirado, hay unos conceptos que me gustaría me expliques.
En el programa hay una función que pone:
"lcd_cursor_on(1); //enciende el cursor con parpadeo", pues bien yo esta función no la había visto nunca.
¿Cómo la sacas? o ¿De dónde la has sacado?
Esa función viene desde hace algún tiempo en las nuevas versiones de la librería LCD.C de CCS
No recuerdo muy bien desde que versión la pusieron, pero me parece que fue por la v4.140

En este momento uso la v5.027 y tiene bastantes mejoras.

Saludos.
 
Sería interesante ver tu código para ver por qué sigue saliendo el '00:00:01'.

Lo he hecho con do while,como tu lo has puesto, y con while, tambien lo he hecho solo con 2 minutos para acortar tiempo.

Con Do While:
PHP:
#include <16F877A.h>
#fuses XT
#fuses NOWDT,PUT,NOBROWNOUT,NOLVP
#use delay(clock= 1MHz)
#include <stdio.h>
#include <time.h> 
#include <lcd420-d.c>

  int hor=0;
  int min=2;
  int seg=0;
  
 void main()  {
    lcd_init();
    lcd_putc("\f"); 
    do {
        lcd_gotoxy(5,2);
        printf(lcd_putc," %02d : %02d : %02d ",hor, min, seg); 
        delay_ms(1000);                   
        if (seg == 0){
            seg = 60;           
           if (min == 0){
                min = 60;
                hor--;
                 }
              min--;
            }        
        seg--;        
         if((min==1)&&(seg==0))
            {
        output_high(pin_c0);
            }
    } while (hor + min + seg >0 );    
}

Con While:
PHP:
#include <16F877A.h>
#fuses XT
#fuses NOWDT,PUT,NOBROWNOUT,NOLVP
#use delay(clock= 1MHz)
#include <stdio.h>
#include <time.h> 
#include <lcd420-d.c>

  int hor=0;
  int min=2;
  int seg=0;

 void main()  { 
 lcd_init();
 lcd_putc("\f");   
  while (seg + min + hor >0) //Mientras sea superior a 0 se ejecuta
      {
    lcd_gotoxy(5,2);   // imprimimos los datos desde columna-5, fila-2
        printf(lcd_putc," %02d : %02d : %02d",hor, min, seg); 
        delay_ms(1000);                     
        if (seg == 0) { // si segundos llega a 0
            seg = 60;   // vuelve otra vez a 60 segundos           
            if (min == 0) //si minutos llega a 0 
                 {
                min = 60; //vuelve otra vez a 60 minutos
               hor--;
                 }
            min--;
          }
        seg--;       
        if((min==1) && (seg==0))
         {
        output_high(pin_c0);
         }
       }     
     }



La decisión de elegir una variable entera es sabiendo el rango que puede almacenar.

Por ejemplo, un int8 podrá almacenar valores entre -128 y +127. Un unsigned int8, entre 0 y 255. int16 son dos bytes e int32, 4.
Eso lo entiendo, lo que yo pregunto es como tomais la decision de que la variable a usar para cierta funcion es de un tamaño u otro.



Esa función viene desde hace algún tiempo en las nuevas versiones de la librería LCD.C de CCS
No recuerdo muy bien desde que versión la pusieron, pero me parece que fue por la v4.140

En este momento uso la v5.027 y tiene bastantes mejoras.

Saludos.

Gracias D@rkbytes, le hechare un vistazo a las mejoras.
 
Última edición por un moderador:
La condición del while() está mal, y es la razón por la cual no te pinta el momento cero.

Fíjate bien en mi código, que la condición es distinta.

La decisión de elegir un tamaño de variable u otro viene determinada por

  • el resultado de las funciones cuyos resultados queremos almacenar
  • resultado de operaciones matemáticas intermedias: elegir aquel tamaño que sabemos que puede albergar todos los casos posibles
  • por exigencia de llamadas a funciones. Casi todas las funciones indican el tipo de variable que hay que poner en sus argumentos.
 
Última edición por un moderador:
te explico, si al while o al do while lo termino en >=0 como lo tienes puesto no se para la cuenta regresiva, si lo termino en >0 entonces se para como ya te dicho 00:00:01, he cambiado el compilador y he formateado el ordenador y nada, mas de lo mismo, pero he creado una funcion añadida como prueba, esta claro que a lo mejor no es muy ortodoso pero es lo que se me ocurre y para lo que lo quiero me sirve de momento, es esta:
Código:
void main() 
   {
    lcd_init();
    lcd_putc("\f");
 
    do {
        lcd_gotoxy(5,2);
        printf(lcd_putc," %02d : %02d : %02d ",hor, min, seg); 

        delay_ms(1000);        
        if (seg == 0){
            seg = 60;
           
           if (min == 0){
                min = 60;
                hor--;
                 }
              min--;
            }
          seg--;
        
         if((min==1)&&(seg==0))
            {
        output_high(pin_c0);
            }

    } while (hor+min+seg>0);
    lcd_gotoxy(5,2);
        printf(lcd_putc," 00 : 00 : 00 "); 
}
 
Atrás
Arriba