jueves, 30 de julio de 2015

Reloj con DS1307 y PIC 18f877

Un proyecto en el cual se desarrollará un reloj con el circuito integrado DS1307 y un microcontrolador de gama media 16f877.
Para el desarrollo he utilizado una librería de las varias que circulan por la web, después de haberlo examinado y probado.
Este proyecto fue desarrollado según requerimientos especificados, se lee el reloj cada segundo y se muestra en un display de 7 segmentos construido con diodos leds.
posee 5 pulsadores para controlar su funcionamiento como es poner la hora, cambiar a cronómetro pausar.
También posee una salida para alarma que nos avisará cuando inicia la cuenta regresiva, todo según requerimientos.
El proyecto está desarrollado en CCS 4.114 compiler y simulado en software Proteus 7.9.
En este artículo les mostraré toda la documentación para poder desarrollarlo, ustedes podrán adaptar el proyecto a sus necesidades.
El programa incluye la configuración del reloj para salida de pulsos a 1 Hz y actualización de la hora.
A continuación les muestro el diagrama de flujo del programa:






El diagrama del circuito para la simulación en proteus: 

Al final podrás encontrar el enlace para descargarlo.

























Para poder desarrollar una placa decircuito impreso y mostrar en un display construido con leds de 5mm les muestro un posible circuito hecho con Eagle 6.1.0.


























