Răsfoiți Sursa

Falta que funcione la funcion de grabar ruta y el grabado de altura del gps

dacowars 1 lună în urmă
părinte
comite
91c522986e
1 a modificat fișierele cu 166 adăugiri și 126 ștergeri
  1. 166 126
      main/main.ino

+ 166 - 126
main/main.ino

@@ -7,6 +7,7 @@
 #include "SD.h"
 #include "SPI.h"
 #include "Arduino.h"
+#include "math.h"
 
 /*
 Uncomment and set up if you want to use custom pins for the SPI communication
@@ -17,6 +18,7 @@ int mosi = -1;
 int cs = -1;
 */
 
+// Inicia I2C en pines default ESP32 (21 SDA, 22 SCL)
 #define SCREEN_WIDTH 128  // Ancho píxeles
 #define SCREEN_HEIGHT 64  // Alto píxeles
 #define OLED_RESET -1     // Reset pin (no usado)
@@ -29,33 +31,36 @@ int cs = -1;
 #define DHTPIN 4     // Digital pin connected to the DHT sensor
 #define DHTTYPE DHT22 
 
-// Objeto TinyGPS++
-TinyGPSPlus gps;
+#define BUTTON_PIN 27  // pin para pulsador
 
-// Serial para GPS
-HardwareSerial gpsSerial(2);
+//definicion de tiempos de pulsacion
+#define PULASCION_LARGA_MS 2000
+#define DURACION_WATCHDOG_MS 10000
 
-// Configuracion del DHT
-DHT dht(DHTPIN, DHTTYPE);
+#define MEASUREMENT_INTERVAL_S 1    //separación entre mediciones (s) 
 
-//definición del objeto para la pantalla OLED
-Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
+#define DEG2RAD (M_PI/180.0)
 
-// pin para pulsador
 
-#define BUTTON_PIN 0  
+// Objeto TinyGPS++
+TinyGPSPlus gps;
+HardwareSerial gpsSerial(2); // Usar UART2
+DHT dht(DHTPIN, DHTTYPE);
+Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
 
 //valores de los sensores
 
 struct SensorData {
-  double latitude;
-  double longitude;
-  float temperature;
-  float humidity;
-  float pressure;
+  double latitude = 0.0;
+  double longitude = 0.0;
+  float temperature = 0.0;
+  float humidity = 0.0;
+  float pressure = 0.0;
+  float altura = 0.0;
 };
 
 SensorData latestData;
+SensorData datosAntiguos;
 
 SemaphoreHandle_t dataMutex; // Mutex para proteger el acceso a latestData
 SemaphoreHandle_t buttonSemaphore; // Semáforo para la tarea del botón
@@ -63,17 +68,22 @@ SemaphoreHandle_t buttonSemaphore; // Semáforo para la tarea del botón
 //flag para reducir las lecturas de DHT y presion
 uint8_t readSensorsFlag = 0;
 
-//definicion de tiempos de pulsacion
-#define PULASCION_LARGA_MS 2000
-#define DURACION_WATCHDOG_MS 10000
-
-bool grabando = 0; //inicia apagado
+bool grabando = false; //inicia apagado
 TaskHandle_t medicionesHandle = NULL; //para suspend/resume
-#define X  1    //separación entre mediciones (s) 
 int pantallaEstado = 0; //maquina de estados
+float distancia_total = 0.0;
 
-float distancia_total = 0;
+char filename[13];
 
