# Contador 0 a 99 con PIC y displays de 7 segmentos



## Gustavo.gmb (Nov 30, 2013)

Buenas a todos, quería aportarles este humilde trabajillo que hice recientemente, el cual se puede aplicar a cualquier proyecto que necesite un contador de 0 a 99 para visualizar algo.

Les dejo todos los archivos necesarios, no es la gran cosa, pero estoy seguro que a alguien le servirá


----------



## solaris8 (Nov 30, 2013)

no se achique amigo, todo aporte es bueno y seguramente ayudara a otro, a realizar su proyecto.....
buen trabajo!!!


----------



## pigma (Nov 30, 2013)

No es humilde porque tambien cuenta. Muchas gracias por compartir!


----------



## jamesoro (Dic 1, 2013)

pues gracias men, pues yo hace como 8 años hice un programita muy pequeño para ayudar con eso de los pic y aun me dan gracias y eso que pense que solo yo lo usaria


----------



## juliocesar71 (Nov 3, 2015)

Buen día.

Estoy diseñando un contador 0-99 en BASIC ascendente y descendente con display y he logrado un contador hasta 9, ascendente.
No sé cómo implementar las funciones para lograr un contador hasta 99.

Adjunto diagrama y el código. Su interés es muy importante a fin de culminar este proyecto. 

Progama en PicBasic Pro:


```
define Osc 4        ' Define el oscilador para un cristal de 4 Mhz.
        
        @device mclr_off 'apago MCLR
        trisa = %11110000
        trisb = %11110000 ' hace salidas solo los bits mas bajos
        numero var byte
        bot var porta.0
        flag var bit
        encerar:
        numero = 0
        display:
        portb = numero
        if bot = 0 then aumentar
        pause 80
        flag = 0
        goto display
        aumentar:
        if flag = 1 then goto display
        flag = 1
        if numero = 9 then encerar
        numero = numero + 1
        goto display
        end
```


----------



## D@rkbytes (Nov 3, 2015)

Necesitas crear lo siguiente:
Crear una variable del tipo Byte 0 a 255. (Para el contador)
Otras dos variables del tipo Byte. (Una para las decenas y otra para las unidades)
Dos rutinas, una para incrementar y otra para decrementar la variable.
Una rutina para multiplexar los displays. Te recomiendo usar interrupción por desborde del Timer 0.

El procedimiento:
En el bucle principal del programa verificarás el estado de los pulsadores.
Tendrás un limite y un desborde, el tope será al incrementar y el desborde al decrementar la variable.
Cuando incrementas, no debes permitir que la variable pase de 99
Y al decrementar, no debes permitir que ocurra el desborde, porque al bajar de 0 la variable retornará a 255.

Posteriormente separas la variable "Contador" en decenas y unidades usando la instrucción "DIG"
A continuación realizas la mutiplexación de los displays. (No importando el orden para mostrar los dígitos)
Es decir, no tiene importancia si muestras primero las unidades y luego las decenas.
Lo que si es importante es el lugar donde se colocan. (Decenas en el display del lado izquierdo y unidades del lado derecho)

Espero sepas como se realiza el sistema multiplex en displays de 7 segmentos.
Este proceso lo harás durante el desborde del Timer 0, dando un corto tiempo de encendido a cada display para mostrar los dígitos.

No es complicado y el código en Basic tampoco lo es.

Nota:
Si usas la instrucción "LookUp" te puedes ahorrar el decodificador 7447.
Con esta instrucción puedes ir tomando los valores de las decenas y las unidades para obtener los bits de encendido de los segmentos de los displays.
Con esto se usa una tabla de valores para cada tipo de display. (Ánodo o cátodo común)
El valor obtenido lo mandas al puerto B y así compactas el circuito. La desventaja es que se usan 7 pines.


----------



## dogflu66 (Nov 4, 2015)

Aquí te dejo la función que te ha dicho el compañero, si no usas funciones no importa, lo importante es la tabla  "LookUp". El primer byte de la tabla corresponde al cero y la correspondencia de los bit con los segmentos es la siguiente:
byte.0 = a
byte.1 = b
"
"
byte.6 = g
byte.7 = h

