dimanche 3 mars 2019

ESP8266 et carte SD

Dans cet article, je vous propose la mise au point d'un "data logger" à base d'ESP8266 qui répétera une mesure à une fréquence choisie par l'utilisateur et enregistrera les informations à l'intérieur  d'un fichier sur une carte SD. De plus, il sera possible de consulter les 10 mesures les plus récentes dans une page web.

Connexion et test du lecteur de carte SD

Mon lecteur de carte SD est un module qui communique au moyen du protocole SPI à un niveau logique de 3,3 V qui convient parfaitement à l'ESP8266.

En ce qui concerne l'ESP8266, j'ai utilisé une carte Wemos D1, mais bien entendu n'importe quel ESP8266 comportant un nombre suffisant de broches GPIO fera l'affaire.


Le module lecteur de cartes SD est connecté à l'ESP8266 de la façon suivante:

      Carte SD    ---    ESP8266
GǸD      ---     GND
 +3,3     ---     3,3V
+5       ---     ----
      CS        ---    GPIO 15
    MOSI      ---    GPIO 13
      SCK      ---    GPIO 14
      MISO    ---    GPIO 12


Bonne nouvelle: la bibliothèque "SD" fournie avec l'IDE Arduino est parfaitement compatible avec l'ESP8266, ce qui simplifie évidemment les choses.

Pour vérifier le fonctionnement correct de la carte SD, c'est toujours une bonne idée de faire l'essai de l'exemple "CardInfo". Il faudra toutefois utiliser "15" comme valeur de la constante "chipSelect".




Sketch

Voici le sketch qui prend une mesure à chaque minute et consigne le résultat à l'intérieur d'un fichier intitulé "Mesures.txt" sur la carte SD.  Pour faire mes tests, j'ai simplement utilisé un potentiomètre branché à l'ADC de l'ESP8266. La date et l'heure de chaque mesure est également enregistrée, après interrogation d'un serveur NTP (il n'est donc pas nécessaire de brancher une horloge temps réel (RTC) à l'ESP8266.

Afin de profiter au maximum des possibilités de l'ESP8266, j'ai également programmé un serveur web qui présente les 10 mesures les plus récentes ayant été enregistrées sur la carte SD.

