Connaître le taux d'humidité d'un milieu est particulièrement utile. Plusieurs domaines sont concernés : l’agro industrie, l’industrie du médicament, le tertiaire et bien plus encore.
En environnement domestique, le confort des êtres humains est assuré lorsque ce taux se situe entre 30% et 70%, selon la température.
Ce tuto a pour but d’utiliser le capteur DHT22, pour mesurer la température et le taux d’humidité d’un lieu, puis, afficher en direct ces grandeurs sur une interface graphique, avec une possibilité de Data Logging.
Sommaire
Matériel nécessaire:
-
-
-
-
- Arduino,
- Un capteur DHT22,
- Une résistance de 330 Ohms 1/4 W,
- Une LED pour visualiser lorsque l’utilisateur enregistre les données,
- AppDesigner et la boîte à outil Instruments Control Toolbox.
-
-
-
Présentation du DHT22:
Le DHT22 est un capteur de température et d'humidité à bas coût. Il utilise une thermistance pour mesurer la température et un capteur capacitif pour mesurer le taux d'humidité dans l'air.
L’unique sortie du capteur délivre sous forme de signaux numériques la mesure du taux d'humidité et la température, codée chacune sur 16 bits. Ces données sont transmises au microcontrôleur à l’aide d’un protocole de communication propriétaire, qui n’est pas le même que celui employé par les composants de la famille Dallas Semiconductors (les mémoires EEPROM Dallas par exemple).
Un logique 1 est représenté par un niveau logique bas de 50µs suivi d'un niveau logique haut de 70µs.
Un logique 0 est représenté par un niveau logique bas de 50µs suivi d'un niveau logique haut de 26µs.
Ce composant communique de façon asynchrone avec le microcontrôleur.
Le microcontrôleur démarre l'échange (Start), en mettant à 0 la ligne de transmission de données pendant 500µs puis relâche la ligne.
Le DHT22 répond (Resp) en en mettant cette même ligne à 0 pendant 80µs puis à 1 pendant la même durée (80µs). Puis l'envoi des données commence, avec l'humidité en premier sur deux octets, suivit de la température sur deux octets aussi. Le bit de poids fort de l'octet haut de la température représente le signe. La température est négative si ce bit est égal à 1; ou positive lorsque le bit est égal à 0.
Pour finir un octet de vérification (Check-sum) est envoyé par le capteur au microcontrôleur, puis l'envoi des données prend fin, et le capteur relâche la ligne de transmission (Release) qui se remet aussitôt à l'état logique 1.
Une transmission dure en moyenne 5ms.
Brochage:
(+) : alimentation, +Vcc, Out : sortie de données humidité et température, (-) : masse 0V.
Spécifications techniques:
-
-
-
-
- Alimentation: 3,3 ou 5 Vcc
- Consommation: 1 - 1,5 mA
- Consommation en veille : 40 – 50µA
- Interface 3 broches : Vcc, Data Out, GND
- Protocole de communication : Bus 1 ligne
- Résolution : 0.1
- Plage de mesure:
> température: -40 à 80 °C
> humidité: 0 à 100 % RH - Précision:
> température: ± 0,5 °C
> humidité: ± 2 % RH - Fréquence d'échantillonnage: 2 s
- Dimensions: 45 x 15 x 10 mm
-
-
-
Note: pour certains modèles de capteurs, il est recommandé de relier la broche de sortie des données à une résistance de Pull Up de 4,7K à 10K. Autrement, il faudra activer la résistance interne de Pull Up sur l’entrée-sortie concernée au cas où Arduino est utilisé.
Le modèle mis en œuvre dans ce tuto en possède déjà.
Le montage d’essai :
Programmation:
Côté Arduino:
Le programme Arduino n'a rien de particulier. Il a été calqué sur l'exemple proposé par le site Adafruit. Sa mise en œuvre toute simple consiste à envoyer sur la liaison série le taux d’humidité et la température.
//DHT22 sensor test program
#include <DHT.h>
//
#define DHTPIN 4 //Digital pin connected to the sensor
#define ledPin 5 //LED is connected here
//
#define DHTTYPE DHT22 //DHT 22(AM2302)
DHT dht(DHTPIN, DHTTYPE);
//
char ledValue;
//
long dhtSampleTime = 1000; //recommended time
long blinkLedTime = 200; //
unsigned long previousDhtTime, previousLedTime;
unsigned long currentTime;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
//initialize device
dht.begin();
//
pinMode(ledPin, OUTPUT);
previousDhtTime = 0;
previousLedTime = 0;
}
void loop() {
// put your main code here, to run repeatedly:
// Read serial input
if (Serial.available() > 0)
{
ledValue = Serial.read();
}
//
//
if (ledValue == 'T') // from serial
{
currentTime = millis();
if(currentTime - previousLedTime >= blinkLedTime)
{
previousLedTime = currentTime;
{
digitalWrite(ledPin, !digitalRead(ledPin)); //blink
}
}
}
if (ledValue == 'F') // from serial
{
digitalWrite(ledPin, LOW);
}
//
// Read sensor and write data to serial port
currentTime = millis();
if(currentTime - previousDhtTime > dhtSampleTime)
{
previousDhtTime = currentTime;
float humidity = dht.readHumidity(); //read sensor humidity
float temperature = dht.readTemperature(); //read temperature as degre Celsius
//Check if any reads failed exit and try again
if (isnan(humidity) || isnan(temperature)){
Serial.println("Failed to read from DHT sensor!");
return;
}
//Send to serial
Serial.print(humidity);
Serial.print(F(" and "));
Serial.println(temperature);
}
}
La librairie dht.h est chargée en premier. Dans cette librairie se trouve toutes les fonctions prédéfinies pour gérer le capteur. Ensuite les variables sont déclarées.
La fonction Setup() met en service la liaison série, ainsi que l’objet dht du capteur.
Dans la boucle principale du programme main() on commence par vérifier si des données en provenance de l’ordinateur sont présentes sur la liaison série; si le caractère ‘T’ est reçu, la LED sur la sortie Arduino clignote; ou si c’est le caractère ‘F’, la LED s’éteint.
Le test qui suit, vérifie des données envoyées par le capteur sont erronées, dans ce cas, un message d’erreur est affiché et une nouvelle lecture est relancée.
Les données valides sont envoyées, sous forme d’une chaine de caractère sur la liaison série. Avec en premier le taux d'humidité, suivi d'un " and " (attention aux espaces) et de la température.
Côté Matlab:
L'interface graphique utilisateur construite à l'aide de AppDesigner, ressemblera à ceci:
Les variables partagées:
Toutes les variables partagées par les fonctions de ce programme se trouvent ici :
properties (Access = private)
s % Serial
serialStatus %
sensorTemperature % sensor temperature read value
sensorHumidity % sensor humidity read value
t_now % Computer time data now
temperatureData = [] % data for plotting
humidityData = [] %
t_live = [] % time array for plotting
Logging = false %
end
s : pour créer la liaison série ;
serialStatus : variable interne pour connaître l’état de la liaison série ;
sensorTemperature : cette variable mémorise la température instantanée envoyée par le capteur sur la liaison série.
sensorHumidity : cette variable mémorise l’humidité relative instantanée envoyée par le capteur sur la liaison série.
t_now : chaque lecture est horodatée. La date est mémorisée dans cette variable.
temperatueData : mémorise sous forme d’un tableau, toutes les températures lues sur la liaison série, pour être utilisé par le graphique.
humidityData : mémorise sous forme d’un tableau, tous les taux d’humidité relative lus sur la liaison série, pour être utilisé par le graphique.
t_live : mémorise sous forme d’un tableau, l’instant de lecture de chaque donnée lue sur la liaison série.
Logging : est une variable interne, qui permet d’activer ou de désactiver le data logging.
Les Helper Function:
La fonction buttonsState() :
Cette fonction définit l’état activé ou désactivé des boutons ou commutateurs pendant les différente phases d’utilisation de l’interface graphique. Cette helper function est appelée selon les cas par les Callbacks de chacun des boutons.
function buttonsState(app, state)
switch state
case "Connected"
app.Lamp.Color = 'green';
app.DisconnectButton.Enable = "on";
app.Switch.Enable = "on";
app.ConnectButton.Enable = "off";
app.PORTDropDown.Enable = "off";
app.BaudDropDown.Enable ="off";
app.StartButton.Enable = "off";
app.StopButton.Enable = "off";
case "Disconnected"
app.Lamp.Color = [.60,0.68,0.60];
app.serialStatus = false;
app.ConnectButton.Enable = "on";
app.PORTDropDown.Enable = "on";
app.BaudDropDown.Enable ="on";
app.DisconnectButton.Enable = "off";
case "Startup"
app.Switch.Enable = "off";
app.DisconnectButton.Enable = "off";
app.StartButton.Enable = "off";
app.StopButton.Enable = "off";
case "Logtofile"
app.Switch.Enable = "off";
app.StartButton.Enable ="off";
app.StopButton.Enable = "on";
case "Waitforlogging"
app.StopButton.Enable ="off";
app.StartButton.Enable = "on";
app.Switch.Enable = "on";
end
end
La fonction acquireData() :
function acquireData(app)
app.t_now = datetime("now","TimeZone","Europe/Paris"); % get curren time
value = readline(app.s); % get data from serial
numericValue = str2double(regexp(value,' and ','split')); % result is array of 2 elements
app.sensorHumidity = numericValue(1,1); % the first element is humdity
app.sensorTemperature = numericValue(1,2); % the second one is temperature
app.humidityData = [app.humidityData, app.sensorHumidity]; % store data in an array
app.temperatureData = [app.temperatureData, app.sensorTemperature];
app.t_live = [app.t_live, app.t_now];
end
Cette fonction effectue l’acquisition de l’humidité, de la température et de l’heure, puis stocke toutes ces valeurs dans les trois tableaux humidityData, temperatureData et t_live.
Les données envoyée sur la liaison série sont des chaînes de caractères au format :
« Humidite and Temperature ».
La fonction prédéfinie regexp() se charge de transformer cette chaine de caractère en un tableau ayant pour éléments de deux chaines de caractères « Humidite » et « Temperature ». Ces données sous transformées en format numérique grâce à la fonction prédéfinie str2double().
La fonction plot_data() :
function plot_data(app)
% define first x lower and upper limits for plotting area
x_lower = app.UIAxes.XLim(1);
x_upper = app.UIAxes.XLim(2);
% so we want to plot few value then update x axes values
if (app.t_now > x_upper)
refresh_t = seconds(10); % update time values every 10 sec
app.UIAxes.XLim = [x_lower + refresh_t, app.t_now + refresh_t];
% also define x ticks, we take five value for this
app.UIAxes.XTick = linspace(x_lower + refresh_t, app.t_now + refresh_t, 5);
end
plot(app.UIAxes, app.t_live, app.humidityData, 'b', app.t_live, app.temperatureData, 'r','LineWidth',1.5);
legend(app.UIAxes, 'Hr(%)', 'T(°C)');
end
Cette fonction se charge d’assurer la représentation graphique de la température(en couleur rouge) et du taux d’humidité (en couleur bleue) en fonction du temps dont l’unité est au format "HH :mm :ss" .
L’axe des temps est constitué de cinq valeurs, et rafraichi toutes les 10 secondes.
La fonction display_live_data() :
function display_live_data(app)
app.HmaxEditField.Value = max (app.humidityData);
app.TmaxCEditField.Value = max (app.temperatureData);
app.HEditField.Value = app.sensorHumidity;
app.TCEditField.Value = app.sensorTemperature;
end
Cette fonction envoie dans les zones d’éditions numérique les contenus des variables sensorHumidity, sensorTemperature, le taux d’humidité relative, la température, ainsi les valeurs maximales enregistrées de ces deux grandeurs.
La fonction processDataReceived() :
function dataToRow = processDataReceived(~, hum, temp, eventtime)
dataToRow = {eventtime};
hum = {hum};
temp = {temp};
dataToRow = {dataToRow{1}, hum{1}, temp{1}}; % then formatting this in a single row
end
Cette fonction met sous la forme {{instant_de_la_lecture}, {humidité}, {température}} ; les données humidité et température horodatées lues sur la liaison série.
La fonction logDataTofile()
function logDataToFile(app)
filename = 'DHTsensor_data.csv';
filepath = 'pwd';
logFile = fullfile(filepath, filename);
persistent rowIndex;
if isempty(rowIndex)
rowIndex = 1;
else
rowIndex = rowIndex + 1;
end
logData = processDataReceived(app, app.sensorHumidity, app.sensorTemperature, datetime);
writecell(logData, logFile,'WriteMode','append');
end
Enregistre les mesures capturées toutes les secondes au format csv, dans le répertoire de travail Matlab. Un autre répertoire peut être choisi il suffit d’indiquer son chemin complet.
Les données sont enregistrées lignes par lignes dans le fichier, y compris pour un nouvel enregistrement.
La Startup function:
Cette fonction crée les paramètres de configuration de la liaison série, définit les limites du graphe, ainsi que le format d’affichage du temps en HH :mm :ss, la grille et le style de graphe encadré.
function startupFcn(app)
app.PORTDropDown.Items = ["Com Port...",serialportlist('available')];
buttonsState(app,"Startup");
% Plot invisible point to initiate datetime ruler
plot(app.UIAxes, datetime("now","TimeZone",'Europe/Paris'), 50);
% Set x limits and x ticks format
this_time = datetime("now","TimeZone",'Europe/Paris','Format','HH:mm:ss');
x_lower = this_time(1) - seconds(5);
x_upper = this_time(1);
app.UIAxes.XLim = [x_lower, x_upper];
app.UIAxes.XAxis.TickLabelFormat = 'HH:mm:ss';
app.UIAxes.XTick = linspace(x_lower, x_upper, 5);
app.UIAxes.YLim = [0, 100];
app.UIAxes.Box = 'on';
grid(app.UIAxes,"on");
end
Les Callbacks:
Le Callback du bouton Connect :
function ConnectButtonPushed(app, event)
app.PORTDropDown.Items = ["Com Port...",serialportlist('available')];
app.s = serialport(app.PORTDropDown.Value,str2double(app.BaudDropDown.Value));
configureTerminator(app.s,"CR/LF");
buttonsState(app,"Connected");
app.serialStatus = true;
end
Active la liaison série, puis désactive certains boutons de l’interfaces graphique en appelant la fonction buttonsState(). La variable serialStatus est positionnée à true pour indiquer que la liaison série est active.
Le Callback du commutateur d’acquisition « Switch »:
function SwitchValueChanged(app, event)
value = app.Switch.Value;
if app.serialStatus
app.DisconnectButton.Enable = "off";
app.StartButton.Enable ="on";
while(strcmp(value,'On'))
acquireData(app);
pause(0.1);
plot_data(app);
display_live_data(app);
if app.Logging
logDataToFile(app);
end
value = app.Switch.Value;
end
app.DisconnectButton.Enable = "on";
app.StartButton.Enable ="off";
app.StopButton.Enable = "off";
end
end
Ce Callback permet de démarrer la acquisition des données sur la liaison série. Lors d’un changement de position du commutateur de la position Off à la position On. Le bouton Disconnect devient inactif ; le bouton "Start" qui actionne le Data Logging devient actif.
Puis on rentre dans une boucle et on y reste tant que ce bouton occupe la position « On ». A l’intérieur de la boucle la fonction d’acquisition acquireData() est appelée, ainsi les fonctions plot_data() et display_live_data(). Si la variable interne Logging est active, la fonction logDataToFile() est appelée.
L’état du Switch est mémorisé dans la variable value à chaque tour de boucle. Lorsque cette variable prend la valeur « Off », on sort de la boucle, puis le bouton Disconnect redevient actif, les deux boutons Start et Stop du panneau Data Logging deviennent inactifs.
Le Callback du bouton Start :
function StartButtonPushed(app, event)
app.Logging = true;
write(app.s,'T',"char");
buttonsState(app,'Logtofile');
end
Il permet d’activer la variable interne Logging, puis d’envoyer sur la liaison série le caractère ‘T’ qui permet de faire clignoter la LED sur la sortie Arduino afin d’indiquer le début de l’enregistrement.
Puis la fonction buttonsState() est appelée avec le paramètre Logtofile. Certains boutons deviennent inactifs.
Le Callback du bouton Stop:
function StopButtonPushed(app, event)
app.Logging = false;
write(app.s,'F',"char");
buttonsState(app,'Waitforlogging');
end
Il désactive la variable Logging, ce qui a pour effet d’arrêter l’enregistrement des données, envoie le caractère ‘F’ sur la liaison série pour éteindre la diode connectée sur la sortie Arduino, puis appelle la fonction buttonsState() avec le paramètre Waitforlogging. Le bouton Stop devient inactif, le commutateur « Switch » devient actif, ainsi que le bouton Start.
Le Callback du bouton Disconnect:
function DisconnectButtonPushed(app, event)
buttonsState(app, 'Disconnected');
delete(app.s);
end
Ce Callback appelle la fonction buttonsState() avec le paramètre Disconnected, certains boutons, ainsi que le bouton Disconnect deviennent inactifs. Le bouton Connect devient actif.
Puis l’objet liaison série « s » est désactivé et effacé.
Test fonctionnel:
La vidéo ci-après résume en image cet article, et présente l'affichage des données en Live sur l'interface graphique:
Conclusion:
Cette interface graphique peut encore être améliorée. On peut proposer par exemple le choix du répertoire à l'utilisateur pour enregistrer le fichier log; ou bien arranger l'affichage du graphe.
Le capteur DHT22 est lent et basic. Mais il constitue un véritable compromis pour un Hobbyiste qui veut réaliser thermomètre – hygromètre avec un Data Logger. Ce type de capteur trouve aussi sa place dans des VMC à commande électronique à bas coût.
JtBB
ressources:
https://learn.adafruit.com/dht/using-a-dhtxx-sensor-with-arduino
https://www.mathworks.com/matlabcentral/fileexchange/72441-dht22-add-on-library-for-arduino
Tuto : configurer une liaison série avec arduino, allumer une led