'Retorna valor: Byte
'Numero a mascara tipo digito display 7 segmentos
'numero = numero a procesar (0 a 9)
'_get7seg, retorna la mascara de los segmentos a activar
Function _get7seg(_numero As Byte) As Byte
	_get7seg = LookUp(0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x80), _numero
End Function

Si te decides a usar dígitos multiplexados los pasos para imprimir en el display son los siguientes:

Apagas dígitos.
Cargas el puerto con el nuevo valor a mostrar.
Iluminas el digito que corresponde.
Antes de realizar más cambios en el display esperar 1mSeg.
Repetir el proceso para el siguiente digito.


----------



## David paz (Sep 4, 2019)

Buenas tardes necesito ayuda con este contador, resulta que solo encienden los display cuando inicia el conteo ascendente, alguien que por favor lo modifique para que enciendan desde el principio. y ademas es posible migrarlo a un 16f628A?
Muchas gracias


----------



## D@rkbytes (Sep 4, 2019)

David paz dijo:


> resulta que solo encienden los display cuando inicia el conteo ascendente, alguien que por favor lo modifique para que enciendan desde el principio


Lo único que tienes que hacer es colocar las siguientes instrucciones en el main después del cambio de banco:

```
bcf    STATUS,5
    movlw    3Fh    ; b'00111111' (Número 0)
    movwf    PORTB
    movwf    PORTC
    ;clrf    PB
    ;clrf    PC
    clrf    conteo
```
Nota que comenté clrf PB y clrf PC para que el agregado posterior se cumpla.
PB es igual que PORTB y PC es igual que PORTC, así que no tiene caso renombrar un registro cuando se usa la librería del PIC en cuestión.
Ahorrar unas pocas letras en nombres de variables es cosa de flojos.
Además, PC es el nombre de un registro y puede causar confusiones. (PC = Program Counter)
Por suerte en este PIC se usa PCL y PCH, si no, grave error.
PCL = Program Counter Low Byte y PCH = Program Counter High Byte, ya que el registro es de 13 bits.


David paz dijo:


> ¿Es posible migrarlo a un 16F628A?


Sí, por supuesto, pero con decodificadores de BCD a 7 segmentos porque faltarían bits en el puerto A.


----------



## David paz (Sep 5, 2019)

Gracias por contestar, le agradezco la ayuda después de probar en varias posiciones pues no sabia en donde era pues soy nivel 000  inicia prendido en ceros.
Muchas gracias
bcf    STATUS,5
    clrf    conteo
    movlw    3Fh    ; b'00111111' (Número 0)
    movwf    PORTB
    movwf    PORTC

************************
LE PUSE UN RESET  Y FUNCIONA


----------



## David paz (Sep 5, 2019)

Buenas tardes,  estoy usando un pic 16f877a y  pickit2 para poder grabarlo, consigo leerlo y grabarlo correctamente pero al momento de ponerlo a funcionar no hace nada  lo vuelvo a colocar en el pickit y aparece en blanco, eso solo pasa con es pic pues los demás funcionan sin problema he grabado 16f628-16f84a.
cual podrá ser el error.


----------



## D@rkbytes (Sep 5, 2019)

Los valores de las palabras de configuración que se muestran no son valores válidos para el PIC16F877A
En la verificación se muestra 2F82 y en lectura 2FCF
Ningún tipo de bits seleccionados en la palabra de configuración debe empezar con 2, solo con 1 o 3.

Si estás usando la misma palabra de configuración del programa que subiste...
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC, el valor para esta configuración debe ser 3FF1
Si obtienes un valor diferente a ese después de la verificación, entonces el microcontrolador está dañado.


----------



## David paz (Sep 5, 2019)

Las dos imágenes son del mismo microcontrolador, y  con 3 diferentes pasa lo mismo.


----------



## D@rkbytes (Sep 5, 2019)

Cambia de programador.
Y no me refiero a que el PICkit 2 sea malo, sino a que puede estar dañado.


----------



## Fernando Caicedo (Nov 25, 2019)

