Reloj Despertador con MicroPIC

Sección dedicada a imágenes de circuitos, diagramas que no requieren explicación previa, Proyectos sencillos.
Area para desarrollo de proyectos, colaboración de toda la comunidad en proyectos. Solución de dudas y aportes.

No publicar manuales, no publicar temas ajenos a los proyectos. de ser necesario, hacer indicación con enlace entre etiquetas CODE
Avatar de Usuario
Enigma
Administrador del Sitio
Administrador del Sitio
Mensajes: 1268
Registrado: 20 Oct 2013, 16:26
Genero: Mujer
Profesion: Webmaster CEO SEO
Ubicacion: Matrix
Navegador: Chrome
Contactar:

Reloj Despertador con MicroPIC

Mensaje sin leer por Enigma » 01 Mar 2015, 14:29

Reloj Despertador con MicroPIC

Este circuito es un simple reloj despertador digital realizado en base a un mcu muy económico y potente (en este caso se eligió por su tamaño y precio, ya que se puede aprovechar mucho mas en otras aplicaciones)

El pic utilizado es el PIC16F883 configurado con oscilador interno y sin interrupciones.
El mismo obtiene los pulsos de reloj y la hora del RTC (Reloj en Tiempo Real) DS1302, este integrado de la firma Maxim nos provee Hora y Fecha, la posibilidad de configurar y de mantener los datos con una pila de BackUp (en el circuito usamos una CR2032) esto es por si se desconecta de la alimentación.

De esta forma no perderemos la hora, una posible mejora seria la de guardar la alarma en la eeprom del pic por si se desconecta la energía, es muy sencillo, solo es necesario utilizar las instrucciones write_eeprom y read_eeprom, con esas instrucciones una graba el valor seteado como alarma y al momento de compararlo con la hora actual la tome de ahí.

También es posible utilizar interrupción por activación externa para el seteo de la hora, seria mas eficiente.
(estas son mejoras que se me van ocurriendo en el momento) el programa lo eh desarrollado en el recreo de la universidad y con una hora de empeño que me sobraba entre dos materias por esto no lo eh optimizado bien, también decidí subirlo asi porque para los que no tienen mucho conocimiento de C, les resultara mas fácil ver unos cuantos IF sencillos.