El código del programa es el siguiente:
#include <Cronometro.h>
#include <DS1307FIN.c>
#byte PORTB = 0x06 // Identificador para el puerto B.
#byte PORTD=0X08
#byte PORTA=0X05
#byte PORTC=0X07
#BYTE OPTION_REG=0X81
#Priority  int_ext, int_rb
#use fast_io(C)
int hr=0;
int min=0;
int sec=0;
int8 modo=0;
int banderaleerclk=0;
int banderaescribirhora=0;
byte CONST DISPLAY[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
int digit;     // resultado de la conversion bin2bcd
int8 banderapause=0;
void tiempo(void)
{
int16 z=0;
int16 y=0;
for(z=0;z<10;z++)
{
for(y=0;y<100;y++)
{}
z++;
}
}
void muestra()
{
int8 temp1=0;
digit= bin2bcd(hr);     //convierte hora a bcd
temp1=swap(digit) & 0b00000001; //filtra para leer solo la hora
temp1=DISPLAY[temp1];
bit_set(PORTA,0);
PORTD=temp1;
tiempo();
bit_clear(PORTA,0) ;   
temp1=swap(digit) & 0b00001111;
temp1=DISPLAY[temp1];
bit_set(PORTA,1);
PORTD=temp1;
tiempo();
bit_clear(PORTA,1) ;
digit=bin2bcd(min);     //convierte minutos a bcd
temp1=swap(digit) & 0b00001111;
temp1=DISPLAY[temp1];
bit_set(PORTA,2);
PORTD=temp1;
tiempo();
bit_clear(PORTA,2) ;   
temp1=swap(digit) & 0b00001111;
temp1=DISPLAY[temp1];
bit_set(PORTA,3);
PORTD=temp1;
tiempo();
bit_clear(PORTA,3) ;
}
void muestra2()
{
int8 temp=0;
digit= bin2bcd(min);     //convierte min a bcd
temp=swap(digit) & 0b00001111;
temp=DISPLAY[temp];
bit_set(PORTA,0);
PORTD=temp;
tiempo();
bit_clear(PORTA,0) ;    
temp=swap(digit) & 0b00001111;
temp=DISPLAY[temp];
bit_set(PORTA,1);
PORTD=temp;
tiempo();
bit_clear(PORTA,1) ;
digit=bin2bcd(sec);     //convierte sec a bcd
temp=swap(digit) & 0b00001111;
temp=DISPLAY[temp];
bit_set(PORTA,2);
PORTD=temp;
tiempo();
bit_clear(PORTA,2) ;   
temp=swap(digit) & 0b00001111;
temp=DISPLAY[temp];
bit_set(PORTA,3);
PORTD=temp;
tiempo();
bit_clear(PORTA,3) ;
}
#int_rb
void pulsadores()
{
delay_ms(50);
int temp =PORTB & 0b11110000;
switch(temp)
 {
 case 0b11100000:
 if(banderapause==1) {
 if (modo==0){
 if (hr<12){hr++;}
 else{hr=0;}
             }
 else{
  if (min<60){min++;}
 else{min=0;}}
 }

    //PIN RB4
 break;
 case 0b11010000:
  if(banderapause==1){
  if (modo==0){
 if (min<60){min++;}
 else{min=0;}
  }
  else
  {
   if (sec<60){sec++;}
 else{sec=0;}
  }
  }
    //PIN RB5
 break;
 case 0b10110000:
 if (modo==1)
 {
 modo=0;
 }
 else{
 disable_interrupts(int_ext);
     min=60;
     sec=0;
    //PIN RB6
    if(banderapause==0)
    {
    output_high(pin_b1);      //alarma
    PORTD=0;
    delay_ms(3000);
     output_low(pin_b1);
      enable_interrupts(int_ext);
    }
     modo=1;
 }
 break;
 case 0b01110000:          //inicia cronometro
 if (banderapause==0){
 banderapause=1;
 disable_interrupts(int_ext);
 }
 else
 {
 banderapause=0;
 output_high(pin_b1);      //alarma
    delay_ms(3000);
     output_low(pin_b1);
  enable_interrupts(int_ext);
 }
    //PIN RB7

 break;
 default:
 break;
 }
 }
#int_ext
void cuentaseg()
{
switch (modo)
{
case 0:          //caso reloj
banderaleerclk=1;
break;
case 1:       //caso cronometro
if (sec >0)
{
sec--;
}
else if(sec==256)
{
min--;
sec=59;
}
if (min==5 && sec==0)     //en 5 minutos aviso alarma
{output_high(pin_b1);}
if(min==4 && sec==56)  //corta alarma
{output_low(pin_b1);}
if(min==0 && sec==5)  //alarma final
{output_high(pin_b1);}
if (min==0 && sec==0)
{
//aviso de cuenta cero
{output_low(pin_b1);}
modo=0  ;                  //vuelve a función reloj
}
break;
}
}
#int_timer0
void tmr_error()
{
 disable_interrupts(INT_TIMER0);
 set_timer0(0);
if(input(pin_c1)==0)
{
banderaescribirhora=1;
}
}
void main()
{
PORTD=0;
PORTB=0;
PORTA=0x00;
set_tris_c(0b11111100);
set_tris_d(0x00);
Set_tris_a(0x00);
set_tris_b(0xf1);
 // ds1307_init();
 // ds1307_am(hr);
 ds1307_get_time(hr,min,sec);
 if((sec & 0b10000000)==0b10000000)   //PARA INICIAR SOLO LA PRIMERA VEZ
 {
  ds1307_init();
  ds1307_am(hr);
 }
 setup_timer_0(RTCC_INTERNAL |RTCC_DIV_256);
set_timer0(0);
ext_int_edge(L_TO_H);
  enable_interrupts(int_ext);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
delay_ms(2000);
while(1)      //se repite indefinidamente
{
if(input(pin_c1)==0 && banderapause==1)
{
 enable_interrupts(INT_TIMER0);
}
else
{
disable_interrupts(INT_TIMER0);
}
switch (modo)
{
case 0:
if(banderaleerclk==1)
{
banderaleerclk=0;
disable_interrupts(GLOBAL);
 ds1307_get_time(hr,min,sec);
 enable_interrupts(GLOBAL);
}
if (banderaescribirhora==1){
banderaescribirhora=0;
if(banderapause==1 && modo==0)  //si está en reloj y interrupción deshabilitada
{
ds1307_set_date_time (10, 06, 15, 2, hr, min, sec); /// se escribe en el displositivo
 ds1307_am(hr);
}
}
muestra();
break;
case 1:
muestra2();
}
}
}



Ahora una vista del modelo de nuestra placa del circuito con SketchUp y Eagle :












Las librerías para el programa puedes descargarlo a continuación:
Codigo y DSN:Aqui