TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: esperanzachat en 19 de Mayo de 2019, 19:01:21
-
Hola, hice un temporizador basado en un DS1307 y el tema que tengo es que, estando alimentado, la hora, una vez ajustada. se adelanta, es decir se adelanta unos 2 min cada 10 a 15 dias y no se porque, ya que no uso ningun comando que la pueda modificar. use la libreria de redpic
///////////////////////////////////////////////////////////////////////////////////////
/// DS1307.C ///
/// Driver for Real Time Clock ///
/// modified by Redpic 08/2006 ///
/// http://picmania.garcia-cuervo.com ///
/// ///
/// void ds1307_init(val) ///
/// - Enable oscillator without clearing the seconds register ///
/// used when PIC loses power and DS1307 run from 3V BAT ///
/// - Config Control Register with next parameters: ///
/// DS1307_ALL_DISABLED All disabled ///
/// DS1307_OUT_ON_DISABLED_HIHG Out to Hight on Disable Out ///
/// DS1307_OUT_ENABLED Out Enabled ///
/// DS1307_OUT_1_HZ Freq. Out to 1 Hz ///
/// DS1307_OUT_4_KHZ Freq. Out to 4.096 Khz ///
/// DS1307_OUT_8_KHZ Freq. Out to 8.192 Khz ///
/// DS1307_OUT_32_KHZ Freq. Out to 32.768 Khz ///
/// ///
/// Example init: ///
/// ds1307_init(DS1307_ALL_DISABLED); ///
/// ds1307_init(DS1307_OUT_ENABLED | DS1307_OUT_1_HZ); ///
/// ///
/// void ds1307_set_date_time(day,mth,year,dow,hour,min,sec) - Set the date/time ///
/// ///
/// void ds1307_get_date(day,mth,year,dow) - Get the date ///
/// ///
/// void ds1307_get_time(hr,min,sec) - Get the time ///
/// ///
/// char ds1307_read_nvram_byte(char addr) - Read byte in address ///
/// ///
/// void ds1307_write_nvram_byte(char addr, char value) - Write byte in address ///
/// ///
/// void ds1307_get_day_of_week(char* ptr) - Get string Day Of Week///
/// ///
/// If defined USE_INTERRUPTS all functions disable Global Interrupts on starts and ///
/// enable Global on ends else usar can do it hiself ///
/// ///
///////////////////////////////////////////////////////////////////////////////////////
#ifndef RTC_SDA
#define RTC_SDA PIN_A1
#define RTC_SCL PIN_A0
#endif
#use i2c(master, sda=RTC_SDA, scl=RTC_SCL)
#define DS1307_ALL_DISABLED 0b00000000 // All disabled
#define DS1307_OUT_ON_DISABLED_HIHG 0b10000000 // Out to Hight on Disable Out
#define DS1307_OUT_ENABLED 0b00010000 // Out Enabled
#define DS1307_OUT_1_HZ 0b00000000 // Freq. Out to 1 Hz
#define DS1307_OUT_4_KHZ 0b00000001 // Freq. Out to 4.096 Khz
#define DS1307_OUT_8_KHZ 0b00000010 // Freq. Out to 8.192 Khz
#define DS1307_OUT_32_KHZ 0b00000011 // Freq. Out to 32.768 Khz
#define Start_user_address_nvram 0x08
#define End_user_address_nvram 0x3f
char days_of_week[7][11]={"Lunes\0","Martes\0","Miércoles\0","Jueves\0","Viernes\0","Sábado\0","Domingo\0"};
byte ds1307_bin2bcd(byte binary_value);
byte ds1307_bcd2bin(byte bcd_value);
void ds1307_init(int val){
byte seconds = 0;
#ifndef USE_INTERRUPTS
disable_interrupts(global);
#endif
i2c_start();
i2c_write(0xD0);
i2c_write(0x00);
i2c_start();
i2c_write(0xD1);
seconds = ds1307_bcd2bin(i2c_read(0));
i2c_stop();
seconds &= 0x7F;
delay_us(3);
i2c_start();
i2c_write(0xD0);
i2c_write(0x00);
i2c_write(ds1307_bin2bcd(seconds));
i2c_start();
i2c_write(0xD0);
i2c_write(0x07);
i2c_write(val);
i2c_stop();
#ifndef USE_INTERRUPTS
enable_interrupts(global);
#endif
}
void ds1307_set_date_time(byte day, byte mth, byte year, byte dow, byte hr, byte min, byte sec){
#ifndef USE_INTERRUPTS
disable_interrupts(global);
#endif
sec &= 0x7F;
hr &= 0x3F;
i2c_start();
i2c_write(0xD0);
i2c_write(0x00);
i2c_write(ds1307_bin2bcd(sec));
i2c_write(ds1307_bin2bcd(min));
i2c_write(ds1307_bin2bcd(hr));
i2c_write(ds1307_bin2bcd(dow));
i2c_write(ds1307_bin2bcd(day));
i2c_write(ds1307_bin2bcd(mth));
i2c_write(ds1307_bin2bcd(year));
i2c_stop();
#ifndef USE_INTERRUPTS
enable_interrupts(global);
#endif
}
void ds1307_get_date(byte &day, byte &mth, byte &year, byte &dow){
#ifndef USE_INTERRUPTS
disable_interrupts(global);
#endif
i2c_start();
i2c_write(0xD0);
i2c_write(0x03);
i2c_start();
i2c_write(0xD1);
dow = ds1307_bcd2bin(i2c_read() & 0x7f);
day = ds1307_bcd2bin(i2c_read() & 0x3f);
mth = ds1307_bcd2bin(i2c_read() & 0x1f);
year = ds1307_bcd2bin(i2c_read(0));
i2c_stop();
#ifndef USE_INTERRUPTS
enable_interrupts(global);
#endif
}
void ds1307_get_time(byte &hr, byte &min, byte &sec){
#ifndef USE_INTERRUPTS
disable_interrupts(global);
#endif
i2c_start();
i2c_write(0xD0);
i2c_write(0x00);
i2c_start();
i2c_write(0xD1);
sec = ds1307_bcd2bin(i2c_read() & 0x7f);
min = ds1307_bcd2bin(i2c_read() & 0x7f);
hr = ds1307_bcd2bin(i2c_read(0) & 0x3f);
i2c_stop();
#ifndef USE_INTERRUPTS
enable_interrupts(global);
#endif
}
char ds1307_read_nvram_byte(char addr){
char retval;
#ifndef USE_INTERRUPTS
disable_interrupts(global);
#endif
i2c_start();
i2c_write(0xD0);
i2c_write(addr);
i2c_start();
i2c_write(0xD1);
retval = i2c_read(0);
i2c_stop();
return(retval);
#ifndef USE_INTERRUPTS
enable_interrupts(global);
#endif
}
void ds1307_write_nvram_byte(char addr, char value){
#ifndef USE_INTERRUPTS
disable_interrupts(global);
#endif
i2c_start();
i2c_write(0xD0);
i2c_write(addr);
i2c_write(value);
i2c_stop();
#ifndef USE_INTERRUPTS
enable_interrupts(global);
#endif
}
void ds1307_get_day_of_week(char* ptr){
byte lday;
byte lmonth;
byte lyr;
byte ldow;
ds1307_get_date(lday,lmonth,lyr,ldow);
sprintf(ptr,"%s",days_of_week[ldow]);
}
///////////////////////////////////////////////////////////////////////////////
byte ds1307_bin2bcd(byte binary_value){
byte temp;
byte retval;
temp = binary_value;
retval = 0;
while(1){
if(temp >= 10){
temp -= 10;
retval += 0x10;
}else{
retval += temp;
break;
}
}
return(retval);
}
byte ds1307_bcd2bin(byte bcd_value){
byte temp;
temp = bcd_value;
temp >>= 1;
temp &= 0x78;
return(temp + (temp >> 2) + (bcd_value & 0x0f));
}
///////////////////////////////////////////////////////////////////////////////
-
Tu problema no esta en el programa, sino en la alimentacion del DS1307 y/o el cristal del DS1307, sea layout,etc
Tuve un compañero que hizo un proyecto con el mismo, Y luego de renegar y pasarle lo mismo, con un mejor filtrado y un mejor layout del oscilador (como lo pide el datasheet del DS1307) ademas de poner a GND el encapsulado del cristal logro una muy buena mejoria. Paso de unos minutos cada 10 dias a segundos al mes.
-
De cualquier forma, un cristal de cuarzo tiene pequeños corrimientos de su fcia. nominal.
Así que es de esperarse algo cómo ésto.
No pienses que un DS1307 sea un reloj atómico.
Las pequeñas diferencias las corrijes por soft, por ejem. a cada hora adelantas o retrasas la diferencia en una hora.
Por ejem si dices que adelanta 2' en 15 días, es decir adelanta aprox .33333 segundos por hora.
Entonces restas .33333 a cada hora, o mejor restas un segundo cada tres horas.
-
Mi compañero tambien intento arreglarlo asi... no pudo... El error no era constante. Por lo tanto no funciono de esa forma.
Ademas 0.33s por HORA es una locura de error. Y tenes un reloj super chino que mantiene mejor el horario con componentes mucho mas baratos :3
-
El detalle de que el corrimiento no es cte. es debido al factor temperatura, entre otros.
Yo utilizo ese método y el error lo he reducido a prácticamente algunos segundos de corrimiento por año.
En el propio programa que realicé, me permite modificar el valor de una variable que se traduce a sumar o restar X segundos por día.
Por otro lado .333" por hora puede resultar una locura de error, pero ese es el cálculo que da en función de los datos que expuso el compañero.
-
Un buen reloj mecánico adelanta o atrasa como máximo 5 segundos/día.
Un oscilador de cuarzo barato puede darte esa misma precisión, pero se puede compensar para mejorarlo. Si está bien compensado debería darte unos 5 segundos/mes de error máximo.
-
Hola, hice un temporizador basado en un DS1307 y el tema que tengo es que, estando alimentado, la hora, una vez ajustada. se adelanta, es decir se adelanta unos 2 min cada 10 a 15 dias y no se porque, ya que no uso ningun comando que la pueda modificar. use la libreria de redpic
Si el cristal tiene una exactitud de 100ppm, eso significa que va a tener un error máximo de = 0.000100 * (24 *60 * 60) = 8,6 segundos/dia
En 15 días el error máximo será de 2 minutos.
Si compras un cristal mejor (de 30 ppm) y tienes suerte, el error no será mayor de 10ppm y mejorará mucho la exactitud.
-
por ahi lei gente quejandose de la falta de presición del ds1307, y que existe un tal ds3231 modulo arduinero que mejora muchisimo el problema respecto al primero....
-
Gracias a todos por responder. Yo uso un modulo "tiny rtc" ó similar, por lo que tendria que descartar a priori errores por el tema de la placa. Sin embargo ya me pasaba con otra placa que tuve que dejar de producir porque no le encontre el defecto. Esta placa es un diseño nuevo.Lo otro raro es que como dije, la hora varia independientemente de que yo consulte la hora o no, incluso si dejo el reloj desenchufado, alimentado solo por la pila.Les pasare una foto de la placa. (http://www.todopic.com.ar/foros/imgtiny/33v1du1.jpg)
La placa tiene un modulo bluetooth y le puse un capacitor de filtrado en la alimentacion del reloj. Ademas funciona a 12V.
-
Obviamente que la hora seguirá sufriendo corrimiento independientemente de si consultas la hora o no, de si está energizado o no. Ya que la base de tiempo trabaja independiente.
-
Yo utilizo muchisimo el DS1307 por que tengo un proyecto en la calle funcionando con mas de 100 unidades vendidas y no tengo esos problemas. Atrasa o adelanta lo normal que hace cualquier reloj casio o reloj de pared, etc..
De modulos RTC decirte que el único que mejores resultados me ha dado ha sido el de robotdyn, mas caro, no trae memoria eeprom como el de tiny pero no importa..
De todas formas, en mis diseños para el ds1307 uso este resonador:
https://lcsc.com/product-detail/SMD-Crystals_SHENZHEN-CRYSTAL-TECH-7MC32768F12UC_C252400.html
Este encapsulado va metalizado internamente y conectado al plano de tierra " Sin tocar lo que es el cuarzo" al cual hay que hacerle un layout totalmente separado de tierra. Algunos diseños sueldan el cuarzo al plano de tierra y eso he comprobado que no les sienta muy bien.
Este que os pongo es complicado de soldar pero es el que mejor resultado me da.
Por otro lado hay que asegurarle al integrado una buena alimentación constante de 5V. Al pin de la batería Backup hay que colocarle un diodo 4147 en inverso se instale o no se instale la pila. He comprobado que la precisión mejora mucho con el diodo, especialmente cuando el integrado conmuta al perder la alimentación y pasa a usar la batería backup.
Por ultimo, utilizar las referencias del chip con certificado industrial. Es mucho mas estable con los cambios de temperatura.
Saludos.
-
El DS3231 lleva un cristal integrado y compensación de temperatura.
https://datasheets.maximintegrated.com/en/ds/DS3231.pdf
El error es menor de 30 segundos al año.
Puedes encontrar módulos por 1€, a mi me parece mejor opción.
-
De nuevo, gracias a todos. Como uso el tiny RTC o similares, no puedo agregarle el diodo. Creo que lo mejor será usar el ds3231. Tengo una libreria, voy a ver si la puedo hacer andar. Ya voy a pedir ayuda con eso si no la puedo hacer andar. Gracias a todos.
-
Si buscas precisión y tener el reloj siempre al segundo por mucho tiempo que pase, puedes probar con un módulo DCF77. Estos relojes se ajustan periódicamente de manera automática, por radio (onda larga), creo que con un reloj atómico. Hay varias emisoras en los distintos continentes, en Europa tenemos la de Alemania con un alcance de 1500Km.
Así te desentiendes por completo, sabes que el reloj siempre estará al segundo.
-
Si buscas precisión y tener el reloj siempre al segundo por mucho tiempo pase, puedes probar con un módulo DCF77. Estos relojes se ajustan periódicamente de manera automática, por radio (onda larga), creo que con un reloj atómico. Hay varias emisoras en los distintos continentes, en Europa tenemos la de Alemania con un alcance de 1500Km.
Así te desentiendes por completo, sabes que el reloj siempre estará al segundo.
Otra alternativa es un módulo GPS, que también está sincronizado con relojes atómicos. Un módulo barato de unos 10 € te dará un error máximo de 100ns.
https://www.ebay.es/itm/Modulo-arduino-GPS-GY-NEO6MV2-nano-UNO-MEGA/252266235582?hash=item3abc3d46be:g:iycAAOSwhfRcOIvD
Ambos tienen el problema de necesitar recibir la señal de radio de onda larga o de los satélites gps y en muchas ocasiones esto no es nada fácil.
Saludos.
-
Ha pasado bastante tiempo que se publicó este asunto, yo he tenido ese problema desde hace tiempo, el problema es la marca o el fabricante del DS1307, al principio utilicé DS1307 de Maxim (Dallas Semi..) durante años la hora ha sido precisa, ultimamente compré DS1307 por aliexpress, ya que cuestan 10 por $0.81 desde ese momento empezaron mis dolores de cabeza, se adelanta 4 a 5 min cada 7 dias, con lo cual tuve que detener la producción y equipos devueltos. Volví a comprar los Maxim originales (Digikey, Mouser etc. a $3.5) y volvió la precisión. Comprobado!
-
Los cristales con menos ppm son los de placas madre, comprate de las antiguas q esten malogradas y pruebas, tambien hay veces q las golpean y se aumentan su ppm :?