Reloj digital con DS3231 y TM1637

Hola

Estoy haciendo un proyecto por que desde hace un rato tengo en el tintero, el cual quiero para uso personal, se trata de un reloj que me permita ver la hora en mi dormitorio de día y de noche, en la noche que no brille tanto como para que me quite el sueño y en el día que se pueda leer a simple vista.

Piezas:
DS3231 para el reloj y termómetro
TM1637 para el display de 7.4
Botones para interface
Arduino nano para desarrollo
Pilas AAA

Objetivos:
Muestra el tiempo en 12/24hrs
Muestra la temperatura en °C durante un pequeño lapso.
Ajuste de hora - minutos
Ajuste de lapso Temperatura
Ajuste de Brillo
Funciona con pilas
Señal de batería baja

Funciones del display:
Hay dos ciclos principales por decirlo de alguna manera, el primero es:
El que muestra la hora y la temperatura, esta ciclo muestra la hora y la temperatura en el lapso de un minuto y se repite al siguiente minuto, en este caso lo único que varia es el lapso en que se muestra la temperatura (de 2 a 10 seg), todo dentro del mismo minuto. Digamos que por ejemplo se ajuste a el lapso de la temperatura a 10 segundos la temperatura se mostrara dies segundos después la hora 50 segundos y así continuara repitiéndose.

El segundo ciclo principal estará dedicado a la configuración de los diferentes ajustes del reloj.
Los cuales serán la horas, minutos. Considero que las horas deben de grabarse en 24 hrs y después cambiarla a 12 antes de grabarla en el rtc si es necesario pero aun no se si el ds3231 pueda facilitarme esto y así evitar ciclos de reloj inecesarios, los minutos de 0 a 59 y la temperatura de 2 a 10.

Dentro de estos dos ciclos habrá un ciclo mas pequeño en tiempo pero no en funcionalidad que se encarga de leer los estados de los botones.

Por encima de estos ciclos deberá haber una condición para revisar cual de los dos ciclos principales es el que debe mostrarse y esta sera definido por el botón set/function, los botones aunque representan lo mismo, afectan a diferentes variables según el ciclo que este activo, lo cual describo a continuación:

Funciones de los botones:
-Mientras se muestra la hora(el principal ciclo) los botones de ajuste +/- ajustan el brillo. el botón set/function cambia entre 12 y 24 hrs.

-En los ajustes(el ciclo secundario) +/- ajustan las horas, minutos y lapso de temperatura, el botón set/function navega entre los diferentes parámetros.

-El botón set/funtion guarda cambios y cambia entre los dos ciclos principales pero solo si se mantiene presionado mas dos segundos.

Tengo las funciones pero me falta el núcleo del programa, aun no he encontrado la forma de manejar los diferentes ciclos con el uso de los botones, tengo una idea pero quizá este descuidando que esto debe funcionar con pilas aunque eso quizá se pueda arreglar mas adelante ya que tenga funcionando todo, quiero ver que me pueden recomendar.

El código:

//La tecla setFunction cambia las variables que seran afectadas por las teclas de cambio...
/*por ejemplo por defecto las teclas de cambio deberan manipular el valor de la luminocidad
   al precioar la tecla setFunction se cambia el valor que sera afectado por las teclas de cambio
   primeramente sera la hora, luego los minutos, luego el lapso de la temperatura.
*/


#include <Arduino.h>
#include <TM1637Display.h>//libreria para el lcd
#include "Wire.h"

#define DS3231_I2C_ADDRESS 0x68   //I2C RTC ADDRESS
#define CLK 2                     //CLK DISPLAY
#define DIO 3                     //DIO DISPLAY
TM1637Display display(CLK, DIO);  //OBJECT DISPLAY
//-------------------------------------------------BOTONES
#define up    9                   //self expl
#define down  8
#define set   7
//-------------------------------------------------VARIABLES
byte buttonUp, buttonDown, setFunction;  //VARIABLES DE ESTADO
byte second, minute, hour, lapTemp, temp, brillo; //variables globales de ajuste
int Count;
byte i = 0;   //variable de indice
byte data[4] = {0xff, 0xff, 0xff, 0xff} ; //debug
unsigned long bounceLap, timeLap, tempLap;
void setup() {
  Serial.begin(9600);             //DEbug
  //-------------------------------------------------Botones
  pinMode(up, INPUT_PULLUP);
  pinMode(down, INPUT_PULLUP);
  pinMode(set, INPUT_PULLUP);
  //-------------------------------------------------DS3231,TM1637 setup
  Wire.begin();
  display.setBrightness(0x0f);
  display.showNumberDec(8888);  //debug
}//--------------------------------------------------END SETUP
void loop() {
  while (millis() - timeLap <= 60000) {// este wile es el main while, se ejecuta siempre.
    readTime(&second, &minute, &hour);
    display.showNumberDec(hour, true, 2, 0);
    display.showNumberDec(minute, true, 2, 2);
    byte dots[0];

    dots[0] =  0b10000000 | display.encodeDigit(hour);
    if (hour >= 10)dots[0] =  0b10000000 | display.encodeDigit(hour - 10);
    if (hour >= 20)dots[0] =  0b10000000 | display.encodeDigit(hour - 20);

    if (second % 2)display.setSegments(dots, 1, 1);
    Serial.print(minute), Serial.print(":"), Serial.println(second);

    while (millis() - bounceLap >= 220ul  ) {//este while es el de los botones, aqui es donde se cambian las variables manual y evita el rebote.
      buttonUp = digitalRead(up);
      buttonDown = digitalRead(down);
      setFunction = digitalRead(set);
      bounceLap = millis();

      if (!buttonUp) Count++;
      if (!buttonDown) Count--;
      if (!buttonUp) setBrillo(true);
      if (!buttonDown) setBrillo(false);
    }
    timeLap = millis();
  }
  
  while (millis() - tempLap <= 4000) { // Ciclo que muestra la temperatura, por ahora fijo a 4 segundos.
    readTemp(&temp);
    display.showNumberDec(temp, true, 2, 2);
    Serial.print(temp), Serial.println("°C");
    tempLap = millis();
  }


  display.setSegments(data);   //debug
}//-------------------------------------------END LOOP

