Montar un reloj con Arduino, el módulo RTC DS3231 y mostrarlo en una pantalla LCD

Con este proyecto podremos regular la fecha y la hora actual. El módulo RTC DS3231 cuenta con una pila que en el caso de que se corte la fuente de alimentación, permitirá al reloj seguir guardando internamente la fecha y hora.

Montar un reloj con Arduino, el módulo RTC DS3231 y mostrarlo en una pantalla LCD

La comunicación del módulo se realiza a través del bus I2C y la tensión de alimentación es de 2.3 a 5.5V

Indice:

Poner el módulo RTC DS3231 en hora y mostrar por una pantalla LCD

Material necesario:

Esquema:

Primero, montamos las conexiones de la pantalla LCD con Arduino, se pueden seguir los pasos en el tutorial ¿Cómo conectar una pantalla LCD?

Para la conexión del módulo RTC, conectamos el GND del módulo con la masa en la protoboard, VCC con la alimentación en la protoboard, SDA con el pin analógico 4 de Arduino y SCL con el pin analógico 5 de la placa Arduino.

Esquema de Arduino con módulo RTC DS3231 y pantalla LCD

Explicación del código:

Al comenzar a trabajar, la hora del módulo no estará ajustada, vamos a comenzar poniéndolo en hora. Para indicar que finalmente está ajustado hacemos parapadear el LED de la placa de Arduino.

#include "Wire.h"
#define DS3231_I2C_ADDRESS 0x68

Incluimos la librería Wire.h, es la que contiene las funciones necesarias para usar el bus I2C en Arduino. En las placas Arduino SDA (línea de datos), corresponde con el pin analógico 4 y SCL (línea de reloj) con el pin analógico 5. En la segunda línea, definimos la dirección I2C para controlar y recibir datos del módulo RTC.

void setup(){
  byte segundos, minutos, hora, diaSemana, diaMes, mes, year;
  Wire.begin();
  pinMode(13, OUTPUT);
  /* poner en hora*/
  segundos = 0;
  minutos = 01;
  hora = 11;
  diaSemana = 1;
  diaMes = 21;
  mes = 12;
  year = 20;
  PonerFecha(segundos, minutos, hora, diaSemana, diaMes, mes, year);
}

En la función setup() definimos las varibles: segundos, minutos, hora, diaSemana, diaMes, mes y year como byte. Seguidamente, inicializamos la librería Wire: Wire.begin(), indicamos que el pin digital 13 funciona como salida, y damos valores a las variables:

  • segundos: tendrá un valor entre 0 y 59
  • minutos: entre 0 y 59
  • hora: tiene un valor entre 1 y 23
  • diaSemana: entre 1 y 7, donde 1 corresponde con lunes, 2 martes, 3 miercoles…
  • diaMes: es de 1 a 31
  • mes: sería de 1 a 12
  • year: de 0 a 99

Lo último, es la llamada a la función PonerFecha(), encargada de ajustar la fecha.

void loop(){
  digitalWrite(13, HIGH);   
  delay(1000);               
  digitalWrite(13, LOW);    
  delay(1000);
}

La función loop() solamente nos va ha indicar cuándo está terminado el ajuste del reloj, pediremos que se encienda y se apague el LED de la placa cambiando de HIGH a LOW.

byte decToBcd(byte val){
  return ( (val/10*16) + (val%10) );
}

Esta función la vamos a necesitar para pasar los datos de decimal a BCD, decimal codificado en binario.

void PonerFecha(
byte segundos,    // 0-59
byte minutos,       // 0-59
byte hora,          // 1-23
byte diaSemana,     // 1-7 1=Lunes, 7=Domingo
byte diaMes,      // 1-28/29/30/31
byte mes,           // 1-12
byte year           // 0-99
){
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0);
  Wire.write(decToBcd(segundos));
  Wire.write(decToBcd(minutos));
  Wire.write(decToBcd(hora));
  Wire.write(decToBcd(diaSemana));
  Wire.write(decToBcd(diaMes));
  Wire.write(decToBcd(mes));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}

En la función PonerFecha() comenzamos la transmisión con beginTransmission y seguidamente, escribimos los datos con la función write, para finalizar la transmisión utilizamos endTransmission.

Código completo:

#include "Wire.h"
#define DS3231_I2C_ADDRESS 0x68

byte decToBcd(byte val){
  return ( (val/10*16) + (val%10) );
}
 
