#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <SD.h>
#include <EEPROM.h>
#include <RTClib.h>
// Definiciones de pines y constantes
#define SCREEN_WIDTH 128 // Ancho del OLED en píxeles
#define SCREEN_HEIGHT 64 // Alto del OLED en píxeles
#define OLED_RESET -1 // Pin de reset del OLED (o -1 si no se utiliza)
#define SCREEN_ADDRESS 0x3C // Dirección I2C del display
#define SoundSensorPin A1 // Pin del sensor de sonido SEN0232
#define VREF 5.0 // Voltaje de referencia para lectura del sensor
#define ENC_SW_PIN 2 // Pin del switch del encoder
#define ENC_A_PIN 3 // Pin A del encoder
#define ENC_B_PIN 4 // Pin B del encoder
#define SD_CS_PIN 10 // Pin CS de la tarjeta SD
#define LED_GREEN 5 // LED verde
#define LED_YELLOW 6 // LED amarillo
#define LED_RED 7 // LED rojo
Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
RTC_DS3231 rtc; // Instancia del módulo RTC DS3231
volatile bool menuActive = false; // Flag para saber si el menú está activo
float alfa = 0.5; // Valor para suavizado (EMA)
int umbralAmarillo = 60; // Umbral para cambiar a LED amarillo
int umbralRojo = 80; // Umbral para cambiar a LED rojo
unsigned long lastWriteTime = 0; // Registro del último guardado
int intervaloGuardar = 60000; // Frecuencia para guardar datos (en milisegundos)
// Variables para parpadeo de LEDs
unsigned long previousMillisLED = 0;
int greenBlinkInterval = 1000; // Intervalo de parpadeo para LED verde (en ms)
int yellowBlinkInterval = 500; // Intervalo de parpadeo para LED amarillo (en ms)
int redBlinkInterval = 200; // Intervalo de parpadeo para LED rojo (en ms)
bool greenState = false; // Estado del LED verde
bool yellowState = false; // Estado del LED amarillo
bool redState = false; // Estado del LED rojo
// Prototipos de funciones
void i2cScanner();
void setupMenu();
void handleEncoder();
void displayDbValue(float db);
void saveToSD(float db);
void controlLEDs(float db);
float readSoundSensor();
void enterMenu();
void guardarConfiguracion();
void configurarFechaHora();
void configurarAlfa();
void resetI2CBus();
void setup() {
Serial.begin(9600);
delay(1000); // Esperar un segundo para asegurarnos de que Serial está listo
Serial.println(F("Iniciando configuración del sistema..."));
// Escanear dispositivos I2C
Wire.begin();
i2cScanner();
// Inicializar el OLED primero
Serial.println(F("Intentando inicializar OLED..."));
if (!oled.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("Error: No se pudo inicializar el OLED."));
while (true); // Detener el programa si no se inicializa el OLED
} else {
Serial.println(F("OLED inicializado correctamente."));
delay(1000); // Esperar para inicialización
oled.clearDisplay(); // Limpiar pantalla OLED
}
// Inicializar RTC
Serial.println(F("Intentando inicializar RTC DS3231..."));
if (!rtc.begin()) {
Serial.println(F("Error: No se pudo inicializar el RTC DS3231."));
while (true); // Detener el programa si no se inicializa el RTC
} else {
Serial.println(F("RTC DS3231 inicializado correctamente."));
DateTime now = rtc.now();
Serial.print(F("Fecha y Hora actual: "));
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(" ");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.println(now.second(), DEC);
}
// Inicializar tarjeta SD
Serial.println(F("Iniciando tarjeta SD..."));
if (!SD.begin(SD_CS_PIN)) {
Serial.println(F("Error: No se pudo inicializar la tarjeta SD."));
Serial.println(F("Posibles causas: mala conexión, tarjeta no presente o módulo defectuoso."));
} else {
Serial.println(F("Tarjeta SD inicializada correctamente."));
}
// Cargar configuraciones guardadas en EEPROM
alfa = EEPROM.read(0) / 100.0;
umbralAmarillo = EEPROM.read(1);
umbralRojo = EEPROM.read(2);
intervaloGuardar = EEPROM.read(3) * 60000;
// Configuración inicial completada
Serial.println(F("Configuración del sistema completa."));
}
void loop() {
if (!menuActive) {
float dbValue = readSoundSensor();
// Aplicar suavizado (EMA)
dbValueSmoothed = alfa * dbValue + (1 - alfa) * dbValueSmoothed;
displayDbValue(dbValueSmoothed);
controlLEDs(dbValueSmoothed);
// Guardar en SD según el intervalo configurado
if (millis() - lastWriteTime > intervaloGuardar) {
saveToSD(dbValueSmoothed);
lastWriteTime = millis();
}
}
}
// Escáner I2C para verificar dispositivos conectados
void i2cScanner() {
Serial.println(F("Escaneando dispositivos I2C..."));
byte error, address;
int nDevices = 0;
for (address = 1; address < 127; address++) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print(F("Dispositivo I2C encontrado en la dirección 0x"));
Serial.println(address, HEX);
nDevices++;
} else if (error == 4) {
Serial.print(F("Error desconocido en la dirección 0x"));
Serial.println(address, HEX);
}
}
if (nDevices == 0) {
Serial.println(F("No se encontraron dispositivos I2C.\n"));
} else {
Serial.println(F("Escaneo I2C completado.\n"));
}
}
// Restablecer el bus I2C
void resetI2CBus() {
Wire.end();
delay(100); // Esperar un poco antes de reiniciar el bus I2C
Wire.begin();
}
// Guardar configuración en EEPROM
void guardarConfiguracion() {
EEPROM.write(0, int(alfa * 100));
EEPROM.write(1, umbralAmarillo);
EEPROM.write(2, umbralRojo);
EEPROM.write(3, intervaloGuardar / 60000);
Serial.println(F("Configuración guardada en EEPROM."));
}
// Configurar la fecha y hora del RTC
void configurarFechaHora() {
oled.clearDisplay();
oled.setCursor(0, 0);
oled.print("Configurar Fecha y Hora:");
oled.display();
delay(1000); // Simular la entrada del usuario
int year = 2024;
int month = 10;
int day = 7;
int hour = 12;
int minute = 0;
rtc.adjust(DateTime(year, month, day, hour, minute, 0));
oled.clearDisplay();
oled.setCursor(0, 0);
oled.print("Fecha y Hora Ajustada");
oled.display();
delay(2000); // Mostrar confirmación
}
// Configurar la variable alfa para la EMA
void configurarAlfa() {
oled.clearDisplay();
oled.setCursor(0, 0);
oled.print("Configurar Alfa:");
oled.display();
delay(1000); // Simular la entrada del usuario
alfa = 0.5; // Actualizar con el valor ajustado (simulado)
oled.clearDisplay();
oled.setCursor(0, 0);
oled.print("Alfa ajustado a: ");
oled.print(alfa);
oled.display();
delay(2000); // Mostrar confirmación
}
// Mostrar el valor en el display OLED
void displayDbValue(float db) {
oled.clearDisplay();
oled.setCursor(0, 0);
oled.setTextSize(2);
oled.print("Ruido: ");
oled.print(db, 1);
oled.print(" dBA");
oled.display();
}