En este tutorial trabajaremos con el Modulo RTC (Real Time Clock) DS1307, podremos saber la hora exacta, día mes año e incluso el día de la semana, a su vez gracias a una EEPROM que trae el modulo podemos guardar los datos sin que se borren al apagar el Arduino.
Agregando el modulo El RTC a nuestro Arduino es como darle un reloj y un calendario, con el DS1307 nuestro Arduino sabrá la hora exacta como segundos, minutos y horas. También podremos saber el día del mes, día de la semana, mes, y año. EL ds1307 tiene implementado su calendario hasta el 2100 y tiene en cuenta también los años bisiestos.
La comunicación entre el Arduino y el Modulo RTC es por I2C (pines SDA y SCL), También tiene un pin (SQ) que envía un pulso cada segundo (1 Hz), que nos puede servir para sincronizar otros componentes o para realizar un contador de segundos. A su vez, el modulo tiene un espacio para soldar un DS18B20 (sensor de temperatura) y acceder a este a través del pin DS
Al reverso tiene un socket para insertar una batería de 3V, que le permite al RTC mantener en funcionamiento la hora y fecha cuando se apague el Arduino o se le quiete la alimentación principal. Esta batería dependiendo de la marca y del tiempo apagado, puede durar desde los 3 hasta los 10 años aproximadamente.
Este módulo también trae una memoria no volátil, una EEPROM AT24C32 con capacidad para 32Kbit o 4Kbytes y también se comunica con el Arduino a través del bus I2C, bus que comparte con el DS1307, de esta forma solo necesitamos 2 pines del Arduino para controlar el RTC y EEPROM del Módulo.
Conexiones entre Modulo RTC DS1307 y Arduino
Adaptador LCD a I2C | Arduino Uno, Nano, Mini. | Arduino Mega , DUE | Arduino Leonardo |
---|---|---|---|
SCL | A5 | 21 | 3 |
SDA | A4 | 20 | 2 |
VCC | 5V | 5V | 5V |
GND | GND | GND | GND |
SCL | A5 | 21 | 3 |
Como se observa la conexión es como cualquier conexión I2C.
Librería para el RTC DS1302
Para este ejemplo usaremos la librería RTClib de Adafruit, librería que pueden descargarlo en:
https://github.com/adafruit/RTClib
Necesitamos descargar e importar dicha librería al IDE de Arduino.
Actualizando la Hora y fecha de nuestro DS1307
Cuando adquirimos un DS1307, al no traer su pila, no tiene la hora actualizada, cada vez que quitamos la pila el DS1307 pierde la hora, estableciéndose como hora 0:0:0 y fecha 00/00/00,
Este ejemplo solo se utiliza para poner a la hora nuestro DS1307:
#include <Wire.h> #include "RTClib.h"
RTC_DS1307
rtc; void setup () {
Serial
.begin(9600); rtc.begin(); //Inicializamos el RTC
Serial
.println("Estableciendo Hora y fecha..."); rtc.adjust(
DateTime
(F(__DATE__), F(__TIME__)));
Serial
.println("DS1307 actualizado con la hora y fecha que se compilo este programa:");
Serial
.print("Fecha = ");
Serial
.print(__DATE__);
Serial
.print(" Hora = ");
Serial
.println(__TIME__); } void loop () { }
De esta forma cada vez que el Arduino se enciende o se reinicia, el Arduino actualizara al DS1307 con la hora que fue compilado el programa.
Después de cargar el código anterior, tan pronto termine la carga Arduino actualizará la hora, pero cada vez que se habré el monitor serial o se reinicie el Arduino, nuevamente vuelve a actualizase con la misma hora de compilación.
El monitor serial solo nos sirve para verificar que nuestro programa es correcto. Después de esto hay que compilarlo y cargarlo de nuevo, para que tenga la hora correcta.
Después de cargar este programa se debe cargar otro distinto, o uno en blanco, para evitar que se esté actualizando con la misma hora de compilación cada vez que se reinicia o enciende el Arduino.
Si deseamos actualizar a una hora y fecha en específico deben de modificar a la siguiente línea de código:
rtc.adjust(
DateTime
(2016,6,10,18,29,0));//2016,Junio,10,18 h,29 min,0 seg
Obteniendo Hora y Fecha del DS1307
En este ejemplo realizaremos la lectura de los segundos, minutos y horas del DS1307, y a su vez también obtendremos la fecha.
Para realizar este ejemplo usamos el siguiente código:
#include <Wire.h> #include "RTClib.h"
RTC_DS1307
rtc; int segundo,minuto,hora,dia,mes; long anio; //variable año
DateTime
HoraFecha; void setup () {
Serial
.begin(9600); rtc.begin(); //Inicializamos el RTC } void loop () { HoraFecha = rtc.now(); //obtenemos la hora y fecha actual segundo=HoraFecha.second(); minuto=HoraFecha.minute(); hora=HoraFecha.hour(); dia=HoraFecha.day(); mes=HoraFecha.month(); anio=HoraFecha.year(); //Enviamos por el puerto serie la hora y fecha.
Serial
.print("hora = ");
Serial
.print(hora);
Serial
.print(":");
Serial
.print(minuto);
Serial
.print(":");
Serial
.print(segundo);
Serial
.print(" Fecha = ");
Serial
.print(dia);
Serial
.print("/");
Serial
.print(mes);
Serial
.print("/");
Serial
.print(anio);
Serial
.println(); delay(1000); }
Como se observa el código es simple y fácil de entender
En el void Setup solamente inicializamos el RTC y en void loop() realizamos la lectura del DS1307, esto se hace en una sola línea de código:
HoraFecha = rtc.now(); //obtenemos la hora y fecha actual
Cada vez que se llama a rtc.now se actualiza la hora y se guarda en el objeto HoraFecha que es de la clase DateTime propia de la librería RTClib
Seguidamente guardamos la hora y fecha en variables separadas, pero también podemos trabajar directamente con el objeto HoraFecha si lo deseamos por ejemplo: HoraFecha. minute()
A continuación mostramos el monitor serial de este ejemplo:
A este ejemplo, podemos agregar variables tipo cadena para mostrar o tener la fecha en formato de texto, por ejemplo para el nombre de los días de la semana y los nombres del mes.
El ejemplo muestra los cambios para mostrar la fecha de forma textual:
#include <Wire.h> #include "RTClib.h"
RTC_DS1307
rtc; char nombreDia[7][12] = {"Domingo", "Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado"}; char nombreMes[12][12]= {"Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"}; int segundo,minuto,hora,dia,mes,diaDeLaSemana; long anio; //variable año
DateTime
HoraFecha; void setup () {
Serial
.begin(9600); rtc.begin(); //Inicializamos el RTC } void loop () { HoraFecha = rtc.now(); //obtenemos la hora y fecha actual segundo=HoraFecha.second(); minuto=HoraFecha.minute(); hora=HoraFecha.hour(); dia=HoraFecha.day(); mes=HoraFecha.month(); anio=HoraFecha.year(); diaDeLaSemana=HoraFecha.dayOfTheWeek(); //Enviamos por el puerto serie la hora y fecha.
Serial
.print(hora);
Serial
.print(":");
Serial
.print(minuto);
Serial
.print(":");
Serial
.print(segundo);
Serial
.print(" , ");
Serial
.print(nombreDia[diaDeLaSemana]);
Serial
.print(" ");
Serial
.print(dia);
Serial
.print(" de ");
Serial
.print(nombreMes[mes-1]);
Serial
.print(" del ");
Serial
.print(anio);
Serial
.println(); delay(1000); }
La salida del monitor serial es el siguiente:
Luz con encendido y apagado automático
En este ejemplo mostraremos el código para encender un foco, o una salida digital que puede ser un motor, un electrodoméstico, una lámpara reflectora, etc, en un horario determinado por nuestro programa.
Por ejemplo para encender la luz de nuestra fachada todos los días de 7:00pm a 11:00pm, o para encender una bomba o electroválvula para establecer un horario de riego en un jardín, etc.
El ejemplo que mostramos a continuación activa la salida digital 2 de lunes a viernes de 6:30 pm a 11:30pm
#include <Wire.h> #include "RTClib.h"
RTC_DS1307
rtc; int segundo,minuto,hora,dia,mes,diaDeLaSemana;
DateTime
HoraFecha; void setup () {
Serial
.begin(9600); rtc.begin(); //Inicializamos el RTC pinMode(2, OUTPUT); } void loop () { HoraFecha = rtc.now(); //obtenemos la hora y fecha actual segundo=HoraFecha.second(); minuto=HoraFecha.minute(); hora=HoraFecha.hour(); diaDeLaSemana=HoraFecha.dayOfTheWeek(); //0:Dominogo, 1:Lunes, 2:Martes ... float horas=hora+minuto/60.0; //condicion: >Domingo y 6.30pm y <11.30pm if(diaDeLaSemana>0&&diaDeLaSemana<7 && horas>18.5&&horas<23.5) { digitalWrite(2, HIGH);
Serial
.print("Salida digital 13 = ON"); } else { digitalWrite(2, LOW);
Serial
.print("Salida digital 13 = OFF"); } //Enviamos por el puerto serie la hora y fecha.
Serial
.print(" hora = ");
Serial
.print(hora);
Serial
.print(":");
Serial
.print(minuto);
Serial
.print(":");
Serial
.print(segundo);
Serial
.print(" dia de La semana = ");
Serial
.print(HoraFecha.dayOfTheWeek());
Serial
.println(); delay(1000); }
Para cambiar de horario solo hay que modificar la condición, notar que los minutos convertimos a horas para trabajar la condición de forma más corta.
Los serial println() solo los usamos para fines demostrativos pues solo es para monitorear el estado:
Librería para la EMPROM AT24C32
La librería del RTC DS1307 también tiene funciones para usar la EEPROM AT24C32, pero nosotros usaremos otra librería, más especializada y con mayor cantidad de funciones:
Usaremos la librería AT24CX escrita por Christian Paul, librería que lo pueden descargar desde su GitHub:
AT24CX Library: https://github.com/cyberp/AT24Cx
Con esta librería podemos programar las siguientes memorias EEPROM: AT24C32, AT24C64, AT24C128, AT24C256 y AT24C512
Lectura y escritura en la EEPROM AT24C32
En este ejemplo guardaremos datos en nuestra EEPROM y posteriormente realizaremos la lectura de los datos guardados.
El código para manejar la EEPROM es el siguiente:
#include <Wire.h> #include <AT24CX.h> AT24C32 EepromRTC; void setup() {
Serial
.begin(9600); } void loop() { // read and write byte byte variable_byte=235; int variable_int=3000; long variable_long=48300011; float variable_float=3.14; char cadena[30] = "Naylamp Mechatronics";
Serial
.println("Guardando datos en la EEPROM..."); EepromRTC.write(1,variable_byte); // posiscion 1:ocupa 1 byte de tamaño EepromRTC.writeInt(2,variable_int); // posiscion 2:ocupa 2 bytes de tamaño EepromRTC.writeLong(4,variable_long); // posiscion 4: ocupa 4 bytes de tamaño EepromRTC.writeFloat(8,variable_float); // posiscion 8:ocupa 4 bytes de tamaño EepromRTC.writeChars(12, cadena, 30);// posiscion 16 y 20 bytes de tamaño
Serial
.println("Leyendo datos guardados..."); byte a = EepromRTC.read(1); int b = EepromRTC.readInt(2); long c = EepromRTC.readLong(4); float d = EepromRTC.readFloat(8); char cadena2[30]; EepromRTC.readChars(12,cadena2,30);
Serial
.print("Dato byte: ");
Serial
.println(a);
Serial
.print("Dato int: ");
Serial
.println(b);
Serial
.print("Dato long: ");
Serial
.println(c);
Serial
.print("Dato float: ");
Serial
.println(d);
Serial
.print("Dato Cadena : ");
Serial
.println(cadena2);
Serial
.println(); delay(5000); }
En el ejemplo anterior es una muestra de cómo leer y escribir datos en la EEPROM AT24C32, se muestra la forma de escribir diferentes tipos de variables.
Cada posición de la memoria es de un byte, si guardamos una variable debemos tener en cuenta el tamaño en bytes de esa variable, y no usar esas posiciones de memoria para guardar otros datos, pues borraríamos el dato inicial.
Podemos guardar en cualquier posición, por ejemplo un dato en la posición 10, otro en la posición 100 y otro en la posición 1500, la cosa es asegurarnos que los datos no se crucen. Para la EEPROM AT24C32, la primera posición es 0 y la posición máxima que podemos usar es de 4095, pues la memoria es de 4kBytes (4096Bytes) de tamaño
A continuación mostramos la salida del monitor serial del ejemplo: