[TUTORIEL] Mini station météo

Un log shield sur carte SD avec horloge RTC et zone de prototypage à pastilles carrées

[TUTORIEL] Mini station météo

Message non lude Laetitia » Mer 26 Nov 2014 14:33

Bonjour,

Aujourd'hui nous allons apprendre à monter une station météo rudimentaire, qui relèvera la température, le taux d'humidité ainsi que la luminosité ambiante. Les données horodatées seront enregistrées à intervalles réguliers sur la carte SD embarquée sur le Mémoire, sous forme d'un tableau .csv de manière à pouvoir les exploiter plus facilement. À la fin de ce tutoriel, pour aller plus loin, nous ajouterons un Deuligne au montage existant pour afficher les données en temps réel 8-)

Ce tutoriel avait été préparé pour un atelier d'initiation à l'électronique embarquée. Nous avons pensé qu'un projet complet mettant en oeuvre deux de nos shields pouvait intéresser d'autres personnes : inspirez-vous-en, remixez-le, faites-le évoluer et racontez-nous ce que vous en avez fait !

- MATÉRIEL -

- Arduino Uno (x1)
- Shield Mémoire 2.0 (x1)
- Capteur de température et d'humidité DHT11 (x1)
- Photorésistance (x1)
- Résistance 10 kOhms (x1)
- Optionnel : Shield Deuligne (x1)

Librairies... pardon, bibliothèques, à installer :
- RTClib
- DHT
- Deuligne

- SCHÉMA DU MONTAGE -

StationMeteo.png
StationMeteo.png (95.59 Kio) Vu 4622 fois

Les plus observateurs remarqueront :

- que le shield Mémoire présenté ici est le Mémoire 1.0 et non le 2.0 : les branchements et le code sont identiques pour les deux versions du shield. Vous pouvez en revanche adapter le code pour un Mémoire 2.0+ en utilisant le DS3231 à la place du DS1307 !

- qu'il s'agit d'un DHT22 et non d'un DHT11 : même câblage pour ces deux capteurs (voir ci-dessous), mais pensez à définir le bon type de capteur dans votre code... Notez également la présence d'une résistance de tirage sur la ligne Data du capteur, indispensable pour le bon fonctionnement du montage !

DHT_pinout.jpg
DHT_pinout.jpg (6.16 Kio) Vu 4622 fois

- EXPLICATIONS -

Le capteur relève le taux d'humidité ainsi que la température, puis envoie les données correspondantes via sa broche Data, suivant un protocole spécifique (voir datasheet). La bibliothèque DHT permet de faire une lecture simple des données en provenance des capteurs. Il faut lui indiquer le type de capteur concerné (DHT11, DHT22...), la broche à laquelle il est relié, puis les fonctions readHumidity() et readTemperature() renvoient la valeur lue sous forme d'un float que l'on peut alors traiter.

La valeur lue sur l'entrée analogique de l'Arduino, en provenance de la photorésistance, sera convertie en pourcentage pour faciliter la lecture.

Dans un premier temps, nous allons afficher les valeurs lues sur les différents capteurs sur le moniteur série. Puis nous les enregistrerons sur la carte SD toutes les 10 secondes. Le délai peut sembler court mais c'est pour que vous n'ayez pas à attendre trop longtemps avant de vérifier si les données ont été correctement inscrites sur la carte SD. Une fois que vous avez validé vos tests, remplacez ".second" par ".minute", ou ajustez suivant vos besoins ;)

Une fois votre montage prêt, programmez votre Arduino avec le code ci-dessous. Pour tester si tout fonctionne bien, passez votre main au-dessus de la photorésistance pour regarder si la luminosité varie bien, et pour faire augmenter la chaleur et l'humidité soufflez sur le capteur ou tenez-le au creux de votre main !

- CODE -

Code: Tout sélectionner
/*
 * Tutoriel : Mini station météo
 * Matériel : Arduino Uno + DHT11 + photorésistance + Mémoire 2.0 (DS1307)
 */

    /* RELEVÉ DONNÉES MÉTÉO */
   
// Inclusion de la librairie nécessaire pour la lecture du DHT11
#include <DHT.h>

