Leçon 8 / 8
Leçon 08 · Arduino

Projet : station météo

Présentation du projet

Dans ce projet final, on assemble tout ce qu'on a appris pour construire une station météo autonome. Elle mesure la température, l'humidité et la pression atmosphérique, affiche les données sur un écran LCD, et les enregistre sur une carte SD pour un suivi dans le temps.

Matériel nécessaire

  • Arduino Uno (ou compatible)
  • Capteur DHT11 — température (0–50 °C) et humidité relative (20–90 %)
  • Capteur BMP280 — pression atmosphérique et température (I2C)
  • Afficheur LCD I2C 16×2 — module avec adaptateur PCF8574
  • Module carte SD — avec carte microSD formatée en FAT32
  • Breadboard et fils de connexion
  • Résistance 10 kΩ (pull-up pour le DHT11)

Schéma de câblage

Voici comment connecter chaque composant à l'Arduino Uno :

DHT11 (données numériques)

  • VCC → 5 V
  • GND → GND
  • DATA → pin 7 (avec résistance pull-up 10 kΩ vers 5 V)

BMP280 (I2C)

  • VCC → 3.3 V
  • GND → GND
  • SDA → pin A4 (SDA Arduino Uno)
  • SCL → pin A5 (SCL Arduino Uno)

LCD I2C 16×2

  • VCC → 5 V
  • GND → GND
  • SDA → pin A4 (bus I2C partagé avec BMP280)
  • SCL → pin A5 (bus I2C partagé avec BMP280)

Module carte SD (SPI)

  • VCC → 5 V
  • GND → GND
  • MOSI → pin 11 (SPI MOSI)
  • MISO → pin 12 (SPI MISO)
  • SCK → pin 13 (SPI SCK)
  • CS → pin 10 (Chip Select)
💡

Le BMP280 et le LCD partagent le même bus I2C (pins A4/A5). Ils ont des adresses différentes (BMP280 : 0x76 ou 0x77 ; LCD : 0x27 en général), donc ils coexistent sans problème. Utilise un scanner I2C pour vérifier les adresses de tes modules si tu n'obtiens rien à l'écran.

Bibliothèques nécessaires

Installe ces bibliothèques depuis le Gestionnaire de bibliothèques (menu Outils → Gérer les bibliothèques…) de l'IDE Arduino :

  • DHT sensor library par Adafruit — pour le DHT11
  • Adafruit BMP280 Library par Adafruit — pour le BMP280
  • LiquidCrystal I2C par Frank de Brabander — pour l'écran LCD
  • SD — bibliothèque officielle Arduino, déjà incluse dans l'IDE

Dépendance automatique : quand tu installes DHT sensor library, l'IDE te propose aussi d'installer Adafruit Unified Sensor. Accepte — c'est une dépendance requise. De même pour Adafruit BMP280 Library.

Code étape par étape

Étape 1 — Lire le DHT11

Commence par tester le DHT11 seul avant d'assembler le projet complet. La bibliothèque DHT fournit les méthodes readTemperature() et readHumidity().

test_dht11.ino
// Test du capteur DHT11
#include <DHT.h>

#define PIN_DHT  7
#define TYPE_DHT DHT11

DHT dht(PIN_DHT, TYPE_DHT);

void setup() {
  Serial.begin(9600);
  dht.begin();
  Serial.println("DHT11 prêt");
}

void loop() {
  float temp = dht.readTemperature();   // °C
  float hum  = dht.readHumidity();      // %

  // Vérifier si la lecture a réussi
  if (isnan(temp) || isnan(hum)) {
    Serial.println("Erreur de lecture DHT11 !");
  } else {
    Serial.print("Temp : ");
    Serial.print(temp);
    Serial.print(" °C   Humidité : ");
    Serial.print(hum);
    Serial.println(" %");
  }

  delay(2000);  // Le DHT11 ne peut pas être lu plus d'1 fois/2 s
}

Étape 2 — Lire le BMP280

Le BMP280 communique en I2C. La bibliothèque Adafruit gère la conversion des valeurs brutes du capteur en Pascals et en degrés Celsius.

test_bmp280.ino
// Test du capteur BMP280
#include <Wire.h>
#include <Adafruit_BMP280.h>

Adafruit_BMP280 bmp;

void setup() {
  Serial.begin(9600);

  if (!bmp.begin(0x76)) {
    Serial.println("BMP280 non trouvé ! Vérif câblage ou adresse (0x76 / 0x77)");
    while (1);  // blocage
  }
  Serial.println("BMP280 prêt");
}

void loop() {
  float temp     = bmp.readTemperature();          // °C
  float pression = bmp.readPressure() / 100.0F;  // Pa → hPa

  Serial.print("Temp BMP : "); Serial.print(temp);     Serial.print(" °C   ");
  Serial.print("Pression : "); Serial.print(pression); Serial.println(" hPa");

  delay(2000);
}