Lors du démarrage, le moniteur série indique la réussite (ou l'échec) de la connexion au réseau WiFi, de la mise en place du serveur web, de la connexion au serveur NTP et de l'initialisation de la carte SD. L'enregistrement de chaque mesure dans la carte SD est également signalée.


Au moyen d'un fureteur, on accède à l'adresse IP indiquée dans le moniteur série, ce qui nous permet de consulter les 10 dernières mesures ayant été consignées sur la carte SD.



/**************************************************************
Data Logger ESP8266
Les mesures d'un capteur sont enregistrées à intervalle
régulier sur une carte SD.
On peut consulter, par l'entremise d'une page web, les
10 plus récentes valeurs enregistrées.
Plus d'infos:
https://electroniqueamateur.blogspot.com/2019/03/esp8266-et-carte-sd.html
*****************************************************************/
// bibliothèques pour le lecteur de carte SD:
#include <SPI.h>
#include <SD.h>
// bibliothèques pour la communication WiFi
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
// bibliothèque pour l'affichage de la date et de l'heure
#include <time.h>
// adresse et mot de passe du réseau wifi
const char* ssid = "********";
const char* password = "********";
// constantes
const int delaiEnMinutes = 1; // combien de minutes entre deux mesures consécutives?
const int stockage_max = 10; //nombre maximal de données stockées en mémoire, pour affichage dans la page web
const int decalage = -5; // la valeur dépend de votre fuseau horaire. Essayez 2 pour la France.
// variables globales
unsigned long derniereMesure; // derniere fois qu'une mesure a été prise
int mesures[stockage_max]; // tableau contenant les plus récentes mesures
time_t date_et_heure[stockage_max]; // tableau contenant le moment des plus récents scans
int nb_de_donnees = 0; // nombre de données déjà stockées dans mesures et dateHeure
File monFichier; // fichier sur la carte SD
ESP8266WebServer serveur(80); // serveur web
// Construction de la page web
void handle_root() {
struct tm * timeinfo;
String contenu;
for (int i = 0; i < stockage_max; i++) {
if (date_et_heure[i] != 0)
{
timeinfo = localtime(&date_et_heure[i]);
contenu.concat( "<p> Date et heure: " + String(timeinfo->tm_mday) + "-" + String(timeinfo->tm_mon + 1) + "-" + String(timeinfo->tm_year + 1900) + " " + String(timeinfo->tm_hour) + ":" + String(timeinfo->tm_min) + ":" + String(timeinfo->tm_sec) + " Mesure: " + String(mesures[i]) + "</p>");
}
}
serveur.send(200, "html", "<head> <title>Data logger ESP8266</title> <meta http-equiv=Refresh content=30></head> "
"<body><H1>" + String(stockage_max) + " plus r&eacute;centes mesures enregistr&eacute;es</H1>"
"<p>" + contenu + "<p>"
"<p>Visitez <a href=http://electroniqueamateur.blogspot.com/>&Eacute;lectronique en Amateur</a>!</p></body>");
delay(100);
}
// Initialisation du WiFi et de la carte SD. Les progrès s'affichent dans le moniteur série
// pour faciliter le débogage, et pour connaître l'adresse IP de l'ESP8266.
void setup()
{
SPI.begin();
Serial.begin(9600);
Serial.println();
WiFi.begin(ssid, password);
Serial.print("Connexion au reseau WiFi");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.println();
Serial.print("Nom du reseau WiFi: ");
Serial.println(ssid);
Serial.print("Adresse IP de la page web: ");
Serial.println(WiFi.localIP());
serveur.on("/", handle_root);
serveur.begin();
Serial.println("Le serveur web est en fonction.");
configTime(decalage * 3600, 0, "ca.pool.ntp.org"); //serveurs NTP canadiens
// en Europe, essayez europe.pool.ntp.org ou fr.pool.ntp.org
Serial.print("Attente date et heure");
while (time(nullptr) <= 100000) {
Serial.print(".");
delay(1000);
}
Serial.println();
Serial.println("Pret.");
Serial.print("Initialisation de la carte SD...");
if (!SD.begin(15)) { // CS du lecteur de carte branché à GPIO15
Serial.println("echec!");
while (1);
}
Serial.println("reussie");
}
void loop()
{
int nouvelleMesure;
time_t heureMesure;
struct tm * timeinfo;
if ((millis() - derniereMesure) >= delaiEnMinutes * 60000) // c'est le moment de prendre une nouvelle mesure
{
nouvelleMesure = analogRead(A0); // mesure de l'entrée analogique A0
time(&heureMesure); // quelle heure est-il?
timeinfo = localtime(&heureMesure);
// enregistrement de la mesure sur la carte SD
// ouverture (ou création) du fichier "Archives.txt")
monFichier = SD.open("Mesures.txt", FILE_WRITE);
// si l'ouverture a réussi, on écrit à l'intérieur
if (monFichier) {
Serial.print("Ecriture dans le fichier Mesures.txt ... "); // dans le moniteur série
monFichier.print("Date et heure: "); // dans le fichier
monFichier.print(String(timeinfo->tm_mday));
monFichier.print("-");
monFichier.print(String(timeinfo->tm_mon + 1));
monFichier.print("-");
monFichier.print(String(timeinfo->tm_year + 1900));
monFichier.print(" ");
monFichier.print(String(timeinfo->tm_hour));
monFichier.print(":");
monFichier.print(String(timeinfo->tm_min));
monFichier.print(":");
monFichier.print(String(timeinfo->tm_sec));
monFichier.print(" Mesure:");
monFichier.println(nouvelleMesure);
// on referme le fichier
monFichier.close();
Serial.println("reussie.");
} else {
// si l'ouverture du fichier a échoué:
Serial.println("Erreur d'ouverture du fichier Mesures.txt");
}
// Stockage des 10 mesures les plus récentes pour affichage dans la page web
if (nb_de_donnees < stockage_max) { // il y a encore des lignes vides pour l'affichage web
mesures[nb_de_donnees] = nouvelleMesure;
date_et_heure[nb_de_donnees] = heureMesure; // quelle heure est-il?
nb_de_donnees++;
}
else // la page web est pleine
{
for (int i = 0; i < stockage_max - 1; i++) { // on décale toutes les infos d'une ligne
mesures[i] = mesures[i + 1];
date_et_heure[i] = date_et_heure[i + 1];
}
mesures[stockage_max - 1] = nouvelleMesure; // on enregistre la nouvelle info
date_et_heure[stockage_max - 1] = heureMesure; // quelle heure est-il?
}
derniereMesure = millis();
}
serveur.handleClient();
}


À lire également: 


Yves Pelletier   (TwitterFacebook)

Aucun commentaire:

Enregistrer un commentaire