void PonerFecha(
byte segundos,    // 0-59
byte minutos,       // 0-59
byte hora,          // 1-23
byte diaSemana,     // 1-7 1=Lunes, 7=Domingo
byte diaMes,      // 1-28/29/30/31
byte mes,           // 1-12
byte year           // 0-99
){
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0);
  Wire.write(decToBcd(segundos));
  Wire.write(decToBcd(minutos));
  Wire.write(decToBcd(hora));
  Wire.write(decToBcd(diaSemana));
  Wire.write(decToBcd(diaMes));
  Wire.write(decToBcd(mes));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}

void setup(){
  byte segundos, minutos, hora, diaSemana, diaMes, mes, year;
  Wire.begin();
  pinMode(13, OUTPUT);
  /* poner en hora*/
  segundos = 0;
  minutos = 01;
  hora = 11;
  diaSemana = 1;
  diaMes = 21;
  mes = 12;
  year = 20;
  PonerFecha(segundos, minutos, hora, diaSemana, diaMes, mes, year);
}
 
void loop(){
  digitalWrite(13, HIGH);   
  delay(1000);               
  digitalWrite(13, LOW);    
  delay(1000);
}

El código completo para mostrar la fecha y la hora en pantalla es el siguiente:

#include "Wire.h"
#include <LiquidCrystal.h>
#define DS3231_I2C_ADDRESS 0x68
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
 
byte bcdToDec(byte val){
  return ( (val/16*10) + (val%16) );
}

void ConseguirFecha(byte *segundos,byte *minutos,byte *hora,byte *diaSemana,byte *diaMes,byte *mes,byte *year){
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();
 
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
 
  *segundos     = bcdToDec(Wire.read() & 0x7f);
  *minutos      = bcdToDec(Wire.read());
  *hora         = bcdToDec(Wire.read() & 0x3f);
  *diaSemana    = bcdToDec(Wire.read());
  *diaMes       = bcdToDec(Wire.read());
  *mes          = bcdToDec(Wire.read());
  *year         = bcdToDec(Wire.read());
}
 
void setup(){
  byte segundos, minutos, hora, diaSemana, diaMes, mes, year;
  Wire.begin();
  lcd.begin(16, 2);
}
 