Étape 3 — Afficher sur le LCD I2C

L'objet LiquidCrystal_I2C prend en paramètre l'adresse I2C du module, le nombre de colonnes (16) et de lignes (2). setCursor(col, row) positionne le curseur.

test_lcd.ino
// Test de l'afficheur LCD I2C
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// Adresse 0x27, 16 colonnes, 2 lignes
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  lcd.init();
  lcd.backlight();

  lcd.setCursor(0, 0);  // col 0, ligne 0
  lcd.print("Station Meteo");

  lcd.setCursor(0, 1);  // col 0, ligne 1
  lcd.print("Initialisation...");

  delay(2000);
  lcd.clear();
}

void loop() {
  lcd.setCursor(0, 0);
  lcd.print("Temp: 22.5 C    ");

  lcd.setCursor(0, 1);
  lcd.print("Hum:  58 %      ");

  delay(2000);
}

Le programme complet

On assemble maintenant les trois capteurs et l'afficheur dans un seul programme. Le LCD alterne entre deux pages : température/humidité (DHT11) et pression (BMP280).

station_meteo.ino
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_BMP280.h>
#include <LiquidCrystal_I2C.h>

// ===== CONFIGURATION =====
#define PIN_DHT  7
#define TYPE_DHT DHT11

DHT             dht(7, DHT11);
Adafruit_BMP280 bmp;
LiquidCrystal_I2C lcd(0x27, 16, 2);

// Variables de mesure
float temperature = 0;
float humidite    = 0;
float pression    = 0;

// Contrôle de l'affichage alterné
bool          affichePage1 = true;
unsigned long dernierChangement = 0;
const unsigned long DELAI_AFFICHAGE = 3000;  // ms

unsigned long derniereLecture = 0;
const unsigned long DELAI_LECTURE = 2000;

// ===== SETUP =====
void setup() {
  Serial.begin(9600);

  // Initialisation LCD
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0); lcd.print("Station Meteo");
  lcd.setCursor(0, 1); lcd.print("Demarrage...");

  // Initialisation DHT11
  dht.begin();

  // Initialisation BMP280
  if (!bmp.begin(0x76)) {
    lcd.setCursor(0, 1);
    lcd.print("BMP280 ERR!     ");
    Serial.println("BMP280 non trouvé !");
    while (1);
  }

  delay(2000);
  lcd.clear();
  Serial.println("Prêt.");
}

// ===== LIRE LES CAPTEURS =====
void lireCapteurs() {
  float t = dht.readTemperature();
  float h = dht.readHumidity();

  if (!isnan(t) && !isnan(h)) {
    temperature = t;
    humidite    = h;
  }

  pression = bmp.readPressure() / 100.0F;
}

// ===== AFFICHER SUR LCD =====
void afficherLCD() {
  if (affichePage1) {
    // Page 1 : température + humidité
    lcd.setCursor(0, 0);
    lcd.print("Temp: ");
    lcd.print(temperature, 1);
    lcd.print(" C     ");

    lcd.setCursor(0, 1);
    lcd.print("Hum:  ");
    lcd.print(humidite, 0);
    lcd.print(" %      ");
  } else {
    // Page 2 : pression atmosphérique
    lcd.setCursor(0, 0);
    lcd.print("Pression :      ");

    lcd.setCursor(0, 1);
    lcd.print(pression, 1);
    lcd.print(" hPa       ");
  }
}

// ===== LOOP =====
void loop() {
  unsigned long maintenant = millis();

  // Lire les capteurs toutes les 2 secondes
  if (maintenant - derniereLecture >= DELAI_LECTURE) {
    derniereLecture = maintenant;
    lireCapteurs();

    // Aussi envoyer sur le port série
    Serial.print("T:"); Serial.print(temperature); Serial.print("C  ");
    Serial.print("H:"); Serial.print(humidite);    Serial.print("%  ");
    Serial.print("P:"); Serial.print(pression);    Serial.println("hPa");
  }

  // Changer de page toutes les 3 secondes
  if (maintenant - dernierChangement >= DELAI_AFFICHAGE) {
    dernierChangement = maintenant;
    affichePage1 = !affichePage1;
    afficherLCD();
  }
}

Enregistrement sur carte SD

On ajoute l'enregistrement dans un fichier meteo.csv sur la carte SD. Chaque ligne contient un numéro de mesure, la température, l'humidité et la pression. Le fichier s'ouvre en mode append (FILE_WRITE) pour ne pas écraser les données.

station_meteo_sd.ino — ajout SD
// En haut du fichier, ajouter :
#include <SPI.h>
#include <SD.h>

#define PIN_CS_SD  10

