¡Proyecto integrador 3! Estación de Monitoreo Ambiental y Radar Gráfico

¡Ha llegado la hora, equipo! La misión final del curso. Este no es solo un proyecto, es la síntesis de todas sus habilidades. Van a construir un dispositivo de instrumentación completo, multifuncional e interactivo que integra medición ambiental, detección de proximidad, registro de datos y una interfaz gráfica avanzada. Hoy se convierten en diseñadores de sistemas embebidos.

🎯 El Reto

Construir una estación de monitoreo "todo en uno" que:


🔌 El Circuito: La Fusión Final de Sistemas

Componentes Necesarios:

📝 Instrucciones de Conexión:

  1. Pantalla OLED (I2C): SDA a A4, SCL a A5.
  2. Sensor DS18B20 (One-Wire): DATA al Pin 2 (con resistencia pull-up de 4.7kΩ a 5V).
  3. Sensor Ultrasónico: Trig al Pin 9, Echo al Pin 10.
  4. Joystick: VRy al Pin A0, SW (botón) al Pin 3.
  5. Servomotor: Cable de señal al Pin 6.
  6. Buzzer: Pata positiva (+) al Pin 4, pata negativa (-) a GND.
  7. Alimentación: Conecta todos los VCC a 5V y todos los GND a GND.

⚡ Diagrama de armado

Diagrama de armado Fritzing del Proyecto Integrador 3

🧠 El Código: El Sistema Operativo Final

Este es el código más completo del curso. Gestiona 4 pantallas, múltiples sensores, actuadores y entradas de usuario simultáneamente.

Código Arduino - Proyecto Integrador

/*
 * PROYECTO INTEGRADOR 3 (Definitivo): Estación Ambiental y Radar Gráfico
 * Descripción: Mide temp/distancia, muestra en 4 pantallas OLED navegables,
 * registra datos, controla servo y tiene alertas sonoras.
 * Por: Profe Campos
 * CECyTEM 05 Guacamayas
*/

// --- INCLUSIÓN DE LIBRERÍAS (NUESTRAS "CAJAS DE HERRAMIENTAS") ---
#include <Wire.h>                // Necesaria para la comunicación I2C.
#include <Adafruit_GFX.h>        // Librería gráfica base de Adafruit.
#include <Adafruit_SSD1306.h>    // Librería para controlar nuestra pantalla OLED.
#include <OneWire.h>             // Protocolo de comunicación One-Wire.
#include <DallasTemperature.h>   // Lectura del sensor DS18B20.
#include <Servo.h>               // Control del servomotor.

// --- OBJETOS Y PINES (DEFINIENDO NUESTRO HARDWARE) ---
Adafruit_SSD1306 display(128, 64, &Wire, -1); 
OneWire oneWire(2);
DallasTemperature sensors(&oneWire);
Servo miServo;

const int pinTrig = 9;
const int pinEcho = 10;
const int pinJoyY = A0;
const int pinJoySW = 3;   
const int pinServo = 6;
const int pinBuzzer = 4;

// --- VARIABLES GLOBALES (LA MEMORIA DE NUESTRO PROGRAMA) ---
int pantallaActual = 0; // 0=Principal, 1=DataLog, 2=Radar Gráfico, 3=Radar Numérico

float distanciaCm = 0;
float tempC = 0;
long duracion; 

// Variables para el registro de datos (Data Logging).
float tempMax = -100; 
float tempMin = 200;  
float distMax = 0;
float distMin = 500; 

//=============================================================================
// FUNCIÓN SETUP
//=============================================================================
void setup() {
  Serial.begin(9600);
  
  sensors.begin(); 
  miServo.attach(pinServo); 
  
  pinMode(pinTrig, OUTPUT);
  pinMode(pinEcho, INPUT);
  pinMode(pinBuzzer, OUTPUT);
  pinMode(pinJoySW, INPUT_PULLUP); 
  
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("Fallo al iniciar SSD1306"));
    for(;;); 
  }
  
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 10);
  display.println("SISTEMA");
  display.setCursor(10, 35);
  display.println("INICIADO");
  display.display(); 
  delay(2000);
}

//=============================================================================
// FUNCIÓN LOOP
//=============================================================================
void loop() {
  // --- NAVEGACIÓN Y ACCIONES DEL JOYSTICK ---
  int valorJoy = analogRead(pinJoyY);
  if (valorJoy < 100) { 
    pantallaActual++; 
    if (pantallaActual > 3) pantallaActual = 0; 
    delay(200); 
  }
  if (valorJoy > 900) { 
    pantallaActual--; 
    if (pantallaActual < 0) pantallaActual = 3; 
    delay(200);
  }
  if (pantallaActual == 1 && digitalRead(pinJoySW) == LOW) {
    resetDataLog(); 
  }

  // --- LECTURA DE SENSORES ---
  leerSensores(); 

  // --- ACTUALIZACIÓN DE DATOS MÁXIMOS Y MÍNIMOS ---
  actualizarDataLog(); 

  // --- COMPROBACIÓN DE ALERTAS ---
  comprobarAlertas(); 

  // --- ACTUALIZAR PANTALLA ---
  display.clearDisplay(); 
  
  if (pantallaActual == 0) dibujarPantallaPrincipal();
  else if (pantallaActual == 1) dibujarPantallaDataLog();
  else if (pantallaActual == 2) dibujarPantallaRadarGrafico();
  else if (pantallaActual == 3) dibujarPantallaRadarNumerico();
  
  display.display(); 
  delay(100); 
}

