/*
* Este programa utiliza una pantalla TTGO con un microcontrolador ESP32 para mostrar un reloj analógico.
* El programa realiza las siguientes acciones:
* - Inicializa la pantalla y dibuja la carátula del reloj, incluyendo los marcadores de horas y minutos.
* - Obtiene la hora de compilación del programa.
* - Actualiza las posiciones de las manecillas del reloj cada segundo.
* - Redibuja las manecillas en sus nuevas posiciones para representar el tiempo actual.
*
* Funciones del programa:
* - setup(): Inicializa la pantalla y dibuja la carátula del reloj.
* - loop(): Actualiza y redibuja las manecillas del reloj cada segundo.
* - conv2d(const char* p): Convierte dos caracteres en un número de dos dígitos.
*/
#include <SPI.h>
#include <TFT_eSPI.h> // Incluye la librería específica para el hardware
#define PI_DIV_180 0.0174532925 // Macro para eliminar magic number en conversion de grad -> rad
TFT_eSPI tft = TFT_eSPI(); // Crea un objeto de la clase TFT_eSPI
// Variables para almacenar los multiplicadores x e y de las manecillas del reloj
float sx = 0, sy = 1, mx = 1, my = 0, hx = -1, hy = 0;
float sdeg = 0, mdeg = 0, hdeg = 0;
// Variables para almacenar las coordenadas x e y previas de las manecillas
uint16_t osx = 120, osy = 120, omx = 120, omy = 120, ohx = 120, ohy = 120;
uint16_t x0 = 0, x1 = 0, yy0 = 0, yy1 = 0;
uint32_t targetTime = 0; // Tiempo objetivo para el próximo timeout de 1 segundo
static uint8_t conv2d(const char* p); // Declaración anticipada de la función conv2d
// Obtiene la hora, minutos y segundos de la hora de compilación del programa
uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), ss = conv2d(__TIME__ + 6);
bool initial = 1; // Variable para marcar la inicialización
void setup(void) {
tft.init(); // Inicializa la pantalla
tft.setRotation(0); // Establece la orientación de la pantalla
// Dibuja la carátula del reloj
tft.fillCircle(120, 120, 118, TFT_GREEN); // Dibuja un círculo verde grande
tft.fillCircle(120, 120, 110, TFT_BLACK); // Dibuja un círculo negro más pequeño sobre el anterior
// Dibuja las 12 líneas de las horas
for (int i = 0; i < 360; i += 30) {
sx = cos((i - 90) * PI_DIV_180); // Calcula la coordenada x del extremo de la línea
sy = sin((i - 90) * PI_DIV_180); // Calcula la coordenada y del extremo de la línea
x0 = sx * 114 + 120; // Calcula la coordenada x del inicio de la línea
yy0 = sy * 114 + 120; // Calcula la coordenada y del inicio de la línea
x1 = sx * 100 + 120; // Calcula la coordenada x del final de la línea
yy1 = sy * 100 + 120; // Calcula la coordenada y del final de la línea
tft.drawLine(x0, yy0, x1, yy1, TFT_GREEN); // Dibuja la línea
}
// Dibuja los 60 puntos de los minutos
for (int i = 0; i < 360; i += 6) {
sx = cos((i - 90) * PI_DIV_180); // Calcula la coordenada x del punto
sy = sin((i - 90) * PI_DIV_180); // Calcula la coordenada y del punto
x0 = sx * 102 + 120; // Calcula la coordenada x del punto
yy0 = sy * 102 + 120; // Calcula la coordenada y del punto
tft.drawPixel(x0, yy0, TFT_WHITE); // Dibuja el punto
// Dibuja puntos más grandes en las posiciones de los cuadrantes principales
if (i == 0 || i == 180) tft.fillCircle(x0, yy0, 2, TFT_WHITE);
if (i == 90 || i == 270) tft.fillCircle(x0, yy0, 2, TFT_WHITE);
}
targetTime = millis() + 1000; // Establece el tiempo objetivo para el primer timeout de 1 segundo
}
void loop() {
if (targetTime < millis()) { // Comprueba si ha pasado 1 segundo
targetTime += 1000; // Actualiza el tiempo objetivo para el próximo segundo
ss++; // Incrementa los segundos
if (ss == 60) { // Si los segundos alcanzan 60
ss = 0; // Resetea los segundos
mm++; // Incrementa los minutos
if (mm > 59) { // Si los minutos alcanzan 60
mm = 0; // Resetea los minutos
hh++; // Incrementa las horas
if (hh > 23) { // Si las horas alcanzan 24
hh = 0; // Resetea las horas
}
}
}
// Precalcula los grados y las coordenadas x e y de las manecillas para una actualización rápida de la pantalla
sdeg = ss * 6; // Convierte segundos en grados (0-59 -> 0-354)
mdeg = mm * 6 + sdeg * 0.01666667; // Convierte minutos y segundos en grados
hdeg = hh * 30 + mdeg * 0.0833333; // Convierte horas, minutos y segundos en grados
hx = cos((hdeg - 90) * PI_DIV_180); // Calcula la coordenada x de la manecilla de las horas
hy = sin((hdeg - 90) * PI_DIV_180); // Calcula la coordenada y de la manecilla de las horas
mx = cos((mdeg - 90) * PI_DIV_180); // Calcula la coordenada x de la manecilla de los minutos
my = sin((mdeg - 90) * PI_DIV_180); // Calcula la coordenada y de la manecilla de los minutos
sx = cos((sdeg - 90) * PI_DIV_180); // Calcula la coordenada x de la manecilla de los segundos
sy = sin((sdeg - 90) * PI_DIV_180); // Calcula la coordenada y de la manecilla de los segundos
if (ss == 0 || initial) { // Si es el primer segundo o es la inicialización
initial = 0; // Marca que la inicialización ha terminado
// Borra las posiciones previas de las manecillas de las horas y los minutos
tft.drawLine(ohx, ohy, 120, 121, TFT_BLACK);
ohx = hx * 62 + 121; // Calcula la nueva coordenada x de la manecilla de las horas
ohy = hy * 62 + 121; // Calcula la nueva coordenada y de la manecilla de las horas
tft.drawLine(omx, omy, 120, 121, TFT_BLACK);
omx = mx * 84 + 120; // Calcula la nueva coordenada x de la manecilla de los minutos
omy = my * 84 + 121; // Calcula la nueva coordenada y de la manecilla de los minutos
}
// Redibuja las nuevas posiciones de las manecillas
tft.drawLine(osx, osy, 120, 121, TFT_BLACK); // Borra la manecilla de los segundos anterior
osx = sx * 90 + 121; // Calcula la nueva coordenada x de la manecilla de los segundos
osy = sy * 90 + 121; // Calcula la nueva coordenada y de la manecilla de los segundos
tft.drawLine(osx, osy, 120, 121, TFT_RED); // Dibuja la nueva manecilla de los segundos en rojo
tft.drawLine(ohx, ohy, 120, 121, TFT_WHITE); // Dibuja la nueva manecilla de las horas en blanco
tft.drawLine(omx, omy, 120, 121, TFT_WHITE); // Dibuja la nueva manecilla de los minutos en blanco
tft.drawLine(osx, osy, 120, 121, TFT_RED); // Dibuja nuevamente la manecilla de los segundos en rojo para evitar parpadeo
tft.fillCircle(120, 121, 3, TFT_RED); // Dibuja un círculo rojo en el centro del reloj para cubrir el centro de las manecillas
}
}
// Función para convertir dos caracteres en un número
static uint8_t conv2d(const char* p) {
uint8_t v = 0;
if ('0' <= *p && *p <= '9')
v = *p - '0';
return 10 * v + *++p - '0'; // Convierte dos caracteres en un número de dos dígitos
}