#include <SPI.h>
#include <SD.h>
// ---------------------- CONFIGURACIÓN ----------------------
const int CS_PIN = 4;
const int SENSOR_PIN = A0; // Potenciómetro simula el sensor
const int LED_ALERTA = 7; // LED indicador de ruptura de cadena de frío
const char* LOG_FILE = "log.csv";
const unsigned long INTERVALO_MS = 2000;
const float TEMP_MIN_SEGURA = -2.0;
const float TEMP_MAX_SEGURA = 4.0; // Rango seguro para arándanos/paltas
unsigned long ultimoRegistro = 0;
unsigned long numeroRegistro = 0;
// Estructura de un registro térmico
struct RegistroTermico {
unsigned long timestamp;
float temperatura_c;
float humedad_pct;
bool alerta;
};
// ---------------------- SETUP ----------------------
void setup() {
Serial.begin(9600);
while (!Serial) { ; }
Serial.println(F("=== FrescoLog - Datalogger de Cadena de Frio ==="));
pinMode(LED_ALERTA, OUTPUT);
digitalWrite(LED_ALERTA, LOW);
Serial.print(F("Inicializando tarjeta microSD..."));
pinMode(CS_PIN, OUTPUT);
if (!SD.begin(CS_PIN)) {
Serial.println(F(" FALLO."));
Serial.println(F("Verifique conexion SPI, formato FAT32 y alimentacion."));
return;
}
Serial.println(F(" OK."));
if (!SD.exists(LOG_FILE)) {
File archivo = SD.open(LOG_FILE, FILE_WRITE);
if (archivo) {
archivo.println(F("registro,timestamp_ms,temperatura_c,humedad_pct,estado"));
archivo.close();
Serial.println(F("Cabecera CSV creada."));
} else {
Serial.println(F("ERROR: no se pudo crear el archivo de log."));
}
}
randomSeed(analogRead(A1));
}
void loop() {
// --- HERRAMIENTA DE DIAGNOSTICO ---
if (Serial.available() > 0) {
char comando = Serial.read();
if (comando == 'r' || comando == 'R') {
File lectura = SD.open(LOG_FILE);
if (lectura) {
Serial.println(F("\n--- CONTENIDO DEL ARCHIVO CSV EN MICROSD ---"));
while (lectura.available()) {
Serial.write(lectura.read());
}
lectura.close();
Serial.println(F("--- FIN DEL ARCHIVO ---\n"));
} else {
Serial.println(F("Error al leer el archivo."));
}
}
}
// --- FIN DE HERRAMIENTA ---
unsigned long ahora = millis();
if (ahora - ultimoRegistro >= INTERVALO_MS) {
ultimoRegistro = ahora;
RegistroTermico dato = leerSensorSimulado();
bool exito = guardarRegistro(dato);
digitalWrite(LED_ALERTA, dato.alerta ? HIGH : LOW);
if (exito) {
Serial.print(F("Registro #"));
Serial.print(numeroRegistro);
Serial.print(F(" | Temp: "));
Serial.print(dato.temperatura_c, 1);
Serial.print(F(" C | "));
Serial.println(dato.alerta ? F("ALERTA: fuera de rango") : F("OK"));
} else {
Serial.println(F("ERROR: fallo al escribir en microSD."));
}
}
}
// ---------------------- FUNCIONES ----------------------
// Simula la lectura de un sensor de temperatura/humedad (en un
// proyecto real aqui se leeria un sensor DHT22 o DS18B20)
RegistroTermico leerSensorSimulado() {
RegistroTermico r;
r.timestamp = millis();
int lectura = analogRead(SENSOR_PIN); // 0-1023
// Mapea el potenciometro a un rango de -5.0 a 10.0 C
r.temperatura_c = -5.0 + (lectura / 1023.0) * 15.0;
r.humedad_pct = 80.0 + (random(-50, 50) / 10.0);
r.alerta = (r.temperatura_c < TEMP_MIN_SEGURA || r.temperatura_c > TEMP_MAX_SEGURA);
return r;
}
// Escribe un registro en el archivo CSV de la microSD
bool guardarRegistro(const RegistroTermico &dato) {
File archivo = SD.open(LOG_FILE, FILE_WRITE);
if (!archivo) {
return false;
}
numeroRegistro++;
archivo.print(numeroRegistro); archivo.print(",");
archivo.print(dato.timestamp); archivo.print(",");
archivo.print(dato.temperatura_c, 1); archivo.print(",");
archivo.print(dato.humedad_pct, 1); archivo.print(",");
archivo.println(dato.alerta ? "ALERTA" : "OK");
archivo.close();
return true;
}