Mise à jour (31 octobre 2016): voici une version plus récente dans laquelle j'utilise un "data logging shield" plutôt que des composants individuels.
Voici un projet classique qui montre de façon éloquente l'efficacité de l'Arduino pour la conception de systèmes de mesures scientifiques: un "data logger".
Dans ce projet, l'Arduino consigne à toutes les minutes, sur une carte SD, les valeurs de température et de luminosité mesurées par des capteurs appropriés.
En plus d'un Arduino Uno, j'ai donc utilisé un lecteur de cartes SD muni d'un adapteur lui permettant de recevoir les signaux de 5 V, un capteur de température numérique DS18B20, une photorésistance et une horloge temps réel (RTC).
Tous ces périphériques étaient déjà prêts à l'emploi, puisqu'ils ont déjà été utilisés dans des articles précédents (que vous pouvez consulter en cliquant les liens du paragraphe précédent).

Les branchements des différents périphériques à l'Arduino sont les suivants:
Le lecteur de cartes SD occupe les pins 10, 11, 12, 13 de l'Arduino (SPI). Mais prenez garde d'abaisser à 3,3 V les signaux qui doivent l'être (plus d'informations à ce sujet ici).
L'horloge RTC est branchées aux pins A4 et A5 (i2c) de l'Arduino (plus d'infos ici).
Le thermomètre DS18B20 est branché à la pin 7 de l'Arduino (plus d'infos ici).
La sonde à base de photorésistance est branchées à la pin A0 de l'Arduino.
Les données sont enregistrées sur la carte SD sous la forme d'un fichier CSV: "comma-separated value". Il s'agit d'un fichier texte destiné à être ouvert dans un tableur comme Excel. Dans mon sketch, j'ai choisi de respecter la convention adoptée par la version française d'Excel: les valeurs d'une même ligne sont séparées par des points virgules (plutôt que par des virgules). De plus, je remplace le point décimal de la température par une virgule.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************************ | |
Saisie de données (data logging) avec un Arduino | |
Matériel: Arduino Uno | |
Lecteur de carte SD (10-11-12-13) avec adapteur 5/3,3 V | |
Horloge temps réel (RTC) (A-4 et A-5) | |
Thermomètre numérique DS18B20 (digital 8) | |
Phorésistance en diviseur de tension (A-0) | |
http://electroniqueamateur.blogspot.com/2013/06/saisie-de-donnees-data-logging-avec-un.html | |
*************************************************************/ | |
// Les librairies | |
#include <OneWire.h> // pour le ds18b20 | |
#include <SD.h> // pour le lecteur de carte SD | |
#include <Wire.h> | |
#include <RTClib.h> // pour l'horloge temps réel | |
// Nombre de secondes entres chaque prise de mesure | |
#define DELAI_MESURES 60 | |
RTC_DS1307 RTC; // objet Real Time Clock | |
DateTime now; | |
long tempsInitial = 0; // nombre de secondes entre le 1 jan 2000 et le début du script | |
long derniereMesure = 0; // moment de la plus récente prise de mesure | |
const int chipSelect = 10; // chipSelect de la carte SD àla pin 10 | |
File logfile; //fichier | |
OneWire ds(8); // fil data du thermomètre branché sur digital 8 | |
byte addresseThermo[8]; // adresse du thermomètre | |
int photoResPin = A0; // photoresistance branchée à analog 0 | |
void error(char *str) | |
{ | |
Serial.print("Erreur: "); | |
Serial.println(str); | |
while(1); | |
} | |
void setup(void) | |
{ | |
// initialisation du moniteur série, s'il y a lieu | |
Serial.begin(9600); | |
Serial.println(); | |
// initialisation de la carte SD | |
pinMode(10, OUTPUT); | |
// see if the card is present and can be initialized: | |
if (!SD.begin(chipSelect)) { | |
error("echec de l'initialisation de la carte SD"); | |
} | |
Serial.println("Initialisation de la carte SD reussie."); | |
// Création d'un fichier | |
char filename[] = "RAPPOR00.CSV"; | |
for (uint8_t i = 0; i < 100; i++) { | |
filename[6] = i/10 + '0'; | |
filename[7] = i%10 + '0'; | |
if (! SD.exists(filename)) { | |
logfile = SD.open(filename, FILE_WRITE); | |
break; | |
} | |
} | |
if (! logfile) { | |
error("echec de la creation du fichier"); | |
} | |
Serial.print("Nom du fichier: "); | |
Serial.println(filename); | |
// initialisation de l'horloge temps réel (RTC) | |
Wire.begin(); | |
RTC.begin(); | |
now = RTC.now(); | |
tempsInitial = now.unixtime(); | |
derniereMesure = now.unixtime()-DELAI_MESURES; | |
// initialisation du thermometre ds18b20: | |
if ( !ds.search(addresseThermo)) { | |
logfile.println("Erreur addr thermometre"); | |
Serial.println("Erreur addr thermometre"); | |
ds.reset_search(); | |
return; | |
} | |
if ( OneWire::crc8( addresseThermo, 7) != addresseThermo[7]) { | |
logfile.println("Erreur CRC (thermometre)"); | |
Serial.println("Erreur CRC (thermometre)"); | |
return; | |
} | |
logfile.println("secondes;date;heure;lumiere;temperature"); | |
Serial.println("secondes;date;heure;lumiere;temperature"); | |
} | |
// Routine de lecture de température | |
float getTemp() { | |
byte i; | |
byte present = 0; | |
byte data[12]; | |
int HighByte, LowByte, TReading, Tc_100,SignBit; | |
float temperature; | |
ds.reset(); | |
ds.select(addresseThermo); | |
ds.write(0x44,1); | |
present = ds.reset(); | |
ds.select(addresseThermo); | |
ds.write(0xBE); | |
for ( i = 0; i < 9; i++) { | |
data[i] = ds.read(); | |
} | |
LowByte = data[0]; | |
HighByte = data[1]; | |
TReading = (HighByte << 8) + LowByte; | |
SignBit = TReading & 0x8000; | |
if (SignBit) { | |
TReading = -TReading; | |
} | |
Tc_100 = (6 * TReading) + TReading / 4; // conversion en celcius? vérifier la fiche technique! | |
temperature = float(Tc_100) / 100; | |
return temperature; | |
} | |
void loop(void) | |
{ | |
// on mesure les données pertinentes | |
now = RTC.now(); // quelle heure est-il? | |
if ((now.unixtime()-derniereMesure)< DELAI_MESURES) return; | |
derniereMesure = now.unixtime(); | |
analogRead(photoResPin); // luminosité | |
delay(10); | |
int luminosite = analogRead(photoResPin); | |
float temperature = getTemp(); //température | |
// Écriture du fichier | |
logfile.print(now.unixtime()-tempsInitial); // nombre de secondes depuis le début des mesures | |
logfile.print("; "); | |
if (now.day() < 10) logfile.print("0"); // date | |
logfile.print(now.day(), DEC); | |
logfile.print("-"); | |
if (now.month() < 10) logfile.print("0"); | |
logfile.print(now.month(), DEC); | |
logfile.print("-"); | |
logfile.print(now.year(), DEC); | |
logfile.print("; "); | |
if (now.hour() < 10) logfile.print("0"); // heure | |
logfile.print(now.hour(), DEC); | |
logfile.print(":"); | |
if (now.minute() < 10) logfile.print("0"); | |
logfile.print(now.minute(), DEC); | |
logfile.print(":"); | |
if (now.second() < 10) logfile.print("0"); | |
logfile.print(now.second(), DEC); | |
logfile.print("; "); | |
logfile.print(luminosite); // luminosite | |
logfile.print("; "); | |
logfile.print(short(temperature)); | |
logfile.print(","); | |
short decimales = (short)(temperature*100)%100; // température (en remplaçant le point décimal | |
if (decimales < 10) logfile.print("0"); // par une virgule) | |
logfile.print(decimales); | |
logfile.println(); | |
// Écriture du moniteur série (utile pour le débogage, pas tellement pendant | |
// l'utilisation réelle. | |
Serial.print(now.unixtime()-tempsInitial); // nombre de secondes depuis le début du sketch | |
Serial.print("; "); | |
if (now.day() < 10) Serial.print("0"); | |
Serial.print(now.day(), DEC); | |
Serial.print("-"); | |
if (now.month() < 10) Serial.print("0"); | |
Serial.print(now.month(), DEC); | |
Serial.print("-"); | |
Serial.print(now.year(), DEC); | |
Serial.print("; "); | |
if (now.hour() < 10) Serial.print("0"); | |
Serial.print(now.hour(), DEC); | |
Serial.print(":"); | |
if (now.minute() < 10) Serial.print("0"); | |
Serial.print(now.minute(), DEC); | |
Serial.print(":"); | |
if (now.second() < 10) Serial.print("0"); | |
Serial.print(now.second(), DEC); | |
Serial.print("; "); | |
Serial.print(luminosite); | |
Serial.print("; "); | |
Serial.print(short(temperature)); | |
Serial.print(","); | |
if (decimales < 10) Serial.print("0"); | |
Serial.print(decimales); | |
Serial.println(); | |
logfile.flush(); | |
} | |

