#include "myDisplay.h"
#include "modulos.h"
#include <Wire.h>
#define DIRECCION_EEPROM 0x50
// Estructura para almacenar hora y valor juntos
struct Medicion {
uint16_t hora;
uint16_t valor;
};
Medicion mediciones[13]; // 13 mediciones de 6 am a 6 pm
myDisplay display;
// Pines del encoder
const int pinCLK = 25;
const int pinDT = 26;
const int pinSW = 27;
// Estados del sistema
enum SystemState {
STATE_NOW, // Modo NOW (medición en tiempo real)
STATE_MEM_SHOW_HOUR, // Mostrando hora almacenada
STATE_MEM_SHOW_VALUE // Mostrando valor almacenado
};
SystemState currentState = STATE_NOW;
// Flags atómicos para interrupciones
volatile bool cambioEncoder = false;
volatile bool botonPresionado = false;
// Variables para debounce
volatile unsigned long ultimoTiempoEncoder = 0;
volatile unsigned long ultimoTiempoBoton = 0;
const unsigned long DEBOUNCE_ENCODER = 1000; // 1ms en microsegundos
const unsigned long DEBOUNCE_BOTON = 50000; // 50ms en microsegundos
// NO necesitas incluir librerías adicionales - ESP32 Arduino Core ya tiene lo necesario
bool showHour = true;
uint8_t displayIndex = 0;
uint16_t currentRadiation = 0;
// ------------------- INTERRUPCIONES MEJORADAS -------------------
void IRAM_ATTR interrupcionEncoder() {
unsigned long tiempoActual = micros();
if (tiempoActual - ultimoTiempoEncoder < DEBOUNCE_ENCODER) return;
ultimoTiempoEncoder = tiempoActual;
cambioEncoder = true;
}
void IRAM_ATTR interrupcionBoton() {
unsigned long tiempoActual = micros();
if (tiempoActual - ultimoTiempoBoton < DEBOUNCE_BOTON) return;
ultimoTiempoBoton = tiempoActual;
botonPresionado = true;
}
// ------------------- LEER SENSOR DE RADIACIÓN -------------------
uint16_t leerSensorRadiacion() {
uint16_t valor = readLightLevel();
return (valor > 9999) ? 9999 : valor; // Saturación a 9999
}
// ------------------- OBTENER HORA ACTUAL -------------------
uint8_t obtenerHoraActual() {
return HoraActual();
}
// ------------------- GUARDAR MEDICIÓN ACTUAL -------------------
void guardarMedicionActual() {
uint8_t horaActual = obtenerHoraActual();
uint16_t valorActual = currentRadiation;
// Buscar si ya existe una medición para esta hora
for (int i = 0; i < 13; i++) {
if (mediciones[i].hora == horaActual) {
mediciones[i].valor = valorActual;
EscribirMedida(horaActual, valorActual);
Serial.print("Actualizada - Hora: ");
Serial.print(horaActual);
Serial.print(" - Valor: ");
Serial.println(valorActual);
return;
}
}
// Si no existe, buscar espacio libre
for (int i = 0; i < 13; i++) {
if (mediciones[i].hora == 0) {
mediciones[i].hora = horaActual;
mediciones[i].valor = valorActual;
EscribirMedida(horaActual, valorActual);
Serial.print("Guardada - Hora: ");
Serial.print(horaActual);
Serial.print(" - Valor: ");
Serial.println(valorActual);
return;
}
}
Serial.println("No hay espacio para nueva medición");
}
// ------------------- INICIALIZAR SENSORES -------------------
bool inicializarSensores() {
Serial.println("Inicializando sensores...");
if (!bh1750Begin()) {
Serial.println("Error: BH1750 no responde");
return false;
}
Serial.println("Sensores inicializados correctamente");
return true;
}
// ------------------- INICIALIZAR DATOS DE EJEMPLO -------------------
void inicializarDatosEjemplo() {
bool eepromVacia = true;
for (int i = 0; i < 13; i++) {
if (LeerMedida(i + 6) != 0) {
eepromVacia = false;
break;
}
}
if (eepromVacia) {
Serial.println("Inicializando datos de ejemplo...");
uint16_t horasEjemplo[] = {6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
uint16_t valoresEjemplo[] = {6666, 7777, 8888, 9999, 1010, 1111, 1212, 101, 202, 303, 404, 505, 606};
for (int i = 0; i < 13; i++) {
EscribirMedida(horasEjemplo[i], valoresEjemplo[i]);
mediciones[i].hora = horasEjemplo[i];
mediciones[i].valor = valoresEjemplo[i];
}
Serial.println("Datos de ejemplo inicializados.\n");
}
}
// ------------------- CARGAR DATOS DESDE EEPROM -------------------
void cargarDatosDesdeEEPROM() {
Serial.println("Cargando datos desde EEPROM...");
uint16_t horas[] = {6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
for (int i = 0; i < 13; i++) {
uint16_t valor = LeerMedida(horas[i]);
mediciones[i].hora = horas[i];
mediciones[i].valor = valor;
Serial.print("Hora: ");
Serial.print(mediciones[i].hora);
Serial.print(" - Valor: ");
Serial.println(mediciones[i].valor);
}
}
// ------------------- SETUP -------------------
void setup() {
Wire.begin();
Serial.begin(115200);
display.begin();
// Configurar pines
REG_WRITE(GPIO_ENABLE_W1TC_REG, (1 << pinCLK) | (1 << pinDT) | (1 << pinSW));
gpio_config_t io_conf = {};
io_conf.pin_bit_mask = (1ULL << pinCLK) | (1ULL << pinDT) | (1ULL << pinSW);
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.intr_type = GPIO_INTR_DISABLE;
gpio_config(&io_conf);
// Configurar interrupciones
attachInterrupt(digitalPinToInterrupt(pinCLK), interrupcionEncoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(pinSW), interrupcionBoton, FALLING);
Serial.println("Sistema listo");
// Inicializar sensores y datos
inicializarSensores();
inicializarDatosEjemplo();
cargarDatosDesdeEEPROM();
}
// ------------------- LOOP CON INTERRUPCIONES Y TIMERS MANUALES -------------------
void loop() {
static unsigned long lastDisplayRefresh = 0;
static unsigned long lastStateChange = 0;
static unsigned long lastSensorRead = 0;
static unsigned long lastAutoSave = 0;
unsigned long currentTime = micros(); // Usar micros() para mayor precisión
// Timer para refresh del display (1kHz = cada 1000us)
if (currentTime - lastDisplayRefresh >= 1000) {
lastDisplayRefresh = currentTime;
display.refresh();
}
// Timer para cambio de estado (2 segundos = 2000000us)
if (currentTime - lastStateChange >= 2000000) {
lastStateChange = currentTime;
switch (currentState) {
case STATE_NOW:
currentState = STATE_MEM_SHOW_HOUR;
showHour = true;
display.showHour(mediciones[displayIndex].hora);
Serial.println("Cambiando a MODO MEM - Mostrando hora");
break;
case STATE_MEM_SHOW_HOUR:
currentState = STATE_MEM_SHOW_VALUE;
showHour = false;
display.showNumber(mediciones[displayIndex].valor);
Serial.println("Mostrando valor");
break;
case STATE_MEM_SHOW_VALUE:
currentState = STATE_NOW;
showHour = true;
Serial.print("Cambiando a MODO NOW - Radiación: ");
Serial.println(currentRadiation);
break;
}
}
// Timer para lectura de sensor (1 segundo = 1000000us)
if (currentTime - lastSensorRead >= 1000000) {
lastSensorRead = currentTime;
currentRadiation = leerSensorRadiacion();
// Guardar automáticamente cada minuto (60 segundos)
static unsigned long saveCounter = 0;
saveCounter += 1000000; // Sumar 1 segundo en microsegundos
if (saveCounter >= 60000000) { // 60 segundos
guardarMedicionActual();
saveCounter = 0;
}
}
// Procesar encoder
if (cambioEncoder) {
cambioEncoder = false;
int clkState = (REG_READ(GPIO_IN_REG) & (1 << pinCLK)) ? 1 : 0;
int dtState = (REG_READ(GPIO_IN_REG) & (1 << pinDT)) ? 1 : 0;
if (clkState != dtState) {
displayIndex = (displayIndex + 1) % 13;
} else {
displayIndex = (displayIndex == 0) ? 12 : (displayIndex - 1);
}
if (currentState == STATE_MEM_SHOW_HOUR || currentState == STATE_MEM_SHOW_VALUE) {
if (showHour) {
display.showHour(mediciones[displayIndex].hora);
} else {
display.showNumber(mediciones[displayIndex].valor);
}
}
Serial.print("Navegando - Hora: ");
Serial.print(mediciones[displayIndex].hora);
Serial.print(" - Valor: ");
Serial.println(mediciones[displayIndex].valor);
}
// Procesar botón
if (botonPresionado) {
botonPresionado = false;
if (currentState == STATE_MEM_SHOW_HOUR || currentState == STATE_MEM_SHOW_VALUE) {
showHour = !showHour;
if (showHour) {
display.showHour(mediciones[displayIndex].hora);
Serial.print("Mostrando hora: ");
Serial.println(mediciones[displayIndex].hora);
} else {
display.showNumber(mediciones[displayIndex].valor);
Serial.print("Mostrando valor: ");
Serial.println(mediciones[displayIndex].valor);
}
} else if (currentState == STATE_NOW) {
guardarMedicionActual();
Serial.println("Medición guardada manualmente");
}
}
// Mostrar en modo NOW
if (currentState == STATE_NOW) {
display.showNumber(currentRadiation);
}
}