bool  sdDisponible = false;
unsigned long compteurMesures = 0;

// Dans setup(), après les autres init :
if (!SD.begin(PIN_CS_SD)) {
  Serial.println("Carte SD non trouvée — données non enregistrées");
  sdDisponible = false;
} else {
  sdDisponible = true;

  // Écrire l'en-tête CSV si le fichier n'existe pas encore
  if (!SD.exists("meteo.csv")) {
    File f = SD.open("meteo.csv", FILE_WRITE);
    if (f) {
      f.println("mesure,temperature_C,humidite_pct,pression_hPa");
      f.close();
    }
  }
  Serial.println("Carte SD prête.");
}

// Fonction d'enregistrement à appeler après lireCapteurs()
void enregistrerSD() {
  if (!sdDisponible) return;

  File fichier = SD.open("meteo.csv", FILE_WRITE);
  if (fichier) {
    compteurMesures++;
    fichier.print(compteurMesures);   fichier.print(",");
    fichier.print(temperature, 1);   fichier.print(",");
    fichier.print(humidite, 0);      fichier.print(",");
    fichier.println(pression, 1);
    fichier.close();
  } else {
    Serial.println("Erreur ouverture meteo.csv");
  }
}

// Dans loop(), après lireCapteurs() :
enregistrerSD();

Le fichier meteo.csv sur la carte SD ressemblera à :

meteo.csv
mesure,temperature_C,humidite_pct,pression_hPa
1,22.5,58,1013.2
2,22.6,57,1013.1
3,22.5,58,1013.3
4,22.7,56,1013.0

Une fois la carte SD retirée et connectée à ton ordinateur, tu peux ouvrir ce fichier dans un tableur (Excel, LibreOffice Calc, Google Sheets) pour tracer des graphiques d'évolution sur la journée.

Améliorations possibles

Affichage alterné par bouton

Ajoute un bouton sur la pin 2 pour basculer manuellement entre les pages du LCD au lieu d'attendre le timer :

bouton.ino
#define PIN_BOUTON  2

// Dans setup() :
pinMode(PIN_BOUTON, INPUT_PULLUP);  // résistance pull-up interne

// Dans loop() — détecter un appui (LOW = appuyé avec INPUT_PULLUP) :
static bool etatPrecedent = HIGH;
bool etatActuel = digitalRead(PIN_BOUTON);

if (etatPrecedent == HIGH && etatActuel == LOW) {
  // Front descendant = appui détecté
  affichePage1 = !affichePage1;
  afficherLCD();
  delay(50);  // anti-rebond simple
}
etatPrecedent = etatActuel;

Idées pour aller plus loin

  • Ajouter un module RTC DS3231 (horloge temps réel) pour horodater les mesures dans le CSV
  • Ajouter une alarme LED ou buzzer si la température dépasse un seuil
  • Remplacer l'Arduino par un ESP8266 ou ESP32 pour envoyer les données en WiFi
  • Publier les mesures via le protocole MQTT vers un broker (Mosquitto) et les afficher dans Grafana ou Home Assistant
📡

Prochaine étape : avec un ESP8266 NodeMCU, tu peux remplacer presque tout le câblage par du WiFi. La bibliothèque PubSubClient permet d'envoyer les mesures en MQTT en moins de 20 lignes de code supplémentaires. C'est le point de départ d'une vraie domotique DIY.

Bilan du module Arduino

Tu as parcouru les 8 leçons du module. Voici ce que tu maîtrises maintenant :

  • L'environnement Arduino : IDE, carte Uno, structure setup() / loop()
  • Les entrées/sorties numériques : pinMode(), digitalWrite(), digitalRead()
  • Les entrées analogiques : analogRead(), conversion en tension, capteurs résistifs
  • Le PWM : analogWrite(), contrôle de LED et de moteur DC
  • La communication série : Serial.print(), Serial.read(), moniteur série
  • Les bibliothèques I2C et SPI : Wire, adressage, EEPROM externe, modules courants
  • Un projet complet : capteurs DHT11 et BMP280, afficheur LCD, enregistrement SD
// À retenir
  • DHT11 sur pin numérique (pin 7) — lecture toutes les 2 secondes minimum. Toujours vérifier isnan().
  • BMP280 et LCD partagent le bus I2C (A4/A5) — chacun a son adresse, pas de conflit.
  • La carte SD utilise le bus SPI (pins 10–13) — ne jamais utiliser pin 10 pour autre chose.
  • Utilise millis() au lieu de delay() pour gérer plusieurs temporisations en parallèle sans bloquer le programme.
  • Le fichier CSV permet une analyse facile des données dans un tableur ou avec Python/matplotlib.
  • Prochaine étape : ESP8266/ESP32 pour passer du hardware au IoT connecté.