Reloj digital con PIC16F877A y display de 7 segmentos. La hora se muestra en formato de 24 horas; por ejemplo 14:35 (dos de la tarde y 35 minutos). Dispone de botones para ajuste de horas y minutos. Un botón adicional permite activar la presentación (encender el display) por un lapso de 1 segundo para ver la hora actual, luego de lo cual el display se apaga pero el conteo del tiempo sigue corriendo; esta funcion apaga el display de forma automatica con el proposito de reducir el consumo y ahorrar energia, muy util si la alimentacion se obtiene de una bateria.

Además, un pin se activa por un lapso de 1 segundo a dos horas diferentes programables por software.


¡Descubre el mundo de los microcontroladores PIC y lleva tus habilidades de programación al siguiente nivel! Obtén nuestro eBook y disfruta aprendiendo paso a paso desde cero, podrás realizar proyectos prácticos, encontrar soluciones a problemas comunes y explorar una amplia cobertura de temas desde lo más básico a lo más avanzado. Incluye software y ejemplos resueltos. ¡Cómpralo ahora y libera el increíble potencial de esta poderosa tecnología hoy mismo!

Microcontroladores PIC en PDF: Curso completo


Para que los proyectos funcionen correctamente, el PIC16F877A se tiene que polarizar de acuerdo al esquema indicado en la polarización básica (ver link más abajo).

Reloj digital en mikroC PRO con el PIC16F877A

A continuación se muestra el código completo para este reloj digital, con el PIC16F877A trabajando con el cristal oscilador externo de 4MHz. Luego de varios intentos fallidos de simulación en Proteus ISIS pude comprobar que el problema se debe a un error generado por el propio simulador, para eso me valí de un ejemplo muy sencillo con el cual pude comparar los resultados experimentales y simulados. Aparentemente falta depurar esta versión del famoso simulador pues presenta problemas con el puerto E.

//reloj7seg.c
//Microcontrolador: PIC16F877A
//Oscilador: Externo 4MHz (modo HS)
//******
//El Proteus 7.5 Professional no acepta la simulación del puerto E y presenta un mensaje de error
//al intentar su simulación. Se probó un ejemplo básico para encender un LED el cual
//funcionó perfectamente en la práctica pero el Proteus generaba el error "Internal Exception:
//acces violation in module PIC16.DLL".
//******
//Entradas:
//AA: Avance Automático al mantener presionado (también avance paso a paso al pulsar y soltar).
//Ajuste de HORAS (AA) ->RB7(40)
//Ajuste de MINUTOS (AA) ->RC7(26)
//ACTIVAR ->RD7(30)
//Salidas:
//Horas -> Puertos  A y B
//Minutos -> Puertos C y D
//Dos puntos (:) ->RE1(9)
//Pulso de 1 segundo -> RE0(8)

//Función para transformar de binario(decimal) a 7 segmentos:
char Bin2_7seg(char digit){
  switch (digit){
    case 0: return 0x3F;  //0x3F es el código 7-segmentos del 0.
    case 1: return 0x06;  //0x06 es el código 7-segmentos del 1.
    case 2: return 0x5B;
    case 3: return 0x4F;
    case 4: return 0x66;
    case 5: return 0x6D;
    case 6: return 0x7D;
    case 7: return 0x07;
    case 8: return 0x7F;
    case 9: return 0x67;
  }
}

char contador=0,segundos=0,minutos=0,horas=0, minutosBCD, unidades, decenas, horasBCD, j=0;
bit activar;