Buenas tardes*. D*isculpen*, *tengo un problema con el contador al hacer en descendente*,* ya que al tratar de invertir el  código reducido usado*,* no me funcion*ó**.
¿*Por favor*, *podrían ayudarme*?*
*A*quí les dejo el código que hice :

```
#include <16f628a.h>

#fuses xt
#fuses put
#fuses nowdt
#fuses noprotect
#fuses nomclr

#use delay(internal=4M)

#use delay(clock=4Mhz)
#use standard_io(b)
#use standard_io(a)
int display[10]={0b0000001, 0b1001111, 0b0010010, 0b0000110,0b1001100 ,0b0100100, 0b0100000, 0b0001111, 0b000000, 0b0000100};

void main()
{
int unidad= 0;
int decena= 0;
int tiempo= 5;

output_b(0b00000000);

while(1)
{
if(input(pin_a2)== 1)
   {
   output_a(0b10);
   output_b(display[unidad]);
   delay_ms(tiempo);
   output_a(0b01);
   output_b(display[decena]);
   delay_ms(tiempo);
   }
   else
   {
   delay_ms(5);
   output_a(0b10);
   output_b(display[unidad]);
   output_b(display[unidad]);
   delay_ms(tiempo);
   output_a(0b01);
   output_b(display[decena]);
   delay_ms(tiempo);
 

      if (input(pin_a2)==1)
      {
      unidad++;

      if (unidad>9)
      {
      decena++;
      unidad=0;

      }

    
      if(decena>9)
      {
      decena=0;
      unidad=0;
      }
      }
   }
}
}
```


----------



## D@rkbytes (Nov 25, 2019)

Fernando Caicedo dijo:


> al tratar de invertir el código reducido usado*,* no me funcion*ó**.*


¿Qué es lo que no funciona?
¿Cómo se supone que debe funcionar?
¿Cuál es el esquema?
Si realizaste una simulación, por favor adjúntala dentro de un archivo comprimido.


----------



## Fernando Caicedo (Nov 25, 2019)

osea trate de hacer que regrese desentenderme pero no me funciono


----------



## D@rkbytes (Nov 25, 2019)

¿Y qué pasaría si en lugar de sumar, restas?


----------



## Fernando Caicedo (Nov 25, 2019)

D@rkbytes dijo:


> ¿Y qué pasaría si en lugar de sumar, restas?



como realizo eso disculpe ?


----------



## D@rkbytes (Nov 25, 2019)

En lugar de unidad++; sería unidad--;
Lo mismo con las decenas.


----------



## Dr. Zoidberg (Nov 25, 2019)

Por suerte el programa está en C. No me quiero imaginar si estuviera en assembler....


----------



## D@rkbytes (Nov 25, 2019)

Por lo que veo va a existir un problema de contención lógica con el pulsador al estar en el puerto A y este mismo usado como salida.
Ya que se usó #use standard_io(a) se debió haber hecho uso del set_tris_a(x); para definir entradas y salidas.

Edit: Cambiar #use standar_io(a) por #use fast_io(a) y en el main declarar: set_tris_a(0b00000100);


----------



## Fernando Caicedo (Nov 25, 2019)

En lugar de unidad++; sería unidad--;
Lo mismo con las decenas.


  asi??

      if (input(pin_a3)==1)
      {
      unidad--;
      if (unidad>9)
      {
      decena--;
      unidad=0;
      }

      if(decena>9)
      {
      decena=0;
      unidad=0;
      }
      }


----------



## D@rkbytes (Nov 25, 2019)

No, porque ahora estás restando y ya no se debe comparar con > 9, sino con == 0
De igual forma, ahora las variables se deben inicializar en 9 porque habrá un decremento.

Sería así:

