|
|
@@ -0,0 +1,251 @@
|
|
|
+#include "TinyGPSPlus.h"
|
|
|
+#include "DHT.h"
|
|
|
+#include <Wire.h>
|
|
|
+#include <Adafruit_GFX.h>
|
|
|
+#include <Adafruit_SSD1306.h>
|
|
|
+#include "FS.h"
|
|
|
+#include "SD.h"
|
|
|
+#include "SPI.h"
|
|
|
+#include "Arduino.h"
|
|
|
+//#include "FreeRTOS.h"
|
|
|
+
|
|
|
+/*
|
|
|
+Uncomment and set up if you want to use custom pins for the SPI communication
|
|
|
+#define REASSIGN_PINS
|
|
|
+int sck = -1;
|
|
|
+int miso = -1;
|
|
|
+int mosi = -1;
|
|
|
+int cs = -1;
|
|
|
+*/
|
|
|
+
|
|
|
+#define SCREEN_WIDTH 128 // Ancho píxeles
|
|
|
+#define SCREEN_HEIGHT 64 // Alto píxeles
|
|
|
+#define OLED_RESET -1 // Reset pin (no usado)
|
|
|
+
|
|
|
+// Pines para UART2 (Serial2)
|
|
|
+#define RX_PIN 16 // RX del ESP32 conectado a TX del GPS
|
|
|
+#define TX_PIN 17 // TX del ESP32 conectado a RX del GPS
|
|
|
+#define GPS_BAUD 115200
|
|
|
+
|
|
|
+#define DHTPIN 4 // Digital pin connected to the DHT sensor
|
|
|
+#define DHTTYPE DHT22
|
|
|
+
|
|
|
+// Objeto TinyGPS++
|
|
|
+TinyGPSPlus gps;
|
|
|
+
|
|
|
+// Serial para GPS
|
|
|
+HardwareSerial gpsSerial(2);
|
|
|
+
|
|
|
+// Configuracion del DHT
|
|
|
+DHT dht(DHTPIN, DHTTYPE);
|
|
|
+
|
|
|
+//definición del objeto para la pantalla OLED
|
|
|
+Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
|
|
+
|
|
|
+// pin para pulsador
|
|
|
+
|
|
|
+#define BUTTON_PIN 0
|
|
|
+
|
|
|
+//valores de los sensores
|
|
|
+
|
|
|
+struct SensorData {
|
|
|
+ double latitude;
|
|
|
+ double longitude;
|
|
|
+ float temperature;
|
|
|
+ float humidity;
|
|
|
+ float pressure;
|
|
|
+};
|
|
|
+
|
|
|
+SensorData latestData;
|
|
|
+
|
|
|
+SemaphoreHandle_t dataMutex; // Mutex para proteger el acceso a latestData
|
|
|
+SemaphoreHandle_t buttonSemaphore; // Semáforo para la tarea del botón
|
|
|
+
|
|
|
+//flag para reducir las lecturas de DHT y presion
|
|
|
+uint8_t readSensorsFlag = 0;
|
|
|
+
|
|
|
+
|
|
|
+void DHT_test() {
|
|
|
+ dht.begin();
|
|
|
+ float h = dht.readHumidity();
|
|
|
+ float t = dht.readTemperature();
|
|
|
+ if (isnan(h) || isnan(t)) {
|
|
|
+ Serial.println("Failed to read from DHT sensor!");
|
|
|
+ OLED_print("DHT22", "Error");
|
|
|
+ while(1); // Detener si hay error
|
|
|
+ }
|
|
|
+ else OLED_print("DHT22", "Correcto");
|
|
|
+}
|
|
|
+
|
|
|
+void OLED_test() { //pantallazo a blanco y luego iniciando
|
|
|
+ // Inicia I2C en pines default ESP32 (21 SDA, 22 SCL)
|
|
|
+ if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Dirección común: 0x3C
|
|
|
+ Serial.println(F("Error: OLED no encontrado!"));
|
|
|
+ for (;;); // Para siempre
|
|
|
+ }
|
|
|
+ display.clearDisplay();
|
|
|
+ display.fillScreen(SSD1306_WHITE); // Pantalla blanca
|
|
|
+ delay(500);
|
|
|
+ display.display();
|
|
|
+ display.clearDisplay();
|
|
|
+ display.setTextSize(2); // Tamaño texto
|
|
|
+ display.setTextColor(SSD1306_WHITE);
|
|
|
+ display.setCursor(0, 0); // Posición
|
|
|
+ display.println("Iniciando...");
|
|
|
+ display.display(); // Muestra
|
|
|
+ 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()) {
|
|
|
+ Serial.println("SD Card Mount Failed");
|
|
|
+ OLED_print("SD Card", "Error\nInserte tarjeta");
|
|
|
+ while(!SD.begin()); // Detener si hay error
|
|
|
+ OLED_print("SD Card", "Insertada");
|
|
|
+ }
|
|
|
+ else OLED_print("SD Card", "Correcto");
|
|
|
+
|
|
|
+ char filename[] = "data001.txt";
|
|
|
+ int num = 1;
|
|
|
+ // Buscar un nombre de archivo disponible
|
|
|
+ while(SD.exists(filename)) {
|
|
|
+ num++;
|
|
|
+ sprintf(filename, "data%03d.txt", num);
|
|
|
+ }
|
|
|
+
|
|
|
+ File file = SD.open(filename, FILE_WRITE);
|
|
|
+ file.close();
|
|
|
+
|
|
|
+ return filename;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void GPS_test_wait() {
|
|
|
+ // Iniciar Serial2 para GPS
|
|
|
+ gpsSerial.begin(GPS_BAUD, SERIAL_8N1, RX_PIN, TX_PIN);
|
|
|
+ while ((gpsSerial.available() > 0) && !gps.location.isValid()) {
|
|
|
+ gps.encode(gpsSerial.read());
|
|
|
+ delay(10);
|
|
|
+ OLED_print("GPS", "Esperando.");
|
|
|
+ delay(100);
|
|
|
+ OLED_print("GPS", "Esperando..");
|
|
|
+ delay(100);
|
|
|
+ OLED_print("GPS", "Esperando...");
|
|
|
+ }
|
|
|
+ OLED_print("GPS", "Encontrado");
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void task_mediciones(void *pvParameters) {
|
|
|
+ TickType_t xLastWakeTime = xTaskGetTickCount();
|
|
|
+ const char* filename = (const char*) pvParameters;
|
|
|
+ while(1) {
|
|
|
+
|
|
|
+ while (gpsSerial.available() > 0) {
|
|
|
+ gps.encode(gpsSerial.read());
|
|
|
+ }
|
|
|
+ File file = SD.open(filename, FILE_WRITE);
|
|
|
+ if (file) {
|
|
|
+ // guardar datos en latestData
|
|
|
+ if (xSemaphoreTake(dataMutex, portMAX_DELAY) == pdTRUE){
|
|
|
+ latestData.latitude = gps.location.lat();
|
|
|
+ latestData.longitude = gps.location.lng();
|
|
|
+ if ((readSensorsFlag % 60) == 0) latestData.temperature = dht.readTemperature();
|
|
|
+ if ((readSensorsFlag % 120) == 0) latestData.humidity = dht.readHumidity();
|
|
|
+ latestData.pressure = 0.0; // Placeholder, no hay sensor de presión
|
|
|
+ }
|
|
|
+
|
|
|
+ // Escribir datos en el archivo
|
|
|
+ file.println(String(latestData.latitude) + "," +
|
|
|
+ String(latestData.longitude) + "," +
|
|
|
+ String(latestData.temperature) + "," +
|
|
|
+ String(latestData.humidity) + "," +
|
|
|
+ String(latestData.pressure));
|
|
|
+ xSemaphoreGive(dataMutex);
|
|
|
+
|
|
|
+ file.close();
|
|
|
+ if (!(readSensorsFlag % 120)) readSensorsFlag = 0;
|
|
|
+ readSensorsFlag++;
|
|
|
+ }
|
|
|
+
|
|
|
+ vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(10000)); // Espera 1 segundo
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void IRAM_ATTR isr_button() {
|
|
|
+ xSemaphoreGiveFromISR(buttonSemaphore, NULL);
|
|
|
+}
|
|
|
+
|
|
|
+void task_ui(void *pvParameters){
|
|
|
+ while(1){
|
|
|
+ if (xSemaphoreTake(buttonSemaphore, portMAX_DELAY) == pdTRUE){
|
|
|
+
|
|
|
+ SensorData dataCopy;
|
|
|
+ // Copiar datos protegidos por mutex
|
|
|
+ if (xSemaphoreTake(dataMutex, portMAX_DELAY) == pdTRUE){
|
|
|
+ dataCopy = latestData;
|
|
|
+ xSemaphoreGive(dataMutex);
|
|
|
+ }
|
|
|
+
|
|
|
+ //Falta implementar la parte de UI con OLED
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void setup() {
|
|
|
+ Serial.begin(115200);
|
|
|
+
|
|
|
+ // OLED check
|
|
|
+ OLED_test();
|
|
|
+ delay(500);
|
|
|
+ // DHT check
|
|
|
+ DHT_test();
|
|
|
+ delay(500);
|
|
|
+ // SD Card check
|
|
|
+ char *filename = SD_test();
|
|
|
+ delay(500);
|
|
|
+ // GPS check
|
|
|
+ GPS_test_wait();
|
|
|
+ delay(2000);
|
|
|
+
|
|
|
+ // Crear tarea para mediciones
|
|
|
+ xTaskCreatePinnedToCore(
|
|
|
+ task_mediciones, // Función de la tarea
|
|
|
+ "Mediciones", // Nombre de la tarea
|
|
|
+ 2048, // Tamaño del stack
|
|
|
+ (void*)filename, // Parámetro de la tarea
|
|
|
+ 1, // Prioridad de la tarea
|
|
|
+ NULL, // Handle de la tarea
|
|
|
+ 0 // Núcleo donde se ejecuta
|
|
|
+ );
|
|
|
+
|
|
|
+ xTaskCreatePinnedToCore(
|
|
|
+ task_ui, // Función de la tarea
|
|
|
+ "UI", // Nombre de la tarea
|
|
|
+ 2048, // Tamaño del stack
|
|
|
+ NULL, // Parámetro de la tarea
|
|
|
+ 1, // Prioridad de la tarea
|
|
|
+ NULL, // Handle de la tarea
|
|
|
+ 1 // Núcleo donde se ejecuta
|
|
|
+ );
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+void loop() {
|
|
|
+
|
|
|
+ vTaskDelay(pdMS_TO_TICKS(1000)); // Espera 1 segundo
|
|
|
+}
|