Tel que prévu, les fichier CSV enregistré sur la carte SD s'ouvre facilement dans Excel, et on peut alors effectuer des calculs sur les données, les mettre en graphique, etc.

Il serait utile d'ajouter un dispositif permettant de s'assurer que tout fonctionne correctement pendant que l'Arduino n'est pas branché à un ordinateur. Car ça doit être un peu frustrant de mettre en place le système pour une série de mesures d'une durée de plusieurs jours, pour ensuite se rendre compte que la carte SD a refusé de s'initialiser au départ. Ça pourrait être une simple LED qui s'allume en cas d'erreur, ou un afficheur LCD indiquant la dernière valeur mesurée, etc.
Notez qu'Adafruit fabrique un "Data Logging Shield" spécialement conçu pour ce genre d'exercice: puisque le shield contient déjà un lecteur de carte SD et une horloge RTC, il ne reste plus qu'à brancher les capteurs désirés.
Yves Pelletier (Twitter: @ElectroAmateur)
Bonjour,
RépondreSupprimerMerci pour cet article fort intéressant.
Serait-il possible de générer un fichier par jour, fichier qui porterait le nom du jour ?
J'ai un projet similaire mais pour le moment je ne sais que copier ce que font les autres et quand ça veut bien fonctionner !
'class DateTime' has no member named 'get'
RépondreSupprimerquand j'essayes sur arduino 1.6.5 ?
a la ligne Serial.print(now.get()-tempsInitial); // nombre de secondes depuis le début du sketch
il faut remplacer now.get() par now.unixtime()
Supprimerdans l’entièreté du croquis
copier un croquis datant de 2013 avec un IDE et une biblio RTC maj, ok je l'essaye en 2021 avec 1.8.4 et une archive rtclib v1.2, pblme identique
Guillaumetell a le probleme en 2016, à peine 3 ans apres le code original
un débutant arduino risque d'etre découragé...
Merci quand meme à Mr Pelletier
Ça avait été programmé avec la RTClib de jeelabs et non avec le fork d'Adafruit. Je vais corriger ça.
SupprimerBonjour Monsieur, çà fonctionne tres bien, ce qui est génial c'est qu'on peut choisir l'intervalle de mesures que l'on désire dans le croquis avant de le televerser, je suis parti de votre travail :
Supprimerj'ai supprimé la photoresistance, je mesure 2 temperatures ds18b20, j'utilise dallasTemperature et les adresses DS18 en dur.
j'ai supprimé l'enregistrement des secondes, inutiles avec l'intervalle que j'utilise, je n'utilise pas la fonction pour changer le point décimal en virgule, çà se fait lors de l'importation du csv renommé txt dans excel pour le traçage du graphique, en lecture nombres temperatures le point n'est pas un problème
Merci et meilleures salutations