void loop(){
  byte segundos, minutos, hora, diaSemana, diaMes, mes, year;
  String s, m, d, mth, h, mty;
   
  ConseguirFecha(&segundos, &minutos, &hora, &diaSemana, &diaMes, &mes, &year);
 
  if (segundos < 10) { s = "0" + String(segundos); } else { s = String(segundos); }
  if (minutos < 10) { m = "0" + String(minutos); } else { m = String(minutos); }
  h = String(hora);
  if (diaMes < 10) { d = "0" + String(diaMes); } else { d = String(diaMes); }
  if (mes < 10) { mth = "0" + String(mes); } else { mth = String(mes); }
  if (year < 10) { mty = "0" + String(year); } else { mty = String(year); }
   
  char* days[] = { "NA", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa", "Do" };
   
  lcd.clear();
  
  lcd.setCursor(4,0);
  
  lcd.print(h + ":" + m + ":" + s);
  
  lcd.setCursor(1,1);
  
  lcd.print(String(days[diaSemana]) + " " + d + "/" + mth + "/20" + mty);
  delay(1000); // Esperamos un segundo
}

Una vez que el reloj está ajustado, para mostrarlo por la pantalla LCD, añadimos la librería LiquidCrystal.h, y definimos los pines con LiquidCristal lcd() utilizados para la conexión con la pantalla .

En la función setup() se añade la inicialización de la pantalla LCD.

En la función loop() hacemos que nos imprima los datos en la pantalla, para ello, primero hace una llamada a la función ConseguirFecha() y pasamos, a continuación, los datos a string para poder imprimirlos en pantalla.

En la función ConseguirFecha() obtenemos los datos del módulo RTC: se inicia la transmisión, reseteamos el registro del puntero y solicitamos los datos que necesitamos.

Reloj con pulsadores para cambiar hora y fecha

Tener dos programas para controlar el reloj es un poco farragoso. Nos parece más cómodo que se pueda cambiar la fecha y la hora a través de un menú, con pulsadores.

Material necesario:

  • Placa Arduino o compatible.
  • Módulo reloj RTC DS3231.
  • Pantalla LCD.
  • Potenciómetro.
  • Protoboard.
  • Cables.
  • 3 resistencia 10KΩ.
  • 3 pulsadores.

Esquema:

El esquema es el mismo que el anterior pero al que hemos añadido 3 pulsadores. El primero, lo vamos a utilizar para resetear y seleccionar la opción que queremos cambiar; va unido al pin digital 6 de la placa Arduino. El segundo pulsador, servirá para disminuir el valor y va unido al pin 5, y el tercer pulsador servirá para aumentar el valor y está unido al pin 4.

Esquema reloj Arduino con 3 pulsadores

Código:

En la función loop() comprobaremos si se tiene que ver la fecha y hora o queremos cambiarla. Para ello, tenemos la variable estadoActual que nos dirá si se ha presionado el botón reset (botón 1), este activará un contador de 0 a 7. Dependiendo de las veces que lo presionemos, nos llevará a las siguientes opciones:

  • primera presión: modificar la hora (el contador estaría en 1).
  • segunda pulsación: modificar los minutos (contador en 2).
  • tercera presión: modificar el día de la semana: lunes, martes, miércoles… (contador en 3).
  • cuarta pulsación: modificar el día del mes (contador en 4).
  • quinta presión: modificar el mes (contador en 5).
  • sexta pulsación: modificar el año (contador en 6).
  • séptima presión: vuelve a mostrar la fecha completa (el contador está de nuevo en 0).

Para la modificación de los datos creamos la función modificar_tiempo(), para mostrar la fecha y la hora en pantalla se llama a la función VerFecha().

#include "Wire.h"
#include <LiquidCrystal.h>
#define DS3231_I2C_ADDRESS 0x68
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
int estadoActual = 0;
int estadoUltimo = 0;
int contador = 0;
int MenosAnterior =0;
int estadoMas = 0;
int estadoMenos = 0;
int MasAnterior =0;

byte decToBcd(byte val){
  return ( (val/10*16) + (val%10) );
}

byte bcdToDec(byte val){
  return ( (val/16*10) + (val%16) );
} 

void ConseguirFecha(byte *segundos,byte *minutos,byte *hora,byte *diaSemana,byte *diaMes,byte *mes,byte *year){
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();
 
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
 
  *segundos     = bcdToDec(Wire.read() & 0x7f);
  *minutos      = bcdToDec(Wire.read());
  *hora         = bcdToDec(Wire.read() & 0x3f);
  *diaSemana    = bcdToDec(Wire.read());
  *diaMes       = bcdToDec(Wire.read());
  *mes          = bcdToDec(Wire.read());
  *year         = bcdToDec(Wire.read());
}
 
void VerFecha(){
    byte segundos, minutos, hora, diaSemana, diaMes, mes, year;
    String s, m, d, mth, h, mty;
     
    ConseguirFecha(&segundos, &minutos, &hora, &diaSemana, &diaMes, &mes, &year);
   
    if (segundos < 10) { s = "0" + String(segundos); } else { s = String(segundos); }
    if (minutos < 10) { m = "0" + String(minutos); } else { m = String(minutos); }
    h = String(hora);
    if (diaMes < 10) { d = "0" + String(diaMes); } else { d = String(diaMes); }
    if (mes < 10) { mth = "0" + String(mes); } else { mth = String(mes); }
    if (year < 10) { mty = "0" + String(year); } else { mty = String(year); }
     
    char* days[] = { "NA", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa", "Do" };
     
    lcd.clear();
    lcd.noBlink();
    
    lcd.setCursor(4,0);
    
    lcd.print(h + ":" + m + ":" + s);
    
    lcd.setCursor(1,1);
    
    lcd.print(String(days[diaSemana]) + " " + d + "/" + mth + "/20" + mty);   
}

void modificar_tiempo(int tipo){
  byte segundos, minutos, hora, diaSemana, diaMes, mes, year;
  ConseguirFecha(&segundos, &minutos, &hora, &diaSemana, &diaMes, &mes, &year);
  Serial.println("presionado");
  int suma = 0;
  int resta = 0;

  if(estadoMenos != MenosAnterior){
    if(estadoMenos == HIGH){
      resta = 1;
    }
  }
  if(estadoMas != MasAnterior){
    if(estadoMas == HIGH){
      suma = 1;
    }
  }
  
  if(tipo == 1){ // modificar la hora
    String h;
    h = String(hora);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.write("Modificar hora");
    lcd.setCursor(0, 1);
    lcd.print(h); 
    lcd.blink();
    if(resta == 1){
      hora = hora-1;
    }
    if(suma == 1){
      hora = hora+1;
    }
    if(hora > 23) hora=0;  
  }

  if(tipo == 2){ // modificar los minutos
    String m;
    m = String(minutos);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.write("Modificar minutos");
    lcd.setCursor(0, 1);
    lcd.print(m); 
    lcd.blink();
    if(resta == 1){
      minutos = minutos-1;
    }
    if(suma == 1){
      minutos = minutos+1;
    }
    if(minutos > 59) minutos=0;  
  }

  if(tipo == 3){ // modificar el día de la semana
    String d;
    d = String(diaSemana);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.write("Modificar dia semana");
    lcd.setCursor(0, 1);
    lcd.print(d); 
    lcd.blink();
    if(resta == 1){
      diaSemana = diaSemana-1;
    }
    if(suma == 1){
      diaSemana = diaSemana+1;
    }
    if(diaSemana == 8) diaSemana=1;
    if(diaSemana == 0) diaSemana=7;  
  }

  if(tipo == 4){ // modificar el día del mes
    String m;
    m = String(diaMes);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.write("Modificar dia mes");
    lcd.setCursor(0, 1);
    lcd.print(m); 
    lcd.blink();
    if(resta == 1){
      diaMes = diaMes-1;
    }
    if(suma == 1){
      diaMes = diaMes+1;
    }
    if(diaMes == 32) diaMes=1;
    if(diaMes == 0) diaMes=31;  
  }

  if(tipo == 5){ // modificar mes
    String ms;
    ms = String(mes);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.write("Modificar mes");
    lcd.setCursor(0, 1);
    lcd.print(ms); 
    lcd.blink();
    if(resta == 1){
      mes = mes-1;
    }
    if(suma == 1){
      mes = mes+1;
    }
    if(mes == 13) mes=1;
    if(mes == 0) mes=12;  
  }

  if(tipo == 6){ // modificar año
    String a;
    a = String(year);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.write("Modificar año");
    lcd.setCursor(0, 1);
    lcd.print(a); 
    lcd.blink();
    if(resta == 1){
      year = year-1;
    }
    if(suma == 1){
      year = year+1;
    }
    if(year == 100) year=1;
    if(year == 0) year=99;  
  }
    
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0);
  Wire.write(decToBcd(segundos));
  Wire.write(decToBcd(minutos));
  Wire.write(decToBcd(hora));
  Wire.write(decToBcd(diaSemana));
  Wire.write(decToBcd(diaMes));
  Wire.write(decToBcd(mes));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}

void setup(){
  byte segundos, minutos, hora, diaSemana, diaMes, mes, year;
  Wire.begin();
  lcd.begin(16, 2);
  //Serial.begin(9600);
  pinMode(6,INPUT);  // pulsador - menu
  pinMode(5,INPUT);  // pulsador - menos
  pinMode(4,INPUT);  // pulsador - mas
}
 
void loop(){
  estadoActual=digitalRead(6);
  estadoMenos=digitalRead(5);
  estadoMas=digitalRead(4);
  //Serial.println(estadoActual);
  if(estadoActual != estadoUltimo){
    if(estadoActual == HIGH){
      contador = contador +1;
      //Serial.println(contador);
    }
  }
  
  if(contador == 0){
    VerFecha();
    delay(1000);
  }else if(contador == 1){
    modificar_tiempo(1);  // modificar la hora
    delay(500);
  }else if(contador == 2){
    modificar_tiempo(2);  // modificar los minutos
    delay(500);
  }else if(contador == 3){
    modificar_tiempo(3);  // modificar dia de la semana
    delay(500);
  }else if(contador == 4){
    modificar_tiempo(4);  // modificar dias mes
    delay(500);
  }else if(contador == 5){
    modificar_tiempo(5);  // modificar mes
    delay(500);
  }else if(contador == 6){
    modificar_tiempo(6);  // modificar año
    delay(500);
  }else if(contador == 7){
    contador = 0;
    delay(1000);
  }
}

Sé el primero en comentar en «Montar un reloj con Arduino, el módulo RTC DS3231 y mostrarlo en una pantalla LCD»

Deja un comentario

Tu dirección de correo electrónico no será publicada.


*