UN RELOJ CON EL DS1307
Actualmente, cuando realizamos proyectos que requieren cierto nivel de flexibilidad, pensar en utilizar un microcontrolador siempre es una buena idea y ya puestos en ‘harina’ (como decimos en España), siempre que el proyecto lo requiera, es interesante, la aplicación de un RTC, es decir, un reloj en tiempo real. Sin embargo, también es cierto que en estos proyectos, estamos limitados a cierto número de E/S que acaban por ser demasiado limitadas y es entonces, es cuando se hace necesario el uso del I2C bus, el cual debemos considerar ya que, nos dará un gran servicio, simplemente con el uso de dos hilos o patillas del proyecto. Más información sobre el I2C bus en este sitio.
Para estos casos, ©Dallas actualmente ©Maxim o ©Cypress, entre otros, como veremos, ponen a nuestra disposición un pequeño dispositivo, capaz de mostrarnos información sobre segundos, minutos, horas, día, fecha, mes y año, con una sola consulta. El DS1307 funciona como un dispositivo esclavo en el bus I2C.
EL DS1307.
Aunque de forma superficial, diré que el DS1307 es un reloj/calendario de baja potencia, completo con 56 bytes de SRAM no-volátil. Como ya se ha mencionado, el reloj/calendario del DS1307, provee información de segundos, minutos, horas, día, fecha, mes y año. La fecha al final del mes durante los meses con menos de 31 días, se ajusta automáticamente e incluye las correcciones para el año bisiesto. El reloj funciona en cualquiera de los formatos de hora 24 o 12 horas con indicador AM/PM. El DS1307 tiene un circuito integrado en el sensor de energía que detecta los fallos de alimentación y cambia automáticamente a la fuente de respaldo de seguridad.
El acceso a los datos, se obtiene mediante la aplicación de una condición de inicio (start) y la prestación de un código de identificación del dispositivo (0x68), seguido de una dirección de registro. Los registros posteriores se puede acceder de forma secuencial. El DS1307 viene en un paquete de 8-pines DIP, además de otros formatos. El DS1307 cuenta en formato BCD.
El DS1307 utiliza un cristal externo de 32.768kHz. El circuito oscilador no necesita resistencias o condensadores externos para funcionar. Puede encontrar más información sobre el DS1307 en la red y también en este sitio.
Para conocer la estructura básica de un programa de Arduino, véase a partir de la página 7 de: «Arduino Programming Notebook by Brian Evans«
Usando Arduino con el Atmega168 y un DS1307 (real time clock), vamos a tratar de poner en funcionamiento el DS1307 por medio de dos cables (I²C) o pines digitales D4 y D5 de Arduino. Estos dos pines SDA y SCL en algunos Arduinos no necesitan de las típicas RPA (Resistencias de Polarización a Alto) ya que disponen de unos puentes (jumps) para su uso, revise su Arduino por si los dispone, lo propio es que tenga que conectar una resistencia (de entre 4k7 y 10k) entre el positivo y el pin SDA y otra al pin SCL, debido a que estos, se presentan con colector abierto o drenador abierto, revise el DS para más información.
Viendo la sencillez del circuito anterior, resulta evidente que no debe crearnos desasosiego poner en practica este proyecto, nos permitirá poner en marcha el reloj del DS1307 con la ayuda de un cristal, nuestro Arduino con un sencillo programa y una batería del tipo botón de 3.2V la cual mantendrá el oscilador interno cuando desconectemos la tensión de alimentación.
Esta es la foto (por ambos lados), que muestra el montaje que realice con los pocos componentes que lleva. Respecto del cristal de cuarzo, como se aprecia, estoy utilizando uno que desguacé, pertenecía a un reloj de pulsera, su precisión es realmente buena, por lo que llevo en pruebas, desvía menos de un segundo por mes, al menos eso es lo que muestra respecto del reloj de mi PC. Todos los componentes, por unas pocas monedas, alrededor de 4€ o poco más, no siempre es necesario adquirir materiales, es conveniente reciclar componentes de montajes anteriores.
En la imagen anterior, se puede apreciar los 5 espadines que he incluido para una conexión más rápida a los distintos anclajes, como un zócalo o al propio protoboard. El circuito impreso (PCB) que corresponde a este circuito se muestra en la siguiente imagen, se incluyen las RPA del esquema.
PRUEBAS CON CÓDIGOS.
Para ser sinceros, diré que he probado bastantes códigos que circulan por la red, si bien es cierto, todos funcionan, unos atrasan y otros adelantan su conteo, naturalmente he hecho ciertos ajustes en los tiempos de alguno de esos códigos, en especial en los que más se adaptaban a mi idea básica y con ello he adquirido cierta destreza en adaptar unos y otros a unas necesidades que me impuse a mi mismo, para lograr «mi reloj«.
Al principio, tuve problemas con el bus I²C, así que, tuve que consultar el foro, gracias a los inestimables consejos y ayudas de los «Maestros» que por ahí circulan, he ido superando los obstáculos que cada día se presentaban. Si me piden consejo; aconsejo que, no se pierda la calma, ni debe bajarse la guardia, hay que perseverar y siempre se puede lograr un resultado adecuado a nuestros esfuerzos, eso es lo que hay que hacer para superarse.
También, tuve que leer muchas hojas de datos de los fabricantes, alguna, con el DS1307, hasta me atreví a hacer una traducción libre al español, ya que encontré muy poco al respecto, en nuestro idioma. El leer estas hojas de características es una fuente de información muy aconsejable para poder sacar sus conclusiones y poner en acción nuestras ideas.
Puesta en práctica.
Y así, empecé con los códigos, con este que sigue y otros, saque conclusiones de cómo proceder para extraer ciertos datos y sobre todo la forma de cómo hacerlo y presentarlo a mi manera.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
// // Maurice Ribble // 4-17-2008 // http://www.glacialwanderer.com/hobbyrobotics // Este codigo prueba el reloj DS1307 en tiempo real en la placa Arduino. // El DS1307 trabaja en binario codificado en decimal o BCD. Usted puede // buscar BCD en Google si no le es familiar. Puede generar una onda // cuadrada, pero no expongo esto en este codigo. Vease el // DS1307 por sus capacidades. // // Modificado, para hispavila.com // #include <Wire.h> // #define DS1307_I2C_ADDRESS 0x68 // Convierte números normales decimales a BCD (binario decimal codificado) byte decToBcd(byte val) { return ( (val/10*16) + (val%10) ); } // Convierte BCD (binario decimal codificado) a números normales decimales byte bcdToDec(byte val) { return ( (val/16*10) + (val%16) ); } // Parar el DS1307, pero esto tiene el efecto secundario de segundos que se // ponen a 0 probablemente solo quiera usar esto para pruebas. /* void stopDs1307() { Wire.beginTransmission(DS1307_I2C_ADDRESS); Wire.send(0); Wire.send(0x80); Wire.endTransmission(); } */ // 1) Sets the date and time on the ds1307 // 2) Starts the clock // 3) Sets hour mode to 24 hour clock // Assumes you're passing in valid numbers void setDateDs1307(byte second, // 0-59 byte minute, // 0-59 byte hour, // 1-23 byte dayOfWeek, // 1-7 byte dayOfMonth, // 1-28/29/30/31 byte month, // 1-12 byte year) // 0-99 { Wire.beginTransmission(DS1307_I2C_ADDRESS); Wire.send(0); Wire.send(decToBcd(second));// 0 a bit 7 inicia el reloj Wire.send(decToBcd(minute)); Wire.send(decToBcd(hour));// Para 12 hora am/pm usted tiene que poner // el bit 6 (tambien tiene que cambiar readDateDs1307) Wire.send(decToBcd(dayOfWeek)); Wire.send(decToBcd(dayOfMonth)); Wire.send(decToBcd(month)); Wire.send(decToBcd(year)); Wire.endTransmission(); } // Establece la fecha y el tiempo del ds1307 void getDateDs1307(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year) { // Resetea el registro puntero Wire.beginTransmission(DS1307_I2C_ADDRESS); Wire.send(0); Wire.endTransmission(); Wire.requestFrom(DS1307_I2C_ADDRESS, 7); // Alguno de estos necesitan enmascarar, ciertos bits son bits de control *second = bcdToDec(Wire.receive() & 0x7f); *minute = bcdToDec(Wire.receive()); *hour = bcdToDec(Wire.receive() & 0x3f);// change this if 12 hour am/pm *dayOfWeek = bcdToDec(Wire.receive()); *dayOfMonth = bcdToDec(Wire.receive()); *month = bcdToDec(Wire.receive()); *year = bcdToDec(Wire.receive()); } void setup() { byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; Wire.begin(); Serial.begin(9600); // Cambie estos valores a los que usted quiere poner su reloj. // Usted probablemente solo quiere poner su reloj una vez y luego quitar // la llamada de setDateDs1307. /* // si desea poner en hora, active esta parte y luego vuelva a quitarla second = 00; minute = 15; hour = 21; dayOfWeek = 6; dayOfMonth = 19; month = 9; year = 9; setDateDs1307(second, minute, hour, dayOfWeek, dayOfMonth, month, year); */ } void loop() { byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); Serial.print("20"); if (year < 10) Serial.print("0"); Serial.print(year, DEC); Serial.print("/"); if (month < 10) Serial.print("0"); Serial.print(month, DEC); Serial.print("/"); if (dayOfMonth < 10) Serial.print("0"); Serial.print(dayOfMonth, DEC); Serial.print(" "); if (hour < 10) Serial.print("0"); Serial.print(hour, DEC); Serial.print(":"); if (minute < 10) Serial.print("0"); Serial.print(minute, DEC); Serial.print(":"); if (second < 10) Serial.print("0"); Serial.print(second, DEC); Serial.print(" Dia de la semana:"); // Serial.println(dayOfWeek, DEC); // Esto pone nombre del dia switch (dayOfWeek) { case 1: Serial.println(" Lunes"); break; case 2: Serial.println(" Martes"); break; case 3: Serial.println(" Miercoles"); break; case 4: Serial.println(" Jueves"); break; case 5: Serial.println(" Viernes"); break; case 6: Serial.println(" Sabado"); break; case 7: Serial.println(" Domingo"); break; } delay(1000); } |
He modificado un poco el código, tratando de adaptarlo a mi idea de lo que quiero, si lo compara con el original, se aprecia que he alterado la forma de presentación de los registros del DS1307 y además he añadido la presentación del día de la semana, me gusta más de esta forma, es algo personal.
Este código, no me acaba de convencer, no digo que no funcione, sólo que, quiero otra cosa. El sistema de conversión de decimal a binario y viceversa no es todo lo exacto que debe ser para un reloj que se parezca a un reloj, o yo no lo he entendido, lo siento, pero lo he probado y es lo que hay. Pero, usted debe probarlo y sacar sus conclusiones, no se fie de mis pruebas, usted puede tener más virtudes que yo.
Así que, yo probaré otro código. Bueno, el circuito que estoy utilizando para estas pruebas se puede ver en esta foto:
Vale, es cierto que la foto pertenece a la prueba de otro código, ya lo comentaré en su momento, pero, el montaje es el mismo, como se verá. De hecho, los pulsadores que se ven en la foto, no son necesarios y por lo tanto aunque no los quite de sus respectivos anclajes, no perturban el funcionamiento de los códigos que uso en cada momento y de esta forma, cuando el código lo requiere los utilizo y nada más que objetar.
Este que sigue, es otro código, con el cual se puede leer la información del registro de datos del reloj, recuerde las hojas de datos (DS data sheet), este registro es para no entorpecer el normal funcionamiento del cronómetro del DS1307 y poder extraer los datos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
<span style="color: #008000;">// // Leerhora.pde // // Este codigo solo lee el contenido del DS1307 // // http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1180908809 // // Modificado, para hispavila.com //</span> #include <Wire.h> int hour; int minute; int second; int month; int dayOfWeek; int dayOfMonth; int year; <span style="color: #008000;">//char* dow[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; //char* dow[7] = {"Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado", "Domingo"};</span> void setup() { Serial.begin(9600); Wire.begin(); } void loop() { <span style="color: #008000;">// Below required to reset the register address to 0.</span> Wire.beginTransmission(104); // transmit to device #104, the ds1307 Wire.send(0x00); Wire.endTransmission(); // stop transmitting Wire.requestFrom(104, 7); <span style="color: #008000;"> // request 7 bytes from slave ds1307, we'll assume </span> <span style="color: #008000;"> // it'll send them all even though it doesn't have to</span> second = Wire.receive(); minute = Wire.receive(); hour = Wire.receive(); dayOfWeek = Wire.receive(); dayOfMonth = Wire.receive(); month = Wire.receive(); year = Wire.receive(); <span style="color: #008000;">// Convertir todos los valores BCD que podrían tener "decenas" a decimal. </span> <span style="color: #008000;">// Mucha gente en arduino hace esto con shits pero esto lo veo más fácil.</span> hour=hour/16 * 10 + hour % 16; minute=minute/16 * 10 + minute % 16; second=second/16 * 10 + second % 16; dayOfMonth=dayOfMonth/16 * 10 + dayOfMonth % 16; month=month/16 * 10 + month % 16; year=2000 + year/16 * 10 + year % 16; if (year < 10) { Serial.print("0"); } Serial.print(year); Serial.print("/"); if (month < 10) { Serial.print("0"); } Serial.print(month); Serial.print("/"); if (dayOfMonth < 10) { Serial.print("0"); } Serial.print(dayOfMonth); Serial.print(" "); if (hour < 10) { Serial.print("0"); } Serial.print(hour); Serial.print(":"); if (minute < 10) { Serial.print("0"); } Serial.print(minute); Serial.print(":"); if (second < 10) { Serial.print("0"); } Serial.print(second); Serial.print(" "); Serial.print(" Dia de la semana:"); // Esto pone nombre del dia switch (dayOfWeek) { case 1: Serial.println(" Lunes"); break; case 2: Serial.println(" Martes"); break; case 3: Serial.println(" Miercoles"); break; case 4: Serial.println(" Jueves"); break; case 5: Serial.println(" Viernes"); break; case 6: Serial.println(" Sabado"); break; case 7: Serial.println(" Domingo"); break; } delay(1000); } |
De nuevo mi impronta, la presentación y el día de la semana. El siguiente paso, es de esperar, buscar y revisar hojas de datos y ejemplos de la red.
He encontrado un código con el que puedo interactuar, es decir, puedo poner la hora en cualquier momento sin necesidad de codificar y cargar el código cada vez, se trata de usar tres pulsadores para cargar los minutos y hora del momento actual. Vaya que más puedo pedir. Revise este código y trate de comprender que hace cada subrutina y hagas sus modificaciones a su gusto. Aquí está:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
<span style="font-size: small;">// RTC con DS1307 // // Se trata de un reloj en tiempo real con el DS1307. // // // Controlado por 3 pulsadores. Los 3 pulsadores son N.A. van a masa // SW0 al pin D4, el SW1 al pin D5 y el SW2 al pin D6. Un pulsador SW0 para // los segundos, un SW1 para para los minutos y el tercero SW2 pulsador las horas. // // Modificado por: V. Garcia, para hispavila.com // #include <Wire.h> // specify use of Wire.h library. byte blinkPin = 13; // LED byte SW0 = 4; // para los segundos byte SW1 = 5; // para los minutos byte SW2 = 6; // para las horas void setup() { Wire.begin(); // join i2c bus (address optional for master) Serial.begin(9600); pinMode(blinkPin, OUTPUT); digitalWrite(blinkPin, 0); pinMode(SW0, INPUT); // for this use a slide switch pinMode(SW1, INPUT); // N.O. push button switch pinMode(SW2, INPUT); // N.O. push button switch digitalWrite(SW0, HIGH); // pull-ups on digitalWrite(SW1, HIGH); digitalWrite(SW2, HIGH); } void loop() { Wire.beginTransmission(0x68); Wire.send(0); Wire.endTransmission(); Wire.requestFrom(0x68, 7); byte secs = Wire.receive(); byte mins = Wire.receive(); byte hrs = Wire.receive(); byte day = Wire.receive(); byte date = Wire.receive(); byte month = Wire.receive(); byte year = Wire.receive(); // use DD-MM-YYYY Serial.print("La fecha es "); // "The date is " if (date < 10) Serial.print("0"); Serial.print(date, HEX); Serial.print("-"); if (month < 10) Serial.print("0"); Serial.print(month,HEX); Serial.print("-"); Serial.print("20"); if (year < 10) Serial.print("0"); Serial.print(year, HEX); Serial.print(" "); // hours, minutes, seconds Serial.print("La hora es "); // "The time is " if (hrs < 10) Serial.print("0"); Serial.print(hrs,HEX); Serial.print(":"); if (mins < 10) Serial.print("0"); Serial.print(mins, HEX); Serial.print(":"); if (secs < 10) Serial.print("0"); Serial.print(secs, HEX); Serial.print(" "); Serial.print(" Dia de la semana:"); // Esto pone nombre del dia switch (day) { case 1: Serial.println(" Lunes"); break; case 2: Serial.println(" Martes"); break; case 3: Serial.println(" Miercoles"); break; case 4: Serial.println(" Jueves"); break; case 5: Serial.println(" Viernes"); break; case 6: Serial.println(" Sabado"); break; case 7: Serial.println(" Domingo"); break; } // if (!(digitalRead(SW0))) set_time(); // hold the switch to set time delay(1000); //wait a second before next output toggle(blinkPin); } // toggle the state on a pin. // cambiar el estado de un pin</span> void toggle(int pinNum) { int pinState = digitalRead(pinNum); pinState = !pinState; digitalWrite(pinNum, pinState); } void set_time() { byte minutes = 0; byte hours = 0; while (!digitalRead(SW0)) // set time switch must be released to exit { while (!digitalRead(SW1)) // set minutes { minutes++; if ((minutes & 0x0f) > 9) minutes = minutes + 6; if (minutes > 0x59) minutes = 0; Serial.print("Minutos = "); if (minutes >= 9) Serial.print("0"); Serial.println(minutes, HEX); delay(750); } while (!digitalRead(SW2)) // set hours { hours++; if ((hours & 0x0f) > 9) hours = hours + 6; if (hours > 0x23) hours = 0; Serial.print("Horas = "); if (hours <= 9) Serial.print("0"); Serial.println(hours, HEX); delay(750); } Wire.beginTransmission(0x68); // activate DS1307 Wire.send(0); // where to begin Wire.send(0x00); //seconds Wire.send(minutes); //minutes Wire.send(0x80 | hours); //hours (24hr time) Wire.send(0x06); // Day 01-07 Wire.send(0x01); // Date 0-31 Wire.send(0x05); // month 0-12 Wire.send(0x09); // Year 00-99 Wire.send(0x10); // Control 0x10 produces a 1 HZ square wave on pin 7. Wire.endTransmission(); } } |
Como es de costumbre, mi aporte al código, en cuanto a adaptar el día de la semana, cosa que no viene en el original, no es mucho, pero ahí está. «Un grano de arena no es una playa, pero por algo se empieza».
Después de varias discusiones en foros, unos en inglés y otros en español, el intercambio de ideas me lleva a poner un poco más de mi parte, creo. El código original, se puede descargar de este enlace, si usted lo desea puede compararlo con el siguiente código tiene «calado».
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
<span style="font-size: small;">/* * RTC Control v.01 * by <http://www.combustory.com> John Vaughters * Credit to: * Maurice Ribble: * http://www.glacialwanderer.com/hobbyrobotics for RTC DS1307 code * * Con este código se puede establecer la fecha y la hora, recuperar la fecha y * la hora y usar la memoria adicional de un chip DS1307 RTC. * El programa también pone todo el espacio de memoria suplementario a 0xff. * Método de Comunicación Serie con el Arduino que, utiliza un Carácter * Mayúscula para cada orden descrita a continuación. * Comandos: T(00-59)(00-59)(00-23)(1-7)(01-31)(01-12)(00-99) - * * T(sec)(min)(hour)(dayOfWeek)(dayOfMonth)(month)(year) - * T pone la fecha del chip RTC DS1307. * Ejemplo para poner la fecha y hora: * 02-Feb-09 19:57:11 para el dia 3 de la semana, * use la orden - T1157193020209 // T11 57 19 3 02 02 09. * Q(1-2) -:- (Q1) Consulta Memoria (Q2) RTC - Volcado Memoria * * Modificado el: 19-09-2009. * by <http://www.hispavila.com> V. Garcia vers.01.2 */ #include "Wire.h" #define DS1307_I2C_ADDRESS 0x68 // Esta es la address I2C // Variables Globales int command = 0; // Comando de carácter, en formato ASCII, // enviados desde el puerto serie int i; long previousMillis = 0; // almacenará la última vez que Temp se ha actualizado byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; byte test; // Convierte números decimales normales a binario codificado decimal byte decToBcd(byte val) { return ( (val/10*16) + (val%10) ); } // Convierte binario codificado decimal a números decimales normales byte bcdToDec(byte val) { return ( (val/16*10) + (val%16) ); } // 1) Establece la fecha y la hora en el ds1307 // 2) Inicia el reloj // 3) Establece el modo de hora de reloj a 24 horas // Se supone que está pasando números válidos, probablemente // tendrá que controlar poner números válidos. void setDateDs1307() { // Uso de (byte) de conversión ASCII y matemáticas tipo para lograr el resultado. second = (byte) ((Serial.read() - 48) * 10 + (Serial.read() - 48)); minute = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48)); hour = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48)); dayOfWeek = (byte) (Serial.read() - 48); dayOfMonth = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48)); month = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48)); year = (byte) ((Serial.read() - 48) *10 + (Serial.read() - 48)); Wire.beginTransmission(DS1307_I2C_ADDRESS); Wire.send(0x00); Wire.send(decToBcd(second)); // 0 a bit 7 Inicia el reloj Wire.send(decToBcd(minute)); Wire.send(decToBcd(hour)); // Si quiere 12 horas am/pm tiene que poner // bit 6 (también tiene que cambiar readDateDs1307) Wire.send(decToBcd(dayOfWeek)); Wire.send(decToBcd(dayOfMonth)); Wire.send(decToBcd(month)); Wire.send(decToBcd(year)); Wire.endTransmission(); } // Consigue la fecha y el tiempo del ds1307 e imprime el resultado void getDateDs1307() { // Resetea el registro puntero Wire.beginTransmission(DS1307_I2C_ADDRESS); Wire.send(0x00); Wire.endTransmission(); Wire.requestFrom(DS1307_I2C_ADDRESS, 7); // A few of these need masks because certain bits are control bits second = bcdToDec(Wire.receive() & 0x7f); minute = bcdToDec(Wire.receive()); hour = bcdToDec(Wire.receive() & 0x3f); // Cambiar para 12 hora am/pm. dayOfWeek = bcdToDec(Wire.receive()); dayOfMonth = bcdToDec(Wire.receive()); month = bcdToDec(Wire.receive()); year = bcdToDec(Wire.receive()); if (hour < 10) Serial.print("0"); Serial.print(hour, DEC); Serial.print(":"); if (minute < 10) Serial.print("0"); Serial.print(minute, DEC); Serial.print(":"); if (second < 10) Serial.print("0"); Serial.print(second, DEC); Serial.print(" "); if (dayOfMonth < 10) Serial.print("0"); Serial.print(dayOfMonth, DEC); Serial.print("/"); // if (month < 10) Serial.print("0"); // esto para poner mes de 01 a 12 // Serial.print(month, DEC); switch (month) // pone el nombre del mes { case 1: Serial.print("Ene"); break; case 2: Serial.print("Feb"); break; case 3: Serial.print("Mar"); break; case 4: Serial.print("Abr"); break; case 5: Serial.print("May"); break; case 6: Serial.print("Jun"); break; case 7: Serial.print("Jul"); break; case 8: Serial.print("Ago"); break; case 9: Serial.print("Sep"); break; case 10: Serial.print("Oct"); break; case 11: Serial.print("Nov"); break; case 12: Serial.print("Dic"); break; } Serial.print("/"); Serial.print("20"); if (year < 10) Serial.print("0"); Serial.print(year, DEC); Serial.print(" Hoy es:"); // Dia de la semana: switch (dayOfWeek) // Esto pone nombre del dia { case 1: Serial.println(" Lunes"); break; case 2: Serial.println(" Martes"); break; case 3: Serial.println(" Miercoles"); break; case 4: Serial.println(" Jueves"); break; case 5: Serial.println(" Viernes"); break; case 6: Serial.println(" Sabado"); break; case 7: Serial.println(" Domingo"); break; } } void setup() { Wire.begin(); Serial.begin(57600); } void loop() { if (Serial.available()) { // busca carácter en serie y procesa si se encuentra command = Serial.read(); if (command == 84) { // Si command = "T" establecer fecha setDateDs1307(); getDateDs1307(); Serial.println(" "); } else if (command == 81) { //Si command = "Q" RTC1307 funciones de memoria delay(100); if (Serial.available()) { command = Serial.read(); if (command == 49) { // Si command = "1" RTC1307 Initialize Memory - // Todos los datos se establecen en 255 (0xff). // Por lo tanto 255 o 0 será un valor no válido. Wire.beginTransmission(DS1307_I2C_ADDRESS); //255 será el valor de inicio // y 0 se cosiderá un error que se produce // cuando el RTC está en modo de batería. Wire.send(0x08); // Ajusta el registro puntero un poco más allá // los registros de fecha/hora. for (i = 1; i <= 27; i++) { Wire.send(0xff); delay(100); } // las lineas comentadas que siguen, no parecen necesarias. // descomentar si procede. Wire.endTransmission(); getDateDs1307(); // Serial.println(": RTC1307 Initialized Memory"); } else if (command == 50) {// Si command="2" RTC1307 Volcado de Memoria getDateDs1307(); // Serial.println(": RTC 1307 Dump Begin"); Wire.beginTransmission(DS1307_I2C_ADDRESS); Wire.send(0x00); Wire.endTransmission(); Wire.requestFrom(DS1307_I2C_ADDRESS, 64); for (i = 1; i <= 64; i++) { test = Wire.receive(); Serial.print(i); Serial.print(":"); Serial.println(test, DEC); } // Serial.println(" RTC1307 Dump end"); } } } // Serial.print("Comando: "); // Serial.println(command); // Caracter comando echo en ASCII que se envió } command = 0; // reset command delay(100); } //******************The End****************/</span> |
Sin duda, hay algunos aportes que mejoran ostensiblemente el código final, también hay que destacar la presentación de los datos extraídos. Es cierto que el código es bastante extenso, sin embargo, considero que queda compensado con el resultado.
No creo necesario reproducir aquí lo que se ha descrito en el sitio del wiki, si bien es cierto que está en inglés.
En atención a las reiteradas llamadas para que se especifique con detalle la PCB usada en el reloj, se ha ampliado la parte que corresponde al montaje del mismo.
Como siempre, comentarios, criticas y sugerencias para mejorar este artículo, son bienvenidos y apreciados.
muy bueno gracias, pero por casualidad no tengras el programa para unirlo con un lcd
Gracias por tus palabras.
En cuanto a dotarlo de un LCD, no es muy complicado, en principio en la Red hay muchos códigos al respecto que te pueden servir.
Los tienes para LiquidCrystal, con 16×2 o 20×4 y también para GLCD de 84×46, depende de lo que desees.
Estoy preparando unos ejercicios con este tipo de GLCD, espero no demorarme mucho, ya sabes con el verano por medias…
Saludos.
Hola Vicente. Muy bueno el proyecto.
Yo utilicé en un principio el módulo comercial del DS1307 con Arduino pero me arrojaba un desfase de 1 minuto a la semana, si no recuerdo mal, y al cabo de unos meses era muy significativa la variación. Opté por el hermano mayor, el DS3231 y la precisión es envidiable. Comentaban en algún foro que al no tener compensacion de temperatura (TCXO) podía haber variación en el reloj. No sé si se debe a que el modulo era de China y el cristal que trae no es todo lo preciso que debería.
Gracias de nuevo y saludos.
No sabría que decirte de los productos de china, pues como siempre hay fabricantes de todo tipo y los honestos siempre se dejan ver con productos de calidad.
He tenido experiencias que satisfacen al exigente como al que más y en alguna excepción uno se topa con un desaliñado, ya sabes, hay de todo.
Los DS3231 son muy fiables y disponen de más opciones, memoria y posibilidad de dos alarmas. Que disfrutes con él.
Un saludo