Bonjour,
ne trouvant aucune bibliothèques pour l'utilisation de capteur DHT11 qui ne soit pas soit une machine à faire exploser la RAM ou des gros tas de while
et de delay()
et delayMicroseconds()
, j'ai décidé d'en faire une moi même, sans aucun code bloquant (donc pas de pulseIn
, pas de delay
et pas de while
- je fonctionne aux machines à état maintenant ). On trouve nombre de tutoriels sur l'utilisation d'un tel capteur sans bibliothèque, et d'articles sur le fonctionnement (listés dans un commentaire dans le fichier header)
Fichier header : dht11.h
/*
Sources et liens utiles :
- Datasheet du DHT11 : https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf
Pour la communication avec le capteur, articles intéressants :
- https://forum.arduino.cc/t/dht11-gather-data-without-library/932829
- https://www.circuitgeeks.com/arduino-dht11-and-dht22-sensor-tutorial/
- https://www.engineersgarage.com/articles-arduino-dht11-humidity-temperature-sensor-interfacing/
- Manipulation bit à bit : https://www.locoduino.org/spip.php?article70
Autres bibliothèques pour DHT11
- https://github.com/markruys/arduino-DHT
- https://github.com/adidax/dht11
- https://github.com/winlinvip/SimpleDHT
- https://github.com/amperka/dht
- https://github.com/RobTillaart/DHTNew
- https://github.com/RobTillaart/DHTlib
- https://github.com/olewolf/DHT_nonblocking
- etc...
*/
//#pragma once
#ifndef dht_h
#define dht_h
#include <Arduino.h>
class DHT11 {
private:
uint8_t _pinCapteur; // Numéro de la broche du capteur DHT11
uint32_t _derniereLecture; // Timestamp de la dernière lecture réussie
uint8_t _humidite; // Dernière valeur d'humidité lue
int8_t _temperature; // Dernière valeur de température lue
uint8_t _donnees[5]; // Buffer pour stocker les données brutes du capteur
uint8_t _indexBit; // Index du bit en cours de lecture
uint32_t _tempsDebut; // Timestamp pour les mesures de durée
enum Etats : uint8_t
{
ATTENTE,
DEMARRAGE,
REPONSE,
LECTURE_BIT,
VERIFICATION
} machineAEtatDHT; // État actuel de la machine à états
bool readSensor(); // Fonction interne pour lire le capteur
public:
/// @brief Initialise le capteur DHT11
/// @param broche Numéro de la broche Arduino à laquelle est connecté le capteur
void init(uint8_t broche);
/// @brief À appeller régulièrement pour mettre à jour la machine à état
void update() {readSensor();}
/// @brief Lit la valeur d'humidité du capteur
/// @return uint8_t Valeur d'humidité en pourcentage
unsigned char readHumidity();
/// @brief Lit la valeur de température du capteur
/// @return int8_t Valeur de température en degrés Celsius
signed char readTemperature();
};
#endif //dht_h
Fichier programme : dht11.cpp
#include "dht11.h"
bool DHT11::readSensor()
{
uint32_t tempsActuel = millis();
switch (machineAEtatDHT)
{
case ATTENTE:
if(tempsActuel - _derniereLecture >= 1000) // temps min d'échantillonnage du DHT11
{
machineAEtatDHT = DEMARRAGE;
_tempsDebut = tempsActuel;
digitalWrite(_pinCapteur, LOW);
pinMode(_pinCapteur, OUTPUT);
Serial.println(F("Démarrage!"));
}
else return false;
break;
case DEMARRAGE:
// Envoyer le signal de démarrage pendant 18ms
if (tempsActuel - _tempsDebut >= 18)
{
pinMode(_pinCapteur, INPUT_PULLUP);
machineAEtatDHT = REPONSE;
_tempsDebut = micros();
}
break;
case REPONSE:
// Attendre la réponse du capteur
if (micros() - _tempsDebut > 100)
{
machineAEtatDHT = LECTURE_BIT;
_indexBit = 0;
_tempsDebut = micros();
Serial.println(F("Réponse!"));
}
break;
case LECTURE_BIT:
// Lire les 40 bits de données
if (digitalRead(_pinCapteur) == HIGH)
{
uint32_t duree = micros() - _tempsDebut;
if (duree > 100)
{
machineAEtatDHT = ATTENTE;
return false;
}
_donnees[_indexBit / 8] <<= 1; // équivalent à <<, décalage d'un cran à gauche des bits
if (duree > 40) _donnees[_indexBit / 8] |= 1; // Si la durée est supérieure à 40 microsecondes, le bit est un '1'
_indexBit++;
if (_indexBit == 40)
{
machineAEtatDHT = VERIFICATION;
Serial.println(F("End lecture!"));
}
_tempsDebut = micros();
}
break;
case VERIFICATION:
/*
effectue un "ET" bit à bit avec 0xFF (11111111 en binaire), pour
ne garder que les 8 bits de poids faible du résultat de l'addition.
parce que l'addition des 4 octets pourrait donner un résultat sur plus de 8 bits.
la somme de contrôle n'utilise que 8 bits. donc par exemple
- si l'addition donne 260 (100000100 en binaire)
- 260 & 0xFF donne 4 (00000100 en binaire)
*/
if (_donnees[4] == ((_donnees[0] + _donnees[1] + _donnees[2] + _donnees[3]) & 0xFF))
{
_humidite = _donnees[0];
_temperature = _donnees[2];
_derniereLecture = tempsActuel;
machineAEtatDHT = ATTENTE;
return true;
}
else
{
machineAEtatDHT = ATTENTE;
return false;
}
default: break;
}
return false;
}
void DHT11::init(uint8_t broche)
{
_pinCapteur = broche;
_derniereLecture = _humidite = _temperature = 0;
delay(2000); // temps nécessaire pour que le DHT11 soit prêt à la transmission de données après le démarrage de l'Arduino.
machineAEtatDHT = ATTENTE;
}
unsigned char DHT11::readHumidity()
{
readSensor();
return _humidite;
}
signed char DHT11::readTemperature()
{
readSensor();
return _temperature;
}
Fichier d'exemple - main.cpp/main.ino
#include "dht11.h"
#define PIN_DHT 6
DHT11 dht11;
unsigned char lastHumidite = 0; // uint8_t
signed char lastTemperature = 0; // int8_t
unsigned char humidite = dht11.readHumidity(); // uint8_t
signed char temperature = dht11.readTemperature(); // int8_t
void afficherDonnees(void)
{
Serial.print("Humidité : ");
Serial.print(humidite);
Serial.print("%, Température : ");
Serial.print(temperature);
Serial.println("°C");
}
void setup(void)
{
Serial.begin(115200);
dht11.init(PIN_DHT);
Serial.println("DHT11 Test");
// Lecture des valeurs actuelles
humidite = dht11.readHumidity(); // uint8_t
temperature = dht11.readTemperature(); // int8_t
afficherDonnees();
}
void loop(void)
{
dht11.update();
humidite = dht11.readHumidity(); // uint8_t
temperature = dht11.readTemperature(); // int8_t
// verif si les valeurs ont changé
if (humidite != lastHumidite || temperature != lastTemperature) {
afficherDonnees();
lastHumidite = humidite;
lastTemperature = temperature;
}
}
Sauf que... Normalement je n'ai rien oublié, mais dans le moniteur série, je vois des print
de débug en continus, ce qui normalement n'est censé arriver que toutes les 1s (fréquence d'échantillonnage maximale du DHT11 de 1 Hz). Donc je sors beaucoup trop souvent de ATTENTE
, comme si if(tempsActuel - _derniereLecture >= 1000)
était toujours vrai ?!
Démarrage!
Réponse!
End lecture!
Démarrage!
Réponse!
End lecture!
Démarrage!
Réponse!
End lecture!
...
Pourtant, les valeurs d'humidité et de température ne change jamais et son toujours à 0... Sauf si je vire les print
de débug dans la bibliothèque (un print
, c'est long donc ça doit fausser les temps de la machine à état!), là de temps en temps j'ai l'affichage de valeur de température et d'humidité, genre ça :
DHT11 Test
Humidité : 0%, Température : 0°C <-------- dans le setup tout est à 0
Humidité : 10%, Température : 17°C <-------- alors qu'il fait 24°C ?!
Humidité : 0%, Température : 0°C <-------- et après ça repasse à 0 ?
Sans analyseur logique va falloir que je me débrouille avec des print, c'est compliqué mais pour l'instant je sèche... Auriez vous une idée sur
Donc je sors beaucoup trop souvent de
ATTENTE
, comme siif(tempsActuel - _derniereLecture >= 1000)
était toujours vrai ?!
Merci d'avance!
Cordialement
Pandaroux007