Início›Projetos›Estação Meteo.
⬤ Projeto Integrado · LCD + DHT + LDR + Chars custom

🌤️ Estação Meteorológica com Dashboard LCD

⏱️ 45–55 min 🧩 LCD 20×4 · DHT11 · LDR · Chars custom · Scroll de alertas · CSV Serial

Nesta página

🎯 Objetivo e Resultado

Dashboard meteorológico completo nas 4 linhas do LCD: temperatura com ícone de termómetro, humidade com ícone de gota, luminosidade com barra gráfica e linha de alertas com scroll automático quando valores ultrapassam limiares. Dados enviados via Serial em formato CSV para registo externo.

Temp: 24.3C Hum:6 Luz: 412 (40%) [ ]<<< TEMP. ALTA! >>

🔌 Ligações

ComponentePino ArduinoNota
LCD 20×4 (I2C)A4 (SDA) / A5 (SCL)Endereço 0x27
DHT11 (módulo #19 Kit B 37)D4Temp. e humidade — biblioteca Adafruit DHT
LDR (módulo #22 Kit B 37)A0Luminosidade 0–1023
Buzzer passivo (opcional)D8Alerta sonoro em emergência
ℹ️
Os módulos DHT11 e LDR são do Kit B 37 (PR.FT6_15) mas são totalmente compatíveis com a placa PR.FT9_5 — ligam-se directamente com Dupont aos pinos livres do Arduino que não são usados pelo LCD ou motor driver.

🔨 Fases de Montagem

Fase 1 — Chars custom e LCD

Regista os 6 ícones (termómetro, gota, sol, grau, bloco, alerta). Inicializa LCD e confirma que os ícones aparecem nas posições correctas.

Fase 2 — DHT11

Liga ao D4. Instala a biblioteca Adafruit DHT via Gestor de Bibliotecas. Testa leitura simples de T e H no Serial Monitor.

Fase 3 — LDR

Liga ao A0. Lê com analogRead(A0). Mapeia para percentagem e barra gráfica. Confirma que a barra responde ao tapar o sensor.

Fase 4 — Dashboard e alertas

Integra os três sensores no dashboard das 4 linhas com actualização por millis(). Adiciona scroll de alertas na linha 3 quando limiares são ultrapassados.

Fase 5 — CSV via Serial

Activa o cabeçalho CSV no setup() e envia uma linha a cada 5s. Liga ao Raspberry Pi ou computador para registar o ficheiro.

💻 Código Completo

proj_estacao_meteo.ino
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>

LiquidCrystal_I2C lcd(0x27, 20, 4);
DHT dht(4, DHT11);

#define LDR_PIN  A0
#define BUZZER   8
#define TEMP_MAX 28.0
#define HUM_MAX  70.0
#define LUZ_MIN  200
#define CSV_MS   5000   // enviar CSV a cada 5s

// ── Chars custom ─────────────────────────────────────────────
byte ic_term[8]  = {0b00100,0b01010,0b01010,0b01110,0b01110,0b11111,0b11111,0b01110}; // termómetro
byte ic_gota[8]  = {0b00100,0b00100,0b01010,0b01010,0b10001,0b10001,0b10001,0b01110}; // gota
byte ic_sol[8]   = {0b00100,0b10101,0b01110,0b11011,0b11011,0b01110,0b10101,0b00100}; // sol
byte ic_grau[8]  = {0b00110,0b01001,0b01001,0b00110,0b00000,0b00000,0b00000,0b00000}; // °
byte ic_bloco[8] = {0b11111,0b11111,0b11111,0b11111,0b11111,0b11111,0b11111,0b11111}; // █
byte ic_alrt[8]  = {0b00100,0b01110,0b01110,0b11111,0b10001,0b11111,0b00000,0b00100}; // ⚠

// ── Timers ────────────────────────────────────────────────────
unsigned long tSensor=0, tScroll=0, tCSV=0;
int  posScroll=0;
String msgAlerta = "";
float ultT=-99, ultH=-99;
int   ultL=-1;

// ── Barra gráfica de luminosidade ────────────────────────────
void barraLuz(int ldr) {
  int b = ldr * 18 / 1023;
  lcd.setCursor(0, 2); lcd.print("[");
  for(int i=0; i<18; i++) i<b ? lcd.write(4) : lcd.write(32);
  lcd.print("]");
}

// ── Gerar mensagem de alerta ──────────────────────────────────
String gerarAlerta(float t, float h, int l) {
  if(t > TEMP_MAX) return "ALERTA: Temp. alta! Verificar ventilacao.";
  if(h > HUM_MAX)  return "ALERTA: Humidade alta! Risco de condensacao.";
  if(l < LUZ_MIN)  return "INFO: Luminosidade baixa. Ligar iluminacao?";
  return           "Sistema OK. T:" + String(t,1) + "C H:" + String(h,0) + "% L:" + String(l);
}

void setup() {
  lcd.createChar(0, ic_term);  lcd.createChar(1, ic_gota);
  lcd.createChar(2, ic_sol);   lcd.createChar(3, ic_grau);
  lcd.createChar(4, ic_bloco); lcd.createChar(5, ic_alrt);
  lcd.init(); lcd.backlight();
  dht.begin();
  Serial.begin(9600);
  Serial.println("ms,temperatura,humidade,luminosidade,estado");
  lcd.setCursor(1,1); lcd.print("Estacao Meteo LCD");
  delay(1500); lcd.clear();
}

void loop() {
  unsigned long agora = millis();

  // ── Ler sensores a cada 2s ────────────────────────────────
  if (agora - tSensor >= 2000) {
    float t = dht.readTemperature();
    float h = dht.readHumidity();
    int   l = analogRead(LDR_PIN);

    if(!isnan(t) && !isnan(h)) {
      // Linha 0 — temperatura
      if(abs(t-ultT) > 0.1) {
        lcd.setCursor(0,0); lcd.write(0);
        lcd.print(" Temp: "); lcd.print(t,1);
        lcd.write(3); lcd.print("C  ");
        ultT=t;
      }
      // Linha 1 — humidade
      if(abs(h-ultH) > 0.5) {
        lcd.setCursor(0,1); lcd.write(1);
        lcd.print(" Hum: "); lcd.print(h,0);
        lcd.print("%  Luz:");lcd.print(l);lcd.print("   ");
        ultH=h;
      }
      // Linha 2 — barra luminosidade
      if(abs(l-ultL) > 5) { barraLuz(l); ultL=l; }

      // Actualiza mensagem de alerta
      msgAlerta = String("                    ") + gerarAlerta(t,h,l);
      posScroll = 0;

      // Alerta sonoro se temperatura alta
      if(t > TEMP_MAX) { tone(BUZZER,880,400); }
    }
    tSensor = agora;
  }

  // ── Scroll da linha 3 a cada 250ms ───────────────────────
  if (agora - tScroll >= 250 && msgAlerta.length() > 0) {
    lcd.setCursor(0, 3);
    lcd.print(msgAlerta.substring(posScroll, posScroll + 20));
    posScroll++;
    if(posScroll > (int)msgAlerta.length() - 20) posScroll = 0;
    tScroll = agora;
  }

  // ── CSV a cada 5s ─────────────────────────────────────────
  if (agora - tCSV >= CSV_MS) {
    float t = dht.readTemperature();
    float h = dht.readHumidity();
    int   l = analogRead(LDR_PIN);
    if(!isnan(t)) {
      Serial.print(agora); Serial.print(",");
      Serial.print(t,1);  Serial.print(",");
      Serial.print(h,1);  Serial.print(",");
      Serial.print(l);    Serial.print(",");
      Serial.println(t > TEMP_MAX || h > HUM_MAX ? "ALERTA" : "OK");
    }
    tCSV = agora;
  }
}

📊 Registo CSV — Análise de Dados

💡
Liga o Arduino ao Raspberry Pi via USB. Usa o script Python abaixo para capturar os dados em CSV. Abre depois com LibreOffice Calc ou Excel para fazer gráficos da evolução temporal.
logger_meteo.py
#!/usr/bin/env python3
# pip3 install pyserial
import serial, csv
from datetime import datetime

PORTA   = "/dev/ttyACM0"   # Ajustar conforme o sistema
BAUD    = 9600
ficheiro = f"meteo_{datetime.now().strftime('%Y%m%d_%H%M')}.csv"

with serial.Serial(PORTA, BAUD, timeout=5) as ser:
    with open(ficheiro, "w", newline="") as f:
        w = csv.writer(f)
        cabecalho = ser.readline().decode().strip().split(",")
        w.writerow(["hora"] + cabecalho[1:])  # substitui ms por hora real
        print(f"A registar em {ficheiro} ...")
        while True:
            linha = ser.readline().decode().strip()
            if not linha: continue
            campos = linha.split(",")
            if len(campos) >= 5:
                agora = datetime.now().strftime("%H:%M:%S")
                w.writerow([agora] + campos[1:])
                f.flush()
                print(f"{agora} T:{campos[1]}C H:{campos[2]}% L:{campos[3]} [{campos[4]}]")

🚀 Como Expandir

🏆 Para ir mais longe

PR.FT9_5 · LCD 20×4 · L293D Motor Driver · Arduino UNO Rev3 · Início · led.dge.medu.pt