//=============================================================================
// --- FUNCIONES AUXILIARES ---
//=============================================================================

void leerSensores() {
  sensors.requestTemperatures(); 
  tempC = sensors.getTempCByIndex(0);
  
  digitalWrite(pinTrig, LOW);
  delayMicroseconds(2);
  digitalWrite(pinTrig, HIGH);
  delayMicroseconds(10);
  digitalWrite(pinTrig, LOW);
  duracion = pulseIn(pinEcho, HIGH);
  distanciaCm = duracion * 0.0343 / 2.0;
  distanciaCm = constrain(distanciaCm, 0, 200); 
}

void actualizarDataLog() {
  if (tempC > tempMax) tempMax = tempC;
  if (tempC < tempMin) tempMin = tempC;
  if (distanciaCm > distMax) distMax = distanciaCm;
  if (distanciaCm < distMin && distanciaCm > 0) distMin = distanciaCm; 
}

void resetDataLog() {
  tempMax = tempC; 
  tempMin = tempC; 
  distMax = distanciaCm;
  distMin = distanciaCm;
  
  tone(pinBuzzer, 1500, 100); 
  display.clearDisplay();
  display.setTextSize(2);
  display.setCursor(15,25);
  display.print("DATOS");
  display.setCursor(5,45);
  display.print("REINICIADOS");
  display.display();
  delay(1000); 
}

void comprobarAlertas() {
  if (tempC > 40.0 || (distanciaCm < 10 && distanciaCm > 0)) {
    display.fillTriangle(0,0, 10,0, 0,10, SSD1306_WHITE);
    tone(pinBuzzer, 2000, 150);
  }
}

// --- FUNCIONES DE DIBUJO DE PANTALLAS ---

void dibujarPantallaPrincipal() {
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print("--- MONitoreo AMBIENTAL ---");
  display.setTextSize(2);
  display.setCursor(5, 20);
  display.print(tempC, 1);
  display.print(" ");
  display.setTextSize(1);
  display.drawCircle(75, 22, 3, SSD1306_WHITE); 
  display.setTextSize(2);
  display.print("C");
  int anguloTemp = map(tempC, 0, 50, 0, 180);
  miServo.write(anguloTemp);
  display.setTextSize(1);
  display.setCursor(0, 55);
  display.print("Mover Joystick->");
}

void dibujarPantallaDataLog() {
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print("--- REGISTRO DE DATOS ---");
  display.setCursor(0, 15);
  display.print("T.Max: "); display.print(tempMax, 1); display.print("C");
  display.setCursor(0, 28);
  display.print("T.Min: "); display.print(tempMin, 1); display.print("C");
  display.setCursor(0, 41);
  display.print("D.Max: "); display.print(distMax, 0); display.print("cm");
  display.setCursor(0, 54);
  display.print("D.Min: "); display.print(distMin, 0); display.print("cm");
}

void dibujarPantallaRadarGrafico() {
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print("--- RADAR GRAFICO ---");
  
  static int anguloScan = 0; 
  static int direccion = 1; 
  anguloScan += direccion;
  if (anguloScan >= 180 || anguloScan <= 0) {
    direccion *= -1; 
  }
  miServo.write(anguloScan);

  display.drawArc(64, 63, 60, 60, 0, 180, SSD1306_WHITE);

  float anguloRad = anguloScan * PI / 180.0; 
  int x2 = 64 - cos(anguloRad) * 60;
  int y2 = 63 - sin(anguloRad) * 60;
  display.drawLine(64, 63, x2, y2, SSD1306_WHITE);

  if (distanciaCm < 60) {
    float anguloBlip = miServo.read() * PI / 180.0;
    int xBlip = 64 - cos(anguloBlip) * distanciaCm;
    int yBlip = 63 - sin(anguloBlip) * distanciaCm;
    display.fillCircle(xBlip, yBlip, 3, SSD1306_WHITE); 
  }
}

void dibujarPantallaRadarNumerico() {
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print("--- RADAR DE PROXIMIDAD ---");
  display.setTextSize(3);
  display.setCursor(5, 25);
  display.print(distanciaCm, 0);
  display.setTextSize(2);
  display.print("cm");
  int barra = map(distanciaCm, 100, 5, 0, 128);
  barra = constrain(barra, 0, 128);
  display.fillRect(0, 58, barra, 6, SSD1306_WHITE);
  int anguloDist = map(distanciaCm, 5, 100, 180, 0);
  miServo.write(anguloDist);
}

🏆 ¡MISIÓN CUMPLIDA, INGENIEROS!

¡Lo han logrado! Han recorrido el camino completo desde encender un LED hasta construir un dispositivo de medición multifuncional con una interfaz gráfica. Han demostrado un dominio de sensores digitales, analógicos, protocolos de comunicación I2C y One-Wire, y han creado un sistema robusto y complejo.

Este proyecto no es solo la culminación de un curso, es el primer paso en su carrera como creadores de tecnología. El conocimiento que tienen ahora es la base para la robótica, la domótica, el Internet de las Cosas y la instrumentación industrial.

El futuro es suyo para programarlo. ¡Felicidades! - Profe Campos