El circuito presenta un LCD de 1x16 (es decir una linea/renglón de 16 caracteres, no parecía necesario uno mas grande pero es posible poner otro mas grande y simplemente con la función lcd_gotoxy(X,Y) es posible posicionar el string en donde queramos (Renglón y carácter).

Como se puede notar el circuito se trato de hacer lo mas economicamente posible utilizando MCU económico, LCD el mas chico dentro de lo que nos sea útil, el RTC cuesta un poco mas que el pic, es posible no utilizar el RTC pero habría que utilizar el cristal de 32768KHz con algún arreglo de compuertas como oscilador e ingresarlo en una interrupción por timer del mcu para marcar el tiempo. Pero no viene mal ya que con el RTC también se puede aprender a utilizar el protocolo I2C el cual esta detallado en el código fuente, como también el código de manejo del LCD.

La única librería que resta es la del propio pic pero si lo tienen que compilar ya deberían contar con ella, posible mente también cuenten con la del DS1302.C y LCD.C (siendo así pueden eliminar el código de estos dos del fuente (el de color gris) e incluir las dos librerías, así quedara mas corto el código de programa).

Funcionamiento
El funcionamiento de este reloj se basa en tres comandos, un interruptor que decide si el reloj esta en modo normal o modo configuración dos pulsadores, uno para incrementar la hora actual, y otro para incrementar la alarma, Si posicionamos el interruptor en normal, el reloj comenzara a funcionar normalmente con la descripción "HORA HH:MM:SS " en cambio si posicionamos el interruptor en configuración se mostrara "HORA 00:00:00 " en este estado si presionamos el botón de tiempo aparecerá "ST" quedando de la siguiente manera "HORA 00:00:00 ST" y si lo mantenemos presionado comenzara a incrementar horas y minutos, lo mismo pasa para configurar la alarma, si presionamos el pulsador de alarma mostrara "HORA 00:00:00 AL" y luego comenzara a incrementar.

Una vez seteado nuevamente ponemos el interruptor en normal y comenzara a funcionar el reloj desde la hora seteada, y en el caso de que la hora de alarma sea igual a la hora actual se encenderá un led. (se puede agregar otra mejora como un interruptor donde esta el led para apagar la alarma... o bien un circuito de alarma sonora temporizado (todo esto se puede hacer con un 555 y un buzzer activo o bien con el mismo pic se puede hacer una subrutina donde se enciende el Led que encienda por un tiempo y luego corte.

También me falto en el diseño ponerle la resistencia a Vcc que alimenta el backlight del lcd, eso nos sirve para poder ver el reloj de noche, claro que si v a estar en la oscuridad tal vez con un interruptor inversor podemos optar por dos resistencias dif, una que encienda mas brillante el backlight a modo dimmer. eso queda a elección.
El circuito funciona perfectamente pero como les eh comentado es posible mejorarlo y es sencillo mejorarlo también.

Se le agrego el control de luminosidad para el backlight con un interruptor inversor para poder elegir entre dos luminosidades diferentes.
Se agrego la grabación de la alarma en la EEPROM interna del mcu para que se retenga si se corta la energía.
Se cambio el display de un renglón por uno de dos renglones ya que el precio es casi el mismo y de esta forma mostramos en la linea 2 el horario de la alarma.

Imagen

El código fuente (con el control de LCD y DS1302 incluido):

Código: Seleccionar todo

#include <16F883.h>
#device adc=8
#FUSES NOWDT
#FUSES INTRC_IO
#FUSES NOPUT
#FUSES MCLR
#FUSES NOBROWNOUT
#FUSES NOLVP
#FUSES NOCPD
#FUSES NOWRT
#FUSES NODEBUG
#FUSES NOPROTECT
#use delay(int=4000000)
#define RTC_RST    PIN_A0
#define RTC_SCLK   PIN_A1
#define RTC_IO     PIN_A2
#include 
#include 
void main()
{
int HH, MIN, SS;
int HHSet, MMset;
int HHAlarm, MMAlarm;
int i;
   lcd_init();
   lcd_putc("Electgpl Clock");
   delay_ms(1000);
   rtc_init();
   lcd_init();
   while(1)
   {
   if (input(PIN_A5)==1)
      {
      if (input(PIN_A4)==1) 
         {
         lcd_gotoxy(15,1);
         lcd_putc("ST");
         rtc_set_datetime(0,0,0,0,HHSet,MMSet);
         MMSet = MMSet + 1;
         if (MMSet > 59)
            {
            delay_ms(100);
            MMSet = 0;
            HHSet = HHSet + 1;
            }  
            if (HHSet > 23)
               {
               HHSet = 0;
               } 
         lcd_gotoxy(1,1);
         printf(lcd_putc,"HORA %02d:%02d:00   ",HHSet,MMSet);               
         }
      else
         {
         if (input(PIN_A3)==1) 
            {
            lcd_gotoxy(15,1);
            lcd_putc("AL");
            MMAlarm = MMAlarm + 1;
            if (MMAlarm > 59)
               {
               delay_ms(100);
               MMAlarm = 0;
               HHAlarm = HHAlarm + 1;
               }  
               if (HHAlarm > 23)
                  {
                  HHAlarm = 0;
                  } 
            lcd_gotoxy(1,1);
            printf(lcd_putc,"HORA %02d:%02d:00   ",HHAlarm,MMAlarm);    
            write_eeprom(8,HHAlarm);
            write_eeprom(9,MMAlarm);
            } 
         } 
      }   
   else     
      {
      rtc_get_time(HH,MIN,SS);
      lcd_gotoxy(1,1);
      printf(lcd_putc,"HORA %02d:%02d:%02d   ",HH,MIN,SS);
      HHAlarm=read_eeprom(8);
      MMAlarm=read_eeprom(9);
      lcd_gotoxy(1,2);
      printf(lcd_putc,"ALARMA  %02d:%02d   ",HHAlarm,MMAlarm);
      if((HH == HHAlarm) && (MIN == MMAlarm))
         output_high(pin_a6);
      else
         output_low(pin_a6);       
      }
   }   
}

El siguiente código es el de las librerías (DS1302.C y LCD.C) que si lo compilan con CCS solo tienen que incluirlas en el encabezado del programa junto a los demás Include las librerías DS1302.C y LCD.C
(yo las he modificado levemente para sacarles algunas cosas que interesaban y cambiarle algunas configuraciones, pero es lo mismo si utilizan las de CCS)

LIBRERIAS EXTRA

Código: Seleccionar todo

#ifndef RTC_SCLK
#define RTC_SCLK PIN_A1
#define RTC_IO   PIN_A3
#define RTC_RST  PIN_A2
#endif
void write_ds1302_byte(BYTE cmd) 
{
   BYTE i;
   for(i=0;i<=7;++i) 
   {
      output_bit(RTC_IO, shift_right(&cmd,1,0) );
      output_high(RTC_SCLK);
      output_low(RTC_SCLK);
   }
}
void write_ds1302(BYTE cmd, BYTE data) 
{
   output_high(RTC_RST);
   write_ds1302_byte(cmd);
   write_ds1302_byte(data);
   output_low(RTC_RST);
}
BYTE read_ds1302(BYTE cmd) 
{
   BYTE i,data;
   output_high(RTC_RST);
   write_ds1302_byte(cmd);
   for(i=0;i<=7;++i) 
   {
      shift_right(&data,1,input(RTC_IO));
      output_high(RTC_SCLK);
      delay_us(2);
      output_low(RTC_SCLK);
      delay_us(2);
   }
   output_low(RTC_RST);
   return(data);
}
void rtc_init() 
{
   BYTE x;
   output_low(RTC_RST);
   delay_us(2);
   output_low(RTC_SCLK);
   write_ds1302(0x8e,0);
   write_ds1302(0x90,0xa4);
   x=read_ds1302(0x81);
   if((x & 0x80)!=0)
     write_ds1302(0x80,0);
}
int get_bcd(BYTE data)
{
   int nibh;
   int nibl;
   nibh=data/10;
   nibl=data-(nibh*10);
   return((nibh<<4)|nibl);
}
int rm_bcd(BYTE data)
{
   int i;
   i=data;
   data=(i>>4)*10;
   data=data+(i<<4>>4);
   return data;
}
void rtc_set_datetime(BYTE day, BYTE mth, BYTE year, BYTE dow, BYTE hr, BYTE min) 
{
   write_ds1302(0x86,get_bcd(day));
   write_ds1302(0x88,get_bcd(mth));
   write_ds1302(0x8c,get_bcd(year));
   write_ds1302(0x8a,get_bcd(dow));
   write_ds1302(0x84,get_bcd(hr));
   write_ds1302(0x82,get_bcd(min));
   write_ds1302(0x80,get_bcd(0));
}
void rtc_get_date(BYTE& day, BYTE& mth, BYTE& year, BYTE& dow) 
{
   day = rm_bcd(read_ds1302(0x87));
   mth = rm_bcd(read_ds1302(0x89));
   year = rm_bcd(read_ds1302(0x8d));
   dow = rm_bcd(read_ds1302(0x8b));
}
void rtc_get_time(BYTE& hr, BYTE& min, BYTE& sec) 
{
   hr = rm_bcd(read_ds1302(0x85));
   min = rm_bcd(read_ds1302(0x83));
   sec = rm_bcd(read_ds1302(0x81));
}
void rtc_write_nvr(BYTE address, BYTE data) 
{
   write_ds1302(address|0xc0,data);
}
BYTE rtc_read_nvr(BYTE address) 
{
    return(read_ds1302(address|0xc1));
}
struct lcd_pin_map 
{                 
BOOLEAN rs;
BOOLEAN rw;
BOOLEAN enable;
BOOLEAN unused;
int     data : 4;         
} lcd;
#if defined(__PCH__)
#if defined use_portb_lcd
   #byte lcd = 0xF81
#else
   #byte lcd = 0xF83
#endif
#else
#if defined use_portb_lcd
   #byte lcd = 6
#else
   #byte lcd = 8
#endif
#endif
#if defined use_portb_lcd
   #define set_tris_lcd(x) set_tris_b(x)
#else
   #define set_tris_lcd(x) set_tris_d(x)
#endif
#define lcd_type 2
#define numero_caracteres 20
#define lcd_line_two 0x40
BYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};
struct lcd_pin_map const LCD_WRITE = {0,0,0,0,0}; 
struct lcd_pin_map const LCD_READ = {0,0,0,0,15};
BYTE lcd_read_byte() 
{
   BYTE low,high;
   set_tris_lcd(LCD_READ);
   lcd.rw = 1;
   delay_cycles(1);
   lcd.enable = 1;
   delay_cycles(1);
   high = lcd.data;
   lcd.enable = 0;
   delay_cycles(1);
   lcd.enable = 1;
   delay_us(1);
   low = lcd.data;
   lcd.enable = 0;
   set_tris_lcd(LCD_WRITE);
   return( (high<<4) | low);
}
void lcd_send_nibble( BYTE n ) 
{
   lcd.data = n;
   delay_cycles(1);
   lcd.enable = 1;
   delay_us(2);
   lcd.enable = 0;
}
void lcd_send_byte( BYTE address, BYTE n ) 
{
   lcd.rs = 0;
   while ( bit_test(lcd_read_byte(),7) ) ;
   lcd.rs = address;
   delay_cycles(1);
   lcd.rw = 0;
   delay_cycles(1);
   lcd.enable = 0;
   lcd_send_nibble(n >> 4);
   lcd_send_nibble(n & 0xf);
}
void lcd_init() 
{
   BYTE i;
   set_tris_lcd(LCD_WRITE);
   lcd.rs = 0;
   lcd.rw = 0;
   lcd.enable = 0;
   delay_ms(15);
   for(i=1;i<=3;++i) 
   {
      lcd_send_nibble(3);
      delay_ms(5);
   }
   lcd_send_nibble(2);
   for(i=0;i<=3;++i)
      lcd_send_byte(0,LCD_INIT_STRING);
}
void lcd_gotoxy( BYTE x, BYTE y) 
{
   BYTE address;
}



Volver a “Proyectos y Circuitos Didacticos”