+void OLED_print(const String& line1, const String& line2) {
+  display.clearDisplay();
+  display.setTextSize(2);
+  display.setTextColor(SSD1306_WHITE);
+  display.setCursor(0, 0);
+  display.println(line1);
+  display.println(line2);
+  display.display();
+}
 
 void DHT_test() {
   dht.begin();
@@ -82,13 +92,15 @@ void DHT_test() {
   if (isnan(h) || isnan(t)) {
     Serial.println("Failed to read from DHT sensor!");
     OLED_print("DHT22", "Error");
-    while(1); // Detener si hay error
+    delay(5000);
+    DHT_test(); // Reintentar
   }
   else OLED_print("DHT22", "Correcto");
 }
 
 void OLED_test() {  //pantallazo a blanco y luego iniciando
   // Inicia I2C en pines default ESP32 (21 SDA, 22 SCL)
+  Wire.begin();
   if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {  // Dirección común: 0x3C
     Serial.println(F("Error: OLED no encontrado!"));
     for (;;);  // Para siempre
@@ -106,39 +118,47 @@ void OLED_test() {  //pantallazo a blanco y luego iniciando
   delay(1000);
 }
 
-void OLED_print(const char* line1, const char* line2) {
-  display.clearDisplay();
-  display.setTextSize(2);
-  display.setTextColor(SSD1306_WHITE);
-  display.setCursor(0, 0);
-  display.println(line1);
-  display.println(line2);
-  display.display();
-}
 
-char* SD_test() {
-  if (!SD.begin()) {
+void SD_test(){
+if (!SD.begin()) {
     Serial.println("SD Card Mount Failed");
-    OLED_print("SD Card", "Error\nInserte tarjeta");
-    while(!SD.begin()); // Detener si hay error
+    OLED_print("SD Card", "Error\nInserte");
+    while (!SD.begin());
     OLED_print("SD Card", "Insertada");
-  } 
-  else OLED_print("SD Card", "Correcto");
+  } else {
+    OLED_print("SD Card", "Correcto");
+    Serial.println("SD Card initialized.");
+  }
+  uint8_t cardType = SD.cardType();
+  if (cardType == CARD_NONE) {
+    Serial.println("No SD card attached");
+    OLED_print("SD Card", "No detectada");
+    while (cardType == CARD_NONE) {
+      delay(1000);
+      cardType = SD.cardType();
+    }
+    OLED_print("SD Card", "Detectada");
+  }
+  uint8_t cardSize = SD.cardSize() / (1024 * 1024);
+  Serial.printf("SD Card Size: %uMB\n", cardSize);
 
-  char filename[] = "data001.txt";
   int num = 1;
-  // Buscar un nombre de archivo disponible
-  while(SD.exists(filename)) {
+  sprintf(filename, "/data%03d.txt", num);
+  while (SD.exists(filename)) {
+    Serial.printf("File %s already exists. Trying next.\n", filename);
     num++;
-    sprintf(filename, "data%03d.txt", num);
+    sprintf(filename, "/data%03d.txt", num);
   }
+  Serial.printf("Using file: %s\n", filename);
 
   File file = SD.open(filename, FILE_WRITE);
-  file.Println("Latitud,Longitud,Temperatura,Humedad,Presión")
-  file.close();
-
-  return filename;
-
+  if (file) {
+    Serial.println("File created successfully");
+    file.println("Latitud,Longitud,Temperatura,Humedad,Presion");
+    file.close();
+  } else {
+    Serial.println("Error creando archivo");
+  }
 }
 
 void GPS_test_wait() {
@@ -157,144 +177,156 @@ void GPS_test_wait() {
 }
 
 float calcular_delta_dist(float lat1, float  long1, float lat2, float long2){
-  float R = 6371;
-  float delta_lat = lat2 - lat1;
-  float delta_long = long2 - long1;
-  float a = sin(delta_lat/2)ˆ2+cos(lat1)*cos(lat2)*sin(delta_long/2)ˆ2;
+  float R = 6371.0; // Radio de la Tierra en km
+  float delta_lat = (lat2 - lat1) * DEG2RAD;
+  float delta_long = (long2 - long1) * DEG2RAD;
+  lat1 = lat1 * DEG2RAD;
+  lat2 = lat2 * DEG2RAD;
+  float a = sin(delta_lat/2)*sin(delta_lat/2)+cos(lat1)*cos(lat2)*sin(delta_long/2)*sin(delta_long/2);
   float c = 2 * atan2(sqrt(a),sqrt(1-a));
-  return float d = R * c; 
+  return R * c;  //En km
 }
 
 void task_mediciones(void *pvParameters) {
   TickType_t xLastWakeTime = xTaskGetTickCount();
-  const char* filename = (const char*) pvParameters;
-  SensorData datosAntiguos;
   while(1) {
-    
     // se leen los valores antes de utilizar el semaphore    
     while (gpsSerial.available() > 0) {
       gps.encode(gpsSerial.read());
     }
+
     float new_latitude = gps.location.lat();
     float new_longitude = gps.location.lng();
-    if ((readSensorsFlag % 60) == 0) float new_temp = dht.readTemperature();
-    if ((readSensorsFlag % 120) == 0) float new_hum = ddht.readHumidity();
+    float new_temp = (readSensorsFlag % 60 == 0) ? dht.readTemperature() : latestData.temperature;
+    float new_hum = (readSensorsFlag % 120 == 0) ? dht.readHumidity() : latestData.humidity;
     float new_press = 0.0; // Placeholder, no hay sensor de presión 
     
+    if (gps.location.isValid() && datosAntiguos.latitude != 0.0) {
+      distancia_total += calcular_delta_dist(datosAntiguos.latitude, datosAntiguos.longitude, new_latitude, new_longitude);
+    }
 
-    File file = SD.open(filename, FILE_WRITE);
-    if (file) {
-      // guardar datos en latestData
-      if (xSemaphoreTake(dataMutex, portMAX_DELAY) == pdTRUE){
-        latestData.latitude = new_latitude;
-        latestData.longitude = new_longitude;
-        latestData.temperature = new_temp;
-        latestData.humidity = new_hum;
-        latestData.pressure = new_press; 
-      }
-      distancia_total += calcular_delta_dist(new_latitude, new_longitude, datosAntiguos.latitude, datosAntiguos.longitude); 
+    if (xSemaphoreTake(dataMutex, portMAX_DELAY) == pdTRUE) {
+      latestData.latitude = new_latitude;
+      latestData.longitude = new_longitude;
+      latestData.temperature = new_temp;
+      latestData.humidity = new_hum;
+      latestData.pressure = new_press;
       datosAntiguos = latestData;
       xSemaphoreGive(dataMutex);
+    }
 
-
+    File file = SD.open(filename, FILE_APPEND);
+    if (file) {
       //Crear la string para escribir en el archivo
-      char frase = String(datosAntiguos.latitude) + "," +
+      String frase = String(datosAntiguos.latitude) + "," +
                    String(datosAntiguos.longitude) + "," +
                    String(datosAntiguos.temperature) + "," +
                    String(datosAntiguos.humidity) + "," +
                    String(datosAntiguos.pressure);
       
-
       // Escribir datos en el archivo
       file.println(frase);
-
       file.close();
-      if (!(readSensorsFlag % 120)) readSensorsFlag = 0;
-      readSensorsFlag++;
     }
 
-    vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(X*1000)); // Espera x*1000 milisegundos
+    if (!(readSensorsFlag % 120)) readSensorsFlag = 0;
+    readSensorsFlag++;
+
+    vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(MEASUREMENT_INTERVAL_S*1000)); // Espera x*1000 milisegundos
   }
 }
 
 void IRAM_ATTR isr_button() {
   static unsigned long lastInterrupt = 0;
   if ((millis() - lastInterrupt) > 200 ){ // debounce de 200 ms 
+    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
     xSemaphoreGiveFromISR(buttonSemaphore, NULL); 
-    lastInterrupt = mmillis();
+    lastInterrupt = millis();
+    if (xHigherPriorityTaskWoken) {
+      portYIELD_FROM_ISR();
+    }
   }
   
 }
 
 void task_ui(void *pvParameters){
   unsigned long pressTime = 0;
-  unsigned long lastActivity = 0;
+  unsigned long lastActivity = millis();
   bool pantallaOn = true; //comprobar el estado inicial, no se cual sera
 
   while(1){
-    if (xSemaphoreTake(buttonSemaphore, portMAX_DELAY) == pdTRUE){ //button pressed
+    if (xSemaphoreTake(buttonSemaphore, pdMS_TO_TICKS(200)) == pdTRUE){ //button pressed
       pressTime = millis();
-      lastActivity = millis();
 
       if (!pantallaOn){
         display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
         pantallaOn = true;
       }
 
+      bool timed_out = false;
       while (digitalRead(BUTTON_PIN) == LOW){
         vTaskDelay(pdMS_TO_TICKS(10));
-        if ((millis() - lastActivity) > DURACION_WATCHDOG_MS){
-          //WATCHDOG 'activo' solo funciona si se mantiene presionado el boton ese tiempo
+        if ((millis() - pressTime) > DURACION_WATCHDOG_MS){ //10s timeout para evitar bloqueos
+          timed_out = true;
           break;
         }
       }
-      
-      unsigned long duration = millis() - pressTime;
-
-      if (duration >= PULASCION_LARGA_MS){
-        //pulsacion larga: cabia entre grabacion y no grabacion de datos
-        grabando != grabando;
-        if (grabando){
-          vTaskResume(medicionesHandle);
-          //Mostrar que empieza la grabación
-          OLED_print("Ruta","iniciada");
-        } else {
-          vTaskSuspend(medicionesHandle);
-          //Mostrar que se pausa/finaliza la grabación
-          OLED_print("Ruta","pausada");
-        }
+
+      if (timed_out){
+        OLED_print("Apagando","pantalla");
+        delay(1000);
+        display.ssd1306_command(SSD1306_DISPLAYOFF); //se apaga la
+        pantallaOn = false;
       } else {
-        //Pulsacion corta + grabando datos, cicla datos
-        if (grabando) {
-          pantallaEstado = (pantallaEstado + 1) % 3; //cicla entre 0-2
-          SensorData currentData;
-          if(xSemaphoreTake(dataMutex, portMAX_DELAY) == pdTRUE){
-            currentData = latestData;
-            xSemaphoreGive(dataMutex);
+      
+        unsigned long duration = millis() - pressTime;
+
+        if (duration >= PULASCION_LARGA_MS){
+          //pulsacion larga: cabia entre grabacion y no grabacion de datos
+          grabando != grabando;
+          if (grabando){
+            vTaskResume(medicionesHandle);
+            //Mostrar que empieza la grabación
+            OLED_print("Ruta","iniciada");
+          } else {
+            vTaskSuspend(medicionesHandle);
+            //Mostrar que se pausa/finaliza la grabación
+            OLED_print("Ruta","pausada");
           }
-          switch (pantallaEstado){
-            case 0:
-              OLED_print("Posicion",String(currentData.longitude)+","+String(currentData.latitude));
-              break;
-            case 1:
-              OLED_print("Distancia",String(distancia_total)+"km");
-              break;
-            case 2:
-              OLED_print("Altitud",String(currentData.pressure)+"m");
-              break;
+        } else {
+          //Pulsacion corta + grabando datos, cicla datos
+          if (grabando) {
+            pantallaEstado = (pantallaEstado + 1) % 3; //cicla entre 0-2
+            SensorData currentData;
+            if(xSemaphoreTake(dataMutex, portMAX_DELAY) == pdTRUE){
+              currentData = latestData;
+              xSemaphoreGive(dataMutex);
+            }
+            switch (pantallaEstado){
+              case 0:
+                OLED_print("Posicion",String(currentData.longitude) + "," + String(currentData.latitude));
+                break;
+              case 1:
+                OLED_print("Distancia",String(distancia_total)+"km");
+                break;
+              case 2:
+                OLED_print("Altitud",String(gps.altitude.meters(), 1)+"m");
+                break;
+            } 
           } else {
-            OLED_print("Grabación","pausada");
+              OLED_print("Grabacion","pausada");
           }
+          
         }
-        lastActivity = mmillis();  //reset watchdog
-      }
 
-      //check watchdog fuera del boton
-      if (pantallaOn && ((millis() - lastActivity) > DURACION_WATCHDOG_MS)){
-        display.ssd1306_command(SSD1306_DISPLAYOFF); //se apaga la pantalla
-        pantallaOn = false;
+        
       }
-
+      lastActivity = millis();  //reset watchdog
+    }
+    //check watchdog fuera del boton
+    if (pantallaOn && ((millis() - lastActivity) > DURACION_WATCHDOG_MS)){
+          display.ssd1306_command(SSD1306_DISPLAYOFF); //se apaga la pantalla
+          pantallaOn = false;
     }
    
     vTaskDelay(pdMS_TO_TICKS(100)); //pequeño delay para no busy waiting
@@ -305,15 +337,21 @@ void task_ui(void *pvParameters){
 void setup() {
   Serial.begin(115200);
 
+  pinMode(BUTTON_PIN, INPUT_PULLUP);
+  attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), isr_button, FALLING);
+  
+  buttonSemaphore = xSemaphoreCreateBinary();
+  dataMutex = xSemaphoreCreateMutex();
+
   // OLED check
   OLED_test();
-  delay(500);
+  delay(1000);
   // DHT check
   DHT_test();
-  delay(500);
+  delay(1000);
   // SD Card check
-  char *filename = SD_test();
-  delay(500);
+  SD_test();
+  delay(1000);
   // GPS check
   GPS_test_wait();
   delay(2000);
@@ -323,7 +361,7 @@ void setup() {
     task_mediciones,     // Función de la tarea
     "Mediciones",        // Nombre de la tarea
     2048,                // Tamaño del stack
-    (void*)filename,     // Parámetro de la tarea
+    NULL,     // Parámetro de la tarea
     10,                   // Prioridad de la tarea
     &medicionesHandle,                // Handle de la tarea
     0                    // Núcleo donde se ejecuta
@@ -339,6 +377,8 @@ void setup() {
     1                    // Núcleo donde se ejecuta
   );
 
+  vTaskSuspend(medicionesHandle); //inicia suspendida
+
 }