// include mqtt communication libraries
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
// include Wi-Fi connection library
#include <WiFi.h>
// Include json parser
#include <ArduinoJson.h>
#include <SPI.h>
#include <SD.h>
// #include <RTClib.h>
#include <Wire.h>
#include <time.h>
#include <driver/ledc.h>
#define SD_CS 5
#define SD_SCLK 18
#define SD_MOSI 23
#define SD_MISO 19
// #define I2C_SDA 21
// #define I2C_SCL 22
#define T_INPUT 33
// RTC_DS1307 rtc;
struct tm timeinfo;
// contadores de los pulsos
volatile float temperatura = 0;
volatile float Vin = 0;
unsigned long tiempo = 0;
// tiempo de muestreo
unsigned long lastTime = 0;
unsigned long samplingTime = 5000;
// define configuration constants for Wi-Fi connection
const char* ssid = "Wokwi-GUEST"; // Nombre de la red
const char* password = NULL; // Contraseña o NULL en caso de no tener
// Variables para NTP
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = -18000;
const int daylightOffset_sec = 0;
void conectarWiFi(void* pvParameters){
Serial.println("INFO: [WiFi] Iniciando conexión...");
int timeout = 60;
int timeoutcounter = 0;
for(;;){
if(WiFi.status() != WL_CONNECTED){
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED){
timeoutcounter++;
Serial.print(".");
delay(500);
if(timeoutcounter>=timeout){
Serial.println("\n INFO: [WiFi] Timeout alcanzado. Reiniciando...");
delay(1000);
ESP.restart();
}
}
Serial.println("\n INFO: [WiFi] Conexión establecida.");
mostrarInfoRed();
}
Serial.print("INFO: [WiFi] Intensidad de la señal:");
Serial.println((String)WiFi.RSSI()+"dB");
// Incluir "delay"
vTaskDelay(5000 / portTICK_PERIOD_MS); // Solo detiene este proceso. Un delay normal detiene todo.
}
}
void mostrarInfoRed(){
if(WiFi.status()==WL_CONNECTED){
Serial.println("INFO: [WIFi] Información de la red:");
Serial.print("Dirección MAC del ESP32:");
Serial.println(WiFi.BSSIDstr());
Serial.print("Dirección IP del ESP32:");
Serial.println(WiFi.localIP());
Serial.print("Dirección IP del router:");
Serial.println(WiFi.gatewayIP());
Serial.print("Máscara de subred:");
Serial.println(WiFi.subnetMask());
}
}
// Implementación de PWM
// --- PWM TASK (LEDC + FreeRTOS) ---
const int pwmPin = 16;
const int pwmChannel = 0;
const int pwmFreq = 5000; // Hz
const int pwmResolution = 8; // bits (0–255)
volatile float duty = 0;
volatile float porcentajePWM = 0;
float dutyPrueba = 200;
void pwmTask(void * pvParameters) {
// Configuración del hardware PWM (se hace UNA sola vez dentro de la tarea)
ledcAttach(pwmPin, pwmFreq, pwmResolution);
int direction = 1; // para hacer un efecto tipo "fade"
Serial.println("INFO: [PWM] Tarea Iniciada.");
unsigned long t1 = millis();
for(;;) {
// Escribir duty cycle
ledcWrite(pwmPin, duty);
if (duty >= 255) direction = -1;
if (duty <= 0) direction = 1;
if(millis() - t1 >= 5000){
Serial.print("INFO: [PWM] porcentaje de PWM = ");
Serial.println(duty*100/255);
t1 = millis();
}
// Delay no bloqueante
vTaskDelay(pdMS_TO_TICKS(50));
}
}
// set up the device
void setup() {
// initialize the serial terminal
Serial.begin(9600);
xTaskCreatePinnedToCore(conectarWiFi, "ConfigWiFi", 8000, NULL, 1, NULL, 0);
// Experimento
pinMode(T_INPUT, INPUT);
pinMode(pwmPin, OUTPUT);
digitalWrite(pwmPin, HIGH);
xTaskCreatePinnedToCore(pwmTask, "PWMTask", 2048, NULL, 1, NULL, 1);
// inicializamos interfaz SPI
SPI.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS);
// Iniciar NTP para conseguir tiempo
unsigned long t = 0;
while(true){
if(millis() - t >= 60000){
Serial.println("INFO: [Tiempo] Intentando obtener tiempo.");
t = millis();
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
if(!getLocalTime(&timeinfo)){
Serial.println("INFO: [Tiempo] Fallo al obtener el tiempo.");
} else{
break;
}
}
}
if(!SD.begin(SD_CS)){
Serial.println("INFO: [SD] Error al inciar la micro SD.");
} else{
Serial.println("INFO: [SD] Micro SD inciada correctamente.");
}
// creamos una carpeta para guardar la información
if (!SD.exists("/laboratorio")) {
if(SD.mkdir("/laboratorio")){
Serial.println("INFO: [SD] Carpeta creada con éxito.");
} else{
Serial.println("INFO: [SD] Error el crear la carpeta.");
}
} else {
Serial.println("INFO: [SD] La carpeta ya existe.");
}
// creamos el archivo
File tomaDatos = SD.open("/laboratorio/EA_LAB03_JAMR_MRA_CASO_XX.csv", FILE_WRITE);
if(!tomaDatos){
Serial.println("INFO: [SD] Error al crear el archivo CSV.");
} else{
if(tomaDatos.size()==0){
// Incluir header compuesto de: timestamp,cuentas_beta solo si el archivo está vacío
tomaDatos.println("timestamp,TiempoRelativo,PWM,Temperatura");
}
}
tomaDatos.close();
}
void loop() {
if ((millis() - lastTime) >= samplingTime) {
// guardamos el tiempo actual
lastTime = millis();
char timestamp[25];
if (getLocalTime(&timeinfo)) {
strftime(timestamp, sizeof(timestamp), "%y-%m-%dT%H:%M:%S", &timeinfo);
Serial.println(timestamp);
}
unsigned long tr = lastTime - 100;
if (Serial.available()) {
String input = Serial.readStringUntil('\n');
input.trim(); // elimina \r y espacios
Serial.println("Dato recibido");
int pwm = input.toInt();
if (pwm >= 0 && pwm <= 100) {
duty = (pwm * 255) / 100;
Serial.print("Nuevo duty: ");
Serial.println(duty);
}
}
Vin = (analogRead(T_INPUT)/4095)*3.3;
temperatura = Vin*100;
File tomaDatos = SD.open("/laboratorio/EA_LAB03_JAMR_MRA_CASO_XX.csv", FILE_APPEND);
if(!tomaDatos){
Serial.println("INFO: [SD] Error al abrir el archivo CSV.");
} else{
tomaDatos.print(timestamp);
tomaDatos.print(",");
tomaDatos.print(tr);
tomaDatos.print(",");
tomaDatos.println(temperatura);
tomaDatos.close();
tomaDatos.println(porcentajePWM);
tomaDatos.close();
Serial.println("INFO: [SD] Datos guardados en SD.");
}
if(millis() - tiempo >= 5000){
Serial.println(timestamp);
Serial.print("Vin = ");
Serial.println(Vin);
Serial.print("Temperatura = ");
Serial.println(temperatura);
tiempo = millis();
}
}
}