void main(){
PORTA=0x00;
RE0_bit=0;
RE1_bit=0;
ADCON1=0x06; //Pines RA<5:0> como E/S digital.
PORTB=0x00;  //Inicialización.
PORTC=0x00;
PORTD=0x00;
TRISA=0x00;  //Puerto A como salida.
TRISB=0x80;  //RB7 como entrada. RB<6:0> como salidas.
TRISC=0x80;  //RC7 como entrada. RC<6:0> como salidas.
TRISD=0x80;  //RD7 como entrada. RD<6:0> como salidas.
TRISE0_bit=0;  //RE0 como salida.
TRISE1_bit=0;  //RE1 como salida.
OPTION_REG=0b01010111;      //Pull ups habilitados.Timer0 como temporizador.
                            //Prescaler asignado al Timer0. Prescaler 1:256.

TMR0=61;                    //Valor inicial del TMR0. Interrupción cada 50 ms.
GIE_bit=1;                  //Interrupciones habilitadas.
T0IE_bit=1;                 //Interrupción del Timer0 habilitada.
activar=1;
while (1){
  if (segundos==60){
    minutos++;
    segundos=0;
  }

  if (minutos==60){
    horas++;
    minutos=0;
  }

  if (horas==24) horas=0;

  //Encender los displays por 1 segundo al presionar ACTIVAR:
  if (activar==1){
    //Encender los dos puntos ":" :
    RE1_bit=1;

    //Transformar los minutos para su presentación:
    minutosBCD=Dec2Bcd(minutos);          //Transforma de binario a BCD.
    unidades=0b1111&minutosBCD;           //Sacar las unidades.
    decenas=0b11110000&minutosBCD;        //Sacar las decenas.
    decenas=decenas>>4;                   //Desplazar 4 bits a la derecha.
    PORTD=Bin2_7seg(unidades);            //Unidades al puerto D.
    PORTC=Bin2_7seg(decenas);             //Decenas al puerto C.

    //Transformar las horas para su presentación:
    horasBCD=Dec2Bcd(horas);              //Transforma de binario a BCD.
    unidades=0b1111&horasBCD;             //Sacar las unidades.
    decenas=0b11110000&horasBCD;          //Sacar las decenas.
    decenas=decenas>>4;                   //Desplazar 4 bits a la derecha.
    PORTB=Bin2_7seg(unidades);            //Unidades al puerto B.
    if (decenas==1)
      PORTA=Bin2_7seg(decenas);            //Decenas al puerto A.
    if (decenas==2)
      PORTA=0x3B;                          //Formar el número "2".
    if (decenas==0) PORTA=0;              //Apagar las decenas cuando valgan cero.
  }
  else{
    PORTA=0;
    PORTB=0;
    PORTC=0;
    PORTD=0;
    PORTE=0;
  }

  //Generar un pulso a una determinada hora, por ejemplo a las 2h01.
  if (horas==2 && minutos==01 && segundos==0)
    RE0_bit=1;
  if (horas==2 && minutos==01 && segundos==1)
    RE0_bit=0;

  //Generar un pulso a una determinada hora, por ejemplo a las 15h25.
  if (horas==15 && minutos==25 && segundos==0)
    RE0_bit=1;
  if (horas==15 && minutos==25 && segundos==1)
    RE0_bit=0;
}
}

void interrupt(void){
  //Botón HORAS presionado:
  if (Button(&PORTB,7,1,0)){
    activar=1;
    horas++;
    if (horas==24) horas=0;
    Delay_ms(200);
  }

  //Botón MINUTOS presionado:
  if (Button(&PORTC,7,1,0)){
    activar=1;
    minutos++;
    if (minutos==60) minutos=0;
    Delay_ms(200);
  }

  //Botón ACTIVAR presionado:
  if (Button(&PORTD,7,1,0))
  activar=1;

  //Medir 1 segundo (para el encendido de los displays):
  if (activar==1){
    j++;
    if (j==20){
      j=0;
      activar=0;
    }
  }

  //Medidor de segundos (para el reloj):
  TMR0=61;                   //Valor inicial del TMR0. Interrupción cada 50 ms.
  contador++;
  if (contador==20){
    segundos++;
    contador=0;
  }
  T0IF_bit=0;              //Borra la bandera de interrupción.
}

Circuito del reloj digital con PIC16F877A

Reloj digital con PIC

Información complementaria