void readTime(byte *second, byte *minute , byte *hour) {
  Wire.beginTransmission (DS3231_I2C_ADDRESS);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 3);
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read());
}//-------------------------------------------END READTIME
void readTemp(byte *tempMSB) {
  Wire.beginTransmission (DS3231_I2C_ADDRESS);
  Wire.write(0x11);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 1);
  *tempMSB = bcdToDec(Wire.read());
}//-------------------------------------------END READTEMP
void setTime(byte *hour, byte *minute)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x01);
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.endTransmission();
}//-------------------------------------------END SETTIME

void setBrillo(bool brillo)
{
  if (brillo) {
    i--;
  } else {
    i++;
  }
  if (i > 7) i = 7;
  if (i < 1) i = 1;

  byte brillos[8] = {8, 9, 10, 11, 12, 13, 14, 15}; //valores que brillan del mas tenue al mas brillante.
  display.setBrightness(brillos[i]);
  //display.setBrightness(8);
  Serial.print("Valor de Incremento: "), Serial.println(brillo);  //debug
  Serial.print("Valor Indice: "), Serial.println(i);              //debug
  Serial.print("Valor de brillo: "), Serial.println(brillos[i]);  //debug
  Serial.println();
  delay(100);
}//-------------------------------------------END SETBRILLO

// Convert normal decimal numbers to binary coded decimal <--> Update Time
byte decToBcd(byte val)
{
  return ( (val / 10 * 16) + (val % 10) );
}
// Convert binary coded decimal to normal decimal numbers <--> Read Time
byte bcdToDec(byte val)
{
  return ( (val / 16 * 10) + (val % 16) );
}

Una nueva actualización.

Tengo rato viendo la manera de como manejar los diferentes ciclos del programa, como ya comente quiero que se vea la hora un cierto tiempo y luego la temperatura otro cierto tiempo.

Pero creo que dejare que la hora fijo a un minuto y poco mas, dejando ajustable solo el lapso de la temperatura, porque en la documentación del ds3231 dice que la temperatura se actualiza 64 segundos después de una lectura i2c con Vbat. lo que creo que va bien para evitar el consumo de bateria.

Temperature Registers (11h–12h)
The temperature is read on initial application of VCC or I2C access on VBAT and once every 64 seconds afterwards. The temperature registers are updated after each user-initiated conversion and on every 64-second conversion. The temperature registers are read-only.

Dejo el código que hice para cambio de ciclos y su salida, me llevo un tiempo caer en cuenta de como manejarlo, no se si sera lo definitivo pero primero me voy a concentrar en la funcionalidad, ya que este funcionando todo bien mirare la manera de que funcione bien con baterías.

unsigned long prevMillis, currMillis;   // variables para el manejo de la duracion del lapso usando millis()
boolean showTime = true;                //variable control 
boolean showTemp = false;               //variable control importante que sean diferentes para el paso de una a otra
unsigned long lapTemp = 3000;           //variable lapso temperatura.
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600); 
}

void loop() {
  // put your main code here, to run repeatedly:
  currMillis = millis();
  if ((currMillis - prevMillis >= 10000) && showTime) { //se ejecuta una vez dentro de el lapso 
    prevMillis = currMillis;
    showTemp = !showTemp;                //Intercambio de estados en variables de control
    showTime = !showTime;                
  } else if(showTime) {   //codigo que se ejecuta siempre dentro del lapso
    Serial.println("Show:Time");          // <-- buen lugar para leer el estado de los botones. 
  }                                       

  if ((currMillis - prevMillis >= lapTemp) && showTemp) { // casi lo mismo de arriba
    prevMillis = currMillis;
    showTemp = !showTemp;
    showTime = !showTime;
  } else if (showTemp){
    Serial.println("Show:Temp °c");
  }
}

salida:

Show:Time
Show:Time
Show:Time
...
...
...
Show:Time
Show:Time
Show:Time
Show:Temp °c
...
...
...
Show:Temp °c

Bueno me voy dormir porque mañana muy temprano salgo de viaje a SanFernando. la proxima semana voy a juntar el código o al menos subiré unas imágenes de mi setup.
saludos.