//Déclaration des pins reliées aux capteurs
#define photores 1
#define DHTPIN 2

// Déclaration du type de capteur utilisé et initialisation
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

// Déclaration des variables nécessaires
float hum;
float temp;
int lum;

    /* DATALOGGING */

// Inclusion des librairies nécessaires à l'utilisation du shield Mémoire
// (les deux premières sont intégrées à l'IDE Arduino)
#include <SD.h>
#include <Wire.h>
#include <RTClib.h>

// Déclaration des objets liés à l'horloge
RTC_DS1307 RTC;
DateTime timestamp;
int updateTime;

void setup()
{
  Serial.begin(9600); // Initialisation liaison série
  dht.begin();        // Initialisation DHT11
 
  // Initialisation carte SD
  pinMode(10, OUTPUT);
  if (!SD.begin(10))
  {
    // Arrêt programme en cas d'erreur
    Serial.println("SD Card failed !");
    return;
  }
  Serial.println("SD Card initialized.");
 
  // Initialisation RTC
  Wire.begin();
  RTC.begin();
 
  // Mise à l'heure suivant paramètres système
  RTC.adjust(DateTime(__DATE__, __TIME__));
  if (!RTC.isrunning())
  {
    Serial.println("RTC is NOT running !");
  }
  Serial.println("DS1307 set.");
 
  // Sauvegarde de l'heure de départ pour commencer l'enregistrement des données
  DateTime startTime = RTC.now();
  updateTime = startTime.second();
 
  // Mise en page du tableau CSV
  File fichier = SD.open("meteo.csv", FILE_WRITE);
  // Le ';' fait office de séparateur et permet de passer d'une case à la suivante
  // le '\n' permet de passer à la ligne suivante. Équivaut à un fichier.println("");
  fichier.print("Date;Heure;Humidite (%);Temperature (*C);Luminosite (%)\n");
  fichier.close();
}

void loop()
{
  // Relevé des valeurs en provenance du DHT11
  hum = dht.readHumidity();
  temp = dht.readTemperature();
 
  // Relevé des valeurs en provenance de la photorésistance et conversion en pourcentage
  lum = analogRead(photores);
  lum = map(lum, 0, 1023, 0, 100); // Valeurs 0 et 1023 à rajuster en fonction des conditions réelles
 
  // Timestamp
  timestamp = RTC.now();

  // Impression sur moniteur série
  Serial.print(timestamp.year(), DEC);
  Serial.print('/');
  Serial.print(timestamp.month(), DEC);
  Serial.print('/');
  Serial.print(timestamp.day(), DEC);
  Serial.print(' ');
  Serial.print(timestamp.hour(), DEC);
  Serial.print(':');
  Serial.print(timestamp.minute(), DEC);
  Serial.print(':');
  if (timestamp.second() < 10)
  {
    Serial.print('0');
  }
  Serial.print(timestamp.second(), DEC);
  Serial.print(" - ");
 
  Serial.print("Humidite : ");
  Serial.print(hum);
  Serial.print(" %\t"); // la tabulation '\t' permet une mise en page simple
  Serial.print("Temperature : ");
  Serial.print(temp);
  Serial.print(" *C\t");
  Serial.print("Luminosite : ");
  Serial.print(lum);
  Serial.println(" %");
 
  // On regarde s'il est temps de faire un relevé sur la carte SD
  // C'est-à-dire s'il s'est écoulé plus de 10 secondes depuis le dernier relevé
  if ((timestamp.second() - 10) == updateTime)
  {
    // auquel cas on remet à jour la variable concernée
    updateTime = timestamp.second();
    // puis on écrit les données
    printFile();
  }
  // cas particulier : lorsque le dernier relevé est à __:__:5_, le prochain doit se faire à __:__:0_
  else if ((timestamp.second() < 10) && ((timestamp.second() + 50) == updateTime))
  {
    updateTime = timestamp.second();
    printFile();
  }
 
  delay(1000);
}