```
#include <16F628A.h>

#use delay(INTERNAL = 4 MHz)
#use fast_io(A)

int display[10] = {0b0000001, 0b1001111, 0b0010010, 0b0000110, 0b1001100,
                   0b0100100, 0b0100000, 0b0001111, 0b000000, 0b0000100};

void main (void)
{
    int unidad = 9;
    int decena = 9;
    int16 tiempo = 5;
 
    set_tris_a(0b00000100);

    while(TRUE)
    {
        if(input_state(PIN_A2))
        {
            output_a(0b10);
            output_b(display[unidad]);
            delay_ms(tiempo);
            output_a(0b01);
            output_b(display[decena]);
            delay_ms(tiempo);
        }
        else
        {
            delay_ms(tiempo);
            output_a(0b10);
            output_b(display[unidad]);
            delay_ms(tiempo);
            output_a(0b01);
            output_b(display[decena]);
            delay_ms(tiempo);
 
            if (input_state(PIN_A2))
            {
                unidad --;
         
                if (unidad == 0)
                {
                    decena --;
                    unidad = 9;
                }
             
                if (decena == 0)
                {
                    decena = 9;
                    unidad = 9;
                }
            }
        }
    }
}
```
Corrijo la comparación porque al parecer al llegar a 10 regresaría a 99
Quedaría de esta forma:

```
if (input_state(PIN_A2))
            {
                unidad --;
          
                if (unidad > 9)
                {
                    decena --;
                    unidad = 9;
                }
              
                if (decena > 9)
                {
                    decena = 9;
                    unidad = 9;
                }
            }
```


----------



## Fernando Caicedo (Nov 25, 2019)

Muchisimas gracias


----------



## D@rkbytes (Nov 26, 2019)

Para comprobar que el programa funcionara correctamente decidí realizar la simulación.
La adjunto con el programa modificado por si a alguien más le pueda servir.


----------



## Afelio (May 23, 2020)

Qué tal, tengo un circuito que funciona como un contador ascendente de 0 a 99 con dos display 7 segmentos, teniendo un push botton como incrementador y otro como reset, el problema que tengo es que mi circuito físico no funciona correctamente, al probarlo en Proteus 8 funciona correctamente o como incrementador.

El problema que detecto según mi perspectiva es que hay algún cable que no esta conectado a tierra por que presenta ciertos cortos que hacen que el display se apague o prenda de forma aleatoria, incluso cuando pongo mis dedos en el pic, los display prenden.

Este problema ya lo había presentado con otro circuito, se arreglo conectando los puertos de entrada que no ocupaba a tierra.

Mis puertos de entrada son el PORTC

Mis puertos de salida son PORTA, PORTB.

Adjunto mas imágenes al respecto.

Si se requiere más información háganme saber, gracias.


----------



## D@rkbytes (May 23, 2020)

Por el tipo de PIC, yo creo que el problema está en la palabra de configuración.



Afelio dijo:


> Si se requiere más información háganme saber, gracias.


Sí, el código.


----------



## el_patriarca (May 23, 2020)

Pon resistencias a los transistores. Y te recomiendo prolijidad


Y si, el código


----------



## Eduardo (May 23, 2020)

Por favor!    Meté resistencias de al menos 100ohms  para limitar la corriente en los segmentos.    

En los simuladores nada se quema, en el mundo real sí.


----------



## D@rkbytes (May 23, 2020)

En el protoboard se ven 7 resistencias de 330 Ohms, debe ser una por segmento porque el sistema es multiplex.


----------



## Eduardo (May 23, 2020)

Tenés razón.  Tal vez sea el color medio cambiado pero me parecen de 33ohms.


----------



## el_patriarca (May 23, 2020)

Creo que Vcc está conectado a los emisores de los 2n2222 y en la simulación está conectado a los colectores


----------



## D@rkbytes (May 23, 2020)

En dado caso que los transistores estuvieran bien conectados, sería mejor usar PNP e invertir la lógica de control.


----------



## Eduardo (May 23, 2020)

D@rkbytes dijo:


> En dado caso que los transistores estuvieran bien conectados, sería mejor usar PNP e invertir la lógica de control.


No creas,  en esa configuración el transistor no llega a saturar (no puede el pobre) pero esa caída de tensión no afecta porque estás sobrado y despues de todo, la parte que no se disipa en el transistor se disipará en las resistencias de los segmentos.  Además, si fueran muchos dígitos te ahorrás el espacio de las resistencias de base.


----------



## Afelio (May 23, 2020)

Eduardo dijo:


> Tenés razón.  Tal vez sea el color medio cambiado pero me parecen de 33ohms.


Aquí les dejo el código.
La palabra de configuración es una predeterminada que nos dieron para todos las prácticas en mi escuela, de hecho la he utilizado en anteriores prácticas y ha funcionado de forma correcta.

Las resistencias que conecté a los display son de 330 ohms.
Usé de manera invertida los transistores debido a que los display son ánodo común, por eso me conviene tenerlos conectados de esa forma.

Más dudas, háganme saber.

```
LIST P=18F4550
#INCLUDE <P18F4550.INC>

;Palabra de Configuración
;CONFIG1L dir 300000h 20
;CONFIG PLLDIV=1 ;
;CONFIG CPUDIV=OSC1_PLL2 ;CUANDO SE USA XTAL
  ;CONFIG USBDIV=2
  ;CONFIG1H dir 300001h 08
CONFIG FOSC=INTOSCIO_EC ;OSCILADOR INTERNO, RA6 COMO PIN, USB USA OSC EC
CONFIG FCMEN=OFF ;DESHABILITDO EL MONITOREO DEL RELOJ
CONFIG IESO=OFF
;CONFIG2L DIR 300002H 38
CONFIG PWRT=ON ;PWRT HABILITADO
CONFIG BOR=OFF ;BROWN OUT RESET DESHABILITADO
CONFIG BORV=3 ;RESET AL MINIMO VOLTAJE NO UTILZADO EN ESTE CASO
CONFIG VREGEN=ON ;REULADOR DE USB ENCENDIDO
;CONFIG2H DIR 300003H 1E
CONFIG WDT=OFF ;WATCH DOG DESHABILITADO
CONFIG WDTPS=32768 ;TIMER DEL WATCHDOG
;CONFIG3H DIR 300005H 81
CONFIG CCP2MX=ON ;CCP2 MULTIPLEXADAS CON RC1
CONFIG PBADEN=OFF ;PUERTO B PINES DEL 0 AL 4 ENTRADAS DIGITALES
CONFIG LPT1OSC=OFF ;TIMER1 CONFIURADO PARA OPERAR EN BAJA POTENCIA
CONFIG MCLRE=ON ;MASTER CLEAR HABILITADO
;CONFIG4L DIR 300006H 81
CONFIG STVREN=ON ;SI EL STACK SE LLENA CAUSE RESET
CONFIG LVP=OFF ;PROGRAMACIÒN EN BAJO VOLTAJE APAGADO
CONFIG ICPRT=OFF ;REGISTRO ICPORT DESHABILITADO
CONFIG XINST=OFF ;SET DE EXTENCION DE INSTRUCCIONES Y DIRECCIONAMIENTO INDEXADO DESHABILITADO
;CONFIG5L DIR 300008H 0F
CONFIG CP0=OFF ;LOS BLOQUES DEL CÒDIGO DE PROGRAMA
CONFIG CP1=OFF ;NO ESTAN PROTEGIDOS
CONFIG CP2=OFF
CONFIG CP3=OFF
;CONFIG5H DR 300009H C0
CONFIG CPB=OFF ;SECTOR BOOT NO ESTA PROTEGIDO
CONFIG CPD=OFF ;EEPROM N PROTEGIDA
;CONFIG6L DIR 30000AH 0F
CONFIG WRT0=OFF ;BLOQUES NO PROTEGIDOS CONTRA ESCRITURA
CONFIG WRT1=OFF
CONFIG WRT2=OFF
  CONFIG  WRT3=OFF
  ;CONFIG6H DIR 30000BH E0
CONFIG WRTC=OFF ;CONFIGURACION DE REGISTROS NO PROTEGIDO
CONFIG WRTB=OFF ;BLOQUE BOOTEBLE NO PROTEGIDO
  CONFIG  WRTD=OFF  ;EEPROMDE DATOS NO PROTGIDA
  ;CONFIG7L DIR 30000CH 0F
CONFIG EBTR0=OFF ;TABLAS DE LETURA NO PROTEGIDAS
CONFIG EBTR1=OFF
CONFIG EBTR2=OFF
  CONFIG  EBTR3=OFF
  ;CONFIG7H DIR 30000DH 40
CONFIG EBTRB=OFF ;TABLAS NO PROTEGIDAS

ORG 0X00

MOVLW 0XFF
MOVWF OSCCON

MOVLW 0X0F
MOVWF ADCON1

MOVLW 0X07
MOVWF CMCON

CBLOCK 0X00
UNIDAD
DECENA
CONTADOR
CONTADOR1
CONTADOR2
CONTADOR3
ENDC

; Entradas
#DEFINE BOTONI PORTC,RC0
#DEFINE BOTONR PORTC,RC1

MOVLW 0X7F
MOVWF TRISC

; Salidas
BCF TRISA,RA1
BCF TRISA,RA2
CLRF TRISB

RESETEO CLRF UNIDAD
CLRF DECENA
CALL LOOP
GOTO INICIO

INICIO CALL LOOP
BTFSS BOTONI
GOTO BOTONRESET
CICLO CALL LOOP
CALL RETARDO2
BTFSC BOTONI
GOTO CICLO
CALL LOOP
GOTO INCREMENTO

BOTONRESET
BTFSS BOTONR
GOTO INICIO
CICLO1 CALL LOOP
CALL RETARDO2
BTFSS BOTONR
GOTO CICLO1
GOTO RESETEO

INCREMENTO
INCF UNIDAD,1
MOVLW D'9'
CPFSGT UNIDAD
GOTO INICIO
MOVLW D'0'
MOVWF UNIDAD
INCF DECENA,1
MOVLW D'9'
CPFSGT DECENA
GOTO INICIO
GOTO RESETEO

LOOP
BCF PORTA,RA2
CALL UNIDADES
BSF PORTA,RA1
CALL RETARDO1
BCF PORTA,RA1
CALL DECENAS
BSF PORTA,RA2
CALL RETARDO1
BCF PORTA,RA2
RETURN

UNIDADES
MOVFF UNIDAD,WREG
RLNCF WREG
CALL DISPLAY
MOVWF PORTB
RETURN

DECENAS
MOVFF DECENA,WREG
RLNCF WREG
CALL DISPLAY
MOVWF PORTB
RETURN

RETARDO1
MOVLW D'124'
MOVWF CONTADOR

RUTINA NOP
DECFSZ CONTADOR,F
GOTO RUTINA
RETURN

RETARDO2
RUTINA4 MOVLW d'10'
MOVWF CONTADOR3

RUTINA3 MOVLW d'2'
MOVWF CONTADOR2

RUTINA2 MOVLW d'249'
MOVWF CONTADOR1

RUTINA1 NOP
DECFSZ CONTADOR1,F
GOTO RUTINA1
DECFSZ CONTADOR2,F
GOTO RUTINA2
DECFSZ CONTADOR3,F
GOTO RUTINA3
RETURN

DISPLAY
ADDWF PCL,F
RETLW b'1000000';0
RETLW b'1111001';1
RETLW b'0100100';2
RETLW b'0110000';3
RETLW b'0011001';4
RETLW b'0010010';5
RETLW b'0000010';6
RETLW b'1111000';7
RETLW b'0000000';8
RETLW b'0011000';9

END
```


----------



## D@rkbytes (May 23, 2020)

La palabra de configuración es más sencillo escribirla de esta forma:

```
config    FOSC = INTOSCIO_EC, PLLDIV = 1
    config    PWRT = ON, LVP = OFF, WDT = OFF
```
Así se escriben únicamente los bits necesarios y se evitan redundancias en los fuses por defecto.

El registro OSCCON está mal configurado. (Aunque los bits más importantes son: IRCF2, IRCF1 e IRCF0)
1 MHz es el valor por defecto si no se configura.
Para 8 MHz debería tener el valor 0x72
Para 4 MHz debería tener el valor 0x62
Para otras frecuencias inferiores hasta 31 KHz, ver la hoja de datos.
El registro CMCON no se está usando, por lo tanto no tiene caso su configuración.
En este PIC con configurar el registro ADCON1 basta para establecer los pines que serán análogos o digitales.
En los PIC18 es más conveniente usar los registros LATX que los PORTX
Otro detalle. Tabular y comentar el código es importante.

Aunque existe algo de basura dentro del programa, debería funcionar físicamente.
Así que debe haber un problema de hardware.


----------