void printFile()
{
  // Impression dans fichier texte sur carte SD
  File fichier = SD.open("meteo.csv", FILE_WRITE);
 
  // Date et heure
  fichier.print(timestamp.year(), DEC);
  fichier.print('/');
  fichier.print(timestamp.month(), DEC);
  fichier.print('/');
  fichier.print(timestamp.day(), DEC);
  fichier.print(';');
  fichier.print(timestamp.hour(), DEC);
  fichier.print(':');
  fichier.print(timestamp.minute(), DEC);
  fichier.print(':');
  // Impression du '0' quand il s'est écoulé moins de 10 secondes
  if (timestamp.second() < 10)
  {
    fichier.print('0');
  }
  fichier.print(timestamp.second(), DEC);
  fichier.print(";");
 
  // Conditions météo
  fichier.print(hum);
  fichier.print(";");
  fichier.print(temp);
  fichier.print(";");
  fichier.print(lum);
  fichier.println("");
  fichier.close();
}

- AFFICHAGE SUR LCD -

L'idée ici est de "finaliser" le projet : on cherche, par exemple, à alimenter l'Arduino et ses shields avec une batterie, et d'installer le tout dans une boîte prévue pour l'occasion, avec juste les capteurs qui dépassent pour faire une station portable. Plus besoin donc de moniteur série : une fois les capteurs calibrés, on remonte les informations directement sur l'écran LCD pour pouvoir se passer de l'ordinateur...

:arrow: Même montage, mais en plaçant le Deuligne au-dessus du shield Mémoire. Il n'y a plus qu'à remettre les câbles au même endroit !

La bibliothèque Deuligne permet de communiquer de manière simple avec l'écran LCD, avec des fonctions similaires à celles que l'on utilise avec le moniteur série (begin(), print(), etc). On remplacera donc les parties concernées, en gardant à l'esprit que l'écran LCD ne peut afficher que 2x16 caractères à la fois.
Le reste du code est identique, voilà la version complète :

- CODE -

Code: Tout sélectionner
/*
 * Tutoriel : Station météo (suite) - Datalogging toutes les 10sec + Affichage live sur LCD
 * Matériel : idem + Deuligne
 */

    /* RELEVÉ DONNÉES MÉTÉO */
   
// Inclusion de la librairie nécessaire pour la lecture du DHT11
#include <DHT.h>

//Déclaration des pins reliées aux capteurs
#define photores 1
#define DHTPIN 2

// Déclaration du type de capteur utilisé et initialisation
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

// Déclaration des variables nécessaires
// Cette fois les variables du DHT11 sont déclarées en int pour tronquer la partie décimale
// 1. pour gagner de la place sur l'affichage
// 2. parce que la précision du capteur n'est de toute façon pas suffisante !
int hum;
int temp;
int lum;

    /* DATALOGGING */

// Inclusion des librairies nécessaires à l'utilisation du shield Mémoire
// (les deux premières sont intégrées à l'IDE Arduino)
#include <SD.h>
#include <Wire.h>
#include <RTClib.h>

// Déclaration des objets liés à l'horloge
RTC_DS1307 RTC;
DateTime timestamp;
int updateTime;

    /* AFFICHAGE LCD */

// Inclusion des librairies nécessaires à l'utilisation du shield Deuligne
// Inutile d'inclure la librairie Wire.h à nouveau !
#include <Deuligne.h>

// Déclaration de l'objet LCD
Deuligne LCD;

void setup()
{
  // Ici plus de liaison série, on a fini le debug
  // On envoie les données directement sur les éléments du montage :)
 
  // Initialisation DHT11
  dht.begin();
 
  // Initialisation Deuligne
  LCD.init();
 
  // Initialisation carte SD
  pinMode(10, OUTPUT);
  if (!SD.begin(10))
  {
    LCD.print("Card failed");
    return;
  }
 
  // Initialisation RTC
  Wire.begin();
  RTC.begin();
 
  // Mise à l'heure suivant paramètres système
  RTC.adjust(DateTime(__DATE__, __TIME__));
  if (!RTC.isrunning())
  {
    LCD.print("RTC failed");
    return;
  }
 
  // Sauvegarde de l'heure de départ pour commencer l'enregistrement des données
  DateTime startTime = RTC.now();
  updateTime = startTime.second();
 
  // Mise en page du tableau CSV
  File fichier = SD.open("meteo.csv", FILE_WRITE);
  // Le ';' fait office de séparateur et permet de passer d'une case à la suivante
  // le '\n' permet de passer à la ligne suivante. Équivaut à un fichier.println("");
  fichier.print("Date;Heure;Humidite (%);Temperature (*C);Luminosite (%)\n");
  fichier.close();
}

void loop()
{
  // Relevé des valeurs en provenance du DHT11
  hum = dht.readHumidity();
  temp = dht.readTemperature();
 
  // Relevé des valeurs en provenance de la photorésistance et conversion en pourcentage
  lum = analogRead(photores);
  lum = map(lum, 0, 1023, 0, 100); // Valeurs à rajuster si besoin
 
  // Relevé de l'heure
  timestamp = RTC.now();
 
  // Affichage sur écran LCD
  // De l'heure
  LCD.print(timestamp.hour(), DEC);
  LCD.print(':');
  LCD.print(timestamp.minute(), DEC);
  LCD.print(':');
  // Impression du '0' quand il s'est écoulé moins de 10 secondes
  if (timestamp.second() < 10)
  {
    LCD.print('0');
  }
  LCD.print(timestamp.second(), DEC);
 
  // Puis des conditions météo
  LCD.print(" H= ");
  LCD.print(hum);
  LCD.setCursor(0, 1); // Placement du curseur sur la 1e colonne de la 2e ligne
  LCD.print("T= ");
  LCD.print(temp);
  LCD.print(" L= ");
  LCD.print(lum);
 
  // On regarde s'il est temps de faire un relevé sur la carte SD
  // C'est-à-dire s'il s'est écoulé plus de 10 secondes depuis le dernier relevé
  if ((timestamp.second() - 10) == updateTime)
  {
    // auquel cas on remet à jour la variable concernée
    updateTime = timestamp.second();
    printFile();
  }
  // cas particulier : lorsque le dernier relevé est à __:__:5_, le prochain doit se faire à __:__:0_
  else if ((timestamp.second() < 10) && ((timestamp.second() + 50) == updateTime))
  {
    updateTime = timestamp.second();
    printFile();
  }
 
  delay(1000);
  LCD.clear(); // Ecran vierge pour la prochaine boucle
}

void printFile()
{
  // Impression dans fichier texte sur carte SD
  File fichier = SD.open("meteo.csv", FILE_WRITE);
 
  // Date et heure
  fichier.print(timestamp.year(), DEC);
  fichier.print('/');
  fichier.print(timestamp.month(), DEC);
  fichier.print('/');
  fichier.print(timestamp.day(), DEC);
  fichier.print(';');
  fichier.print(timestamp.hour(), DEC);
  fichier.print(':');
  fichier.print(timestamp.minute(), DEC);
  fichier.print(':');
  // Impression du '0' quand il s'est écoulé moins de 10 secondes
  if (timestamp.second() < 10)
  {
    fichier.print('0');
  }
  fichier.print(timestamp.second(), DEC);
  fichier.print(";");
 
  // Conditions météo
  fichier.print(hum);
  fichier.print(";");
  fichier.print(temp);
  fichier.print(";");
  fichier.print(lum);
  fichier.println("");
  fichier.close();
}

- COMMENTAIRES -

Aujourd'hui nous avons rajouté deux "briques" à notre Arduino et deux capteurs. Et si on mettait un buzzer qui nous avertit lorsque le taux d'humidité est trop bas ? Un capteur de gaz pour vérifier la qualité de l'air ? Un shield Bluetooth pour envoyer les informations à notre smartphone ? Quelle amélioration y apporteriez-vous ? N'oubliez pas de poster dans la section "Vos projets, vos idées" :idea:

C'est tout pour cette fois ! J'espère que ce tutoriel vous aura plu, et bonne bidouille en attendant le prochain !
"If it's itchy, scratch it !" - "DIY or die"

RTFM (À lire avant de poster) - ANDb (Arduino Noob Database)
Avatar de l’utilisateur
Laetitia
 
Messages: 296
Inscription: Mar 7 Aoû 2012 15:07
Localisation: Toulouse

Retourner vers Mémoire